@aws/nx-plugin 0.45.0 → 0.46.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/package.json +1 -1
  2. package/src/infra/app/__snapshots__/generator.spec.ts.snap +20 -20
  3. package/src/py/fast-api/__snapshots__/generator.spec.ts.snap +3669 -0
  4. package/src/py/fast-api/generator.js +57 -50
  5. package/src/py/fast-api/generator.js.map +1 -1
  6. package/src/py/fast-api/schema.d.ts +1 -0
  7. package/src/py/fast-api/schema.json +8 -0
  8. package/src/py/mcp-server/__snapshots__/generator.spec.ts.snap +593 -3
  9. package/src/py/mcp-server/generator.js +4 -18
  10. package/src/py/mcp-server/generator.js.map +1 -1
  11. package/src/py/mcp-server/schema.d.ts +1 -0
  12. package/src/py/mcp-server/schema.json +8 -0
  13. package/src/py/strands-agent/__snapshots__/generator.spec.ts.snap +596 -6
  14. package/src/py/strands-agent/generator.js +4 -18
  15. package/src/py/strands-agent/generator.js.map +1 -1
  16. package/src/py/strands-agent/schema.d.ts +1 -0
  17. package/src/py/strands-agent/schema.json +8 -0
  18. package/src/terraform/project/generator.js +23 -7
  19. package/src/terraform/project/generator.js.map +1 -1
  20. package/src/trpc/backend/__snapshots__/generator.spec.ts.snap +3669 -0
  21. package/src/trpc/backend/generator.js +6 -17
  22. package/src/trpc/backend/generator.js.map +1 -1
  23. package/src/trpc/backend/schema.d.ts +1 -0
  24. package/src/trpc/backend/schema.json +8 -0
  25. package/src/ts/mcp-server/__snapshots__/generator.spec.ts.snap +594 -4
  26. package/src/ts/mcp-server/generator.js +4 -18
  27. package/src/ts/mcp-server/generator.js.map +1 -1
  28. package/src/ts/mcp-server/schema.d.ts +1 -0
  29. package/src/ts/mcp-server/schema.json +8 -0
  30. package/src/ts/nx-plugin/generator.js +1 -0
  31. package/src/ts/nx-plugin/generator.js.map +1 -1
  32. package/src/ts/react-website/app/__snapshots__/generator.spec.ts.snap +36 -36
  33. package/src/utils/agent-core-constructs/agent-core-constructs.d.ts +11 -5
  34. package/src/utils/agent-core-constructs/agent-core-constructs.js +51 -10
  35. package/src/utils/agent-core-constructs/agent-core-constructs.js.map +1 -1
  36. package/src/utils/agent-core-constructs/files/terraform/app/agent-core/__nameKebabCase__/__nameKebabCase__.tf.template +46 -0
  37. package/src/utils/agent-core-constructs/files/terraform/core/agent-core/runtime.tf.template +536 -0
  38. package/src/utils/api-constructs/api-constructs.d.ts +4 -4
  39. package/src/utils/api-constructs/api-constructs.js +45 -5
  40. package/src/utils/api-constructs/api-constructs.js.map +1 -1
  41. package/src/utils/api-constructs/files/terraform/app/apis/http/__apiNameKebabCase__/__apiNameKebabCase__.tf.template +382 -0
  42. package/src/utils/api-constructs/files/terraform/app/apis/rest/__apiNameKebabCase__/__apiNameKebabCase__.tf.template +508 -0
  43. package/src/utils/api-constructs/files/terraform/core/api/http/http-api/http-api.tf.template +250 -0
  44. package/src/utils/api-constructs/files/terraform/core/api/rest/rest-api/rest-api.tf.template +150 -0
  45. package/src/utils/files/terraform/src/metrics/metrics.tf.template +3 -2
  46. package/src/utils/py.d.ts +5 -0
  47. package/src/utils/py.js +9 -1
  48. package/src/utils/py.js.map +1 -1
  49. package/src/utils/shared-constructs-constants.d.ts +2 -0
  50. package/src/utils/shared-constructs-constants.js +3 -1
  51. package/src/utils/shared-constructs-constants.js.map +1 -1
  52. package/src/utils/shared-constructs.js +2 -2
  53. package/src/utils/shared-constructs.js.map +1 -1
  54. package/src/utils/versions.d.ts +63 -61
  55. package/src/utils/versions.js +62 -60
  56. package/src/utils/versions.js.map +1 -1
  57. /package/src/utils/agent-core-constructs/files/{app → cdk/app}/agent-core/__nameKebabCase__/Dockerfile.template +0 -0
  58. /package/src/utils/agent-core-constructs/files/{app → cdk/app}/agent-core/__nameKebabCase__/__nameKebabCase__.ts.template +0 -0
  59. /package/src/utils/agent-core-constructs/files/{core → cdk/core}/agent-core/runtime.ts.template +0 -0
  60. /package/src/utils/api-constructs/files/{app → cdk/app}/apis/http/__apiNameKebabCase__.ts.template +0 -0
  61. /package/src/utils/api-constructs/files/{app → cdk/app}/apis/rest/__apiNameKebabCase__.ts.template +0 -0
  62. /package/src/utils/api-constructs/files/{core → cdk/core}/api/http/http-api.ts.template +0 -0
  63. /package/src/utils/api-constructs/files/{core → cdk/core}/api/rest/rest-api.ts.template +0 -0
  64. /package/src/utils/api-constructs/files/{core → cdk/core}/api/trpc/trpc-utils.ts.template +0 -0
  65. /package/src/utils/api-constructs/files/{core → cdk/core}/api/utils/utils.ts.template +0 -0
@@ -1123,3 +1123,3672 @@ export class IntegrationBuilder<
1123
1123
  }
1124
1124
  "
1125
1125
  `;
1126
+
1127
+ exports[`fastapi project generator > terraform iacProvider > should generate terraform files for HTTP API with Cognito auth and snapshot them > terraform-http-cognito-files 1`] = `
1128
+ {
1129
+ "http-api.tf": "# Core HTTP API Gateway module
1130
+ # This module creates the API Gateway HTTP API, stage, and logging resources
1131
+
1132
+ terraform {
1133
+ required_version = ">= 1.0"
1134
+
1135
+ required_providers {
1136
+ aws = {
1137
+ source = "hashicorp/aws"
1138
+ version = "~> 6.0"
1139
+ }
1140
+ }
1141
+ }
1142
+
1143
+ # Core HTTP API Gateway Variables
1144
+
1145
+ variable "api_name" {
1146
+ description = "Name of the HTTP API Gateway"
1147
+ type = string
1148
+ }
1149
+
1150
+ variable "api_description" {
1151
+ description = "Description of the HTTP API Gateway"
1152
+ type = string
1153
+ default = "HTTP API Gateway"
1154
+ }
1155
+
1156
+ variable "stage_name" {
1157
+ description = "Name of the API Gateway stage"
1158
+ type = string
1159
+ default = "prod"
1160
+ }
1161
+
1162
+ variable "stage_auto_deploy" {
1163
+ description = "Whether to automatically deploy the API stage"
1164
+ type = bool
1165
+ default = true
1166
+ }
1167
+
1168
+ # CORS Configuration
1169
+
1170
+ variable "cors_allow_credentials" {
1171
+ description = "Whether to allow credentials in CORS requests"
1172
+ type = bool
1173
+ default = false
1174
+ }
1175
+
1176
+ variable "cors_allow_headers" {
1177
+ description = "List of allowed headers for CORS"
1178
+ type = list(string)
1179
+ default = ["authorization", "content-type", "x-amz-content-sha256", "x-amz-date", "x-amz-security-token"]
1180
+ }
1181
+
1182
+ variable "cors_allow_methods" {
1183
+ description = "List of allowed HTTP methods for CORS"
1184
+ type = list(string)
1185
+ default = ["*"]
1186
+ }
1187
+
1188
+ variable "cors_allow_origins" {
1189
+ description = "List of allowed origins for CORS"
1190
+ type = list(string)
1191
+ default = ["*"]
1192
+ }
1193
+
1194
+ variable "cors_expose_headers" {
1195
+ description = "List of headers to expose in CORS responses"
1196
+ type = list(string)
1197
+ default = []
1198
+ }
1199
+
1200
+ variable "cors_max_age" {
1201
+ description = "Maximum age for CORS preflight requests in seconds"
1202
+ type = number
1203
+ default = 86400
1204
+ }
1205
+
1206
+ # Tags
1207
+
1208
+ variable "tags" {
1209
+ description = "Tags to apply to all resources"
1210
+ type = map(string)
1211
+ default = {}
1212
+ }
1213
+
1214
+ # Data sources
1215
+ data "aws_region" "current" {}
1216
+ data "aws_caller_identity" "current" {}
1217
+
1218
+ # Resources
1219
+
1220
+ # KMS key for CloudWatch log group encryption
1221
+ resource "aws_kms_key" "logs_key" {
1222
+ description = "KMS key for CloudWatch log group encryption"
1223
+ deletion_window_in_days = 7
1224
+ enable_key_rotation = true
1225
+
1226
+ policy = jsonencode({
1227
+ Version = "2012-10-17"
1228
+ Statement = [
1229
+ {
1230
+ Sid = "Enable IAM User Permissions"
1231
+ Effect = "Allow"
1232
+ Principal = {
1233
+ AWS = "arn:aws:iam::\${data.aws_caller_identity.current.account_id}:root"
1234
+ }
1235
+ Action = "kms:*"
1236
+ Resource = "*"
1237
+ },
1238
+ {
1239
+ Sid = "Allow CloudWatch Logs"
1240
+ Effect = "Allow"
1241
+ Principal = {
1242
+ Service = "logs.\${data.aws_region.current.name}.amazonaws.com"
1243
+ }
1244
+ Action = [
1245
+ "kms:Encrypt",
1246
+ "kms:Decrypt",
1247
+ "kms:ReEncrypt*",
1248
+ "kms:GenerateDataKey*",
1249
+ "kms:DescribeKey"
1250
+ ]
1251
+ Resource = "*"
1252
+ Condition = {
1253
+ ArnEquals = {
1254
+ "kms:EncryptionContext:aws:logs:arn" = "arn:aws:logs:\${data.aws_region.current.name}:\${data.aws_caller_identity.current.account_id}:log-group:/aws/apigateway/\${var.api_name}"
1255
+ }
1256
+ }
1257
+ }
1258
+ ]
1259
+ })
1260
+
1261
+ tags = var.tags
1262
+ }
1263
+
1264
+ resource "aws_kms_alias" "logs_key_alias" {
1265
+ name = "alias/\${var.api_name}-api-logs-encryption"
1266
+ target_key_id = aws_kms_key.logs_key.key_id
1267
+ }
1268
+
1269
+ # HTTP API Gateway
1270
+ resource "aws_apigatewayv2_api" "http_api" {
1271
+ name = var.api_name
1272
+ protocol_type = "HTTP"
1273
+ description = var.api_description
1274
+
1275
+ cors_configuration {
1276
+ allow_credentials = var.cors_allow_credentials
1277
+ allow_headers = var.cors_allow_headers
1278
+ allow_methods = var.cors_allow_methods
1279
+ allow_origins = var.cors_allow_origins
1280
+ expose_headers = var.cors_expose_headers
1281
+ max_age = var.cors_max_age
1282
+ }
1283
+
1284
+ tags = var.tags
1285
+ }
1286
+
1287
+ # API Gateway stage
1288
+ resource "aws_apigatewayv2_stage" "api_stage" {
1289
+ api_id = aws_apigatewayv2_api.http_api.id
1290
+ name = var.stage_name
1291
+ auto_deploy = var.stage_auto_deploy
1292
+
1293
+ access_log_settings {
1294
+ destination_arn = aws_cloudwatch_log_group.api_logs.arn
1295
+ format = jsonencode({
1296
+ requestId = "$context.requestId"
1297
+ ip = "$context.identity.sourceIp"
1298
+ requestTime = "$context.requestTime"
1299
+ httpMethod = "$context.httpMethod"
1300
+ routeKey = "$context.routeKey"
1301
+ status = "$context.status"
1302
+ protocol = "$context.protocol"
1303
+ responseLength = "$context.responseLength"
1304
+ error = "$context.error.message"
1305
+ integrationError = "$context.integrationErrorMessage"
1306
+ })
1307
+ }
1308
+
1309
+ default_route_settings {
1310
+ throttling_burst_limit = 5000
1311
+ throttling_rate_limit = 10000
1312
+ }
1313
+
1314
+ tags = var.tags
1315
+
1316
+ depends_on = [aws_cloudwatch_log_group.api_logs]
1317
+ }
1318
+
1319
+ # CloudWatch Log Group for API Gateway
1320
+ resource "aws_cloudwatch_log_group" "api_logs" {
1321
+ #checkov:skip=CKV_AWS_338:Log retention set to forever
1322
+ #checkov:skip=CKV_AWS_66:Log retention set to forever
1323
+ name = "/aws/apigateway/\${var.api_name}"
1324
+ kms_key_id = aws_kms_key.logs_key.arn
1325
+ tags = var.tags
1326
+ }
1327
+
1328
+ # Outputs
1329
+
1330
+ output "api_id" {
1331
+ description = "ID of the HTTP API Gateway"
1332
+ value = aws_apigatewayv2_api.http_api.id
1333
+ }
1334
+
1335
+ output "api_arn" {
1336
+ description = "ARN of the HTTP API Gateway"
1337
+ value = aws_apigatewayv2_api.http_api.arn
1338
+ }
1339
+
1340
+ output "api_endpoint" {
1341
+ description = "Base URL of the HTTP API Gateway"
1342
+ value = aws_apigatewayv2_api.http_api.api_endpoint
1343
+ }
1344
+
1345
+ output "api_execution_arn" {
1346
+ description = "Execution ARN of the HTTP API Gateway"
1347
+ value = aws_apigatewayv2_api.http_api.execution_arn
1348
+ }
1349
+
1350
+ output "stage_id" {
1351
+ description = "ID of the API Gateway stage"
1352
+ value = aws_apigatewayv2_stage.api_stage.id
1353
+ }
1354
+
1355
+ output "stage_arn" {
1356
+ description = "ARN of the API Gateway stage"
1357
+ value = aws_apigatewayv2_stage.api_stage.arn
1358
+ }
1359
+
1360
+ output "stage_execution_arn" {
1361
+ description = "Execution ARN of the API Gateway stage"
1362
+ value = aws_apigatewayv2_stage.api_stage.execution_arn
1363
+ }
1364
+
1365
+ output "stage_invoke_url" {
1366
+ description = "Invoke URL of the API Gateway stage"
1367
+ value = aws_apigatewayv2_stage.api_stage.invoke_url
1368
+ }
1369
+
1370
+ output "api_log_group_name" {
1371
+ description = "Name of the API Gateway CloudWatch log group"
1372
+ value = aws_cloudwatch_log_group.api_logs.name
1373
+ }
1374
+
1375
+ output "api_log_group_arn" {
1376
+ description = "ARN of the API Gateway CloudWatch log group"
1377
+ value = aws_cloudwatch_log_group.api_logs.arn
1378
+ }",
1379
+ "test-api.tf": "terraform {
1380
+ required_version = ">= 1.0"
1381
+
1382
+ required_providers {
1383
+ aws = {
1384
+ source = "hashicorp/aws"
1385
+ version = "~> 6.0"
1386
+ }
1387
+ }
1388
+ }
1389
+
1390
+ # Authentication Configuration
1391
+ variable "user_pool_id" {
1392
+ description = "Cognito User Pool ID for authentication"
1393
+ type = string
1394
+ }
1395
+
1396
+ variable "user_pool_client_ids" {
1397
+ description = "List of Cognito User Pool Client IDs"
1398
+ type = list(string)
1399
+ }
1400
+
1401
+ variable "env" {
1402
+ description = "Environment variables for the Lambda function"
1403
+ type = map(string)
1404
+ default = {}
1405
+ }
1406
+
1407
+ variable "additional_iam_policy_statements" {
1408
+ description = "Additional IAM policy statements for the Lambda function"
1409
+ type = list(object({
1410
+ Effect = string
1411
+ Action = list(string)
1412
+ Resource = list(string)
1413
+ }))
1414
+ default = []
1415
+ }
1416
+
1417
+ # CORS Configuration (passed to core module)
1418
+ variable "cors_allow_credentials" {
1419
+ description = "Whether to allow credentials in CORS requests"
1420
+ type = bool
1421
+ default = false
1422
+ }
1423
+
1424
+ variable "cors_allow_headers" {
1425
+ description = "List of allowed headers for CORS"
1426
+ type = list(string)
1427
+ default = ["authorization", "content-type", "x-amz-content-sha256", "x-amz-date", "x-amz-security-token"]
1428
+ }
1429
+
1430
+ variable "cors_allow_methods" {
1431
+ description = "List of allowed HTTP methods for CORS"
1432
+ type = list(string)
1433
+ default = ["*"]
1434
+ }
1435
+
1436
+ variable "cors_allow_origins" {
1437
+ description = "List of allowed origins for CORS"
1438
+ type = list(string)
1439
+ default = ["*"]
1440
+ }
1441
+
1442
+ variable "cors_expose_headers" {
1443
+ description = "List of headers to expose in CORS responses"
1444
+ type = list(string)
1445
+ default = []
1446
+ }
1447
+
1448
+ variable "cors_max_age" {
1449
+ description = "Maximum age for CORS preflight requests in seconds"
1450
+ type = number
1451
+ default = 0
1452
+ }
1453
+
1454
+ # Tags
1455
+ variable "tags" {
1456
+ description = "Tags to apply to all resources"
1457
+ type = map(string)
1458
+ default = {}
1459
+ }
1460
+
1461
+ # Get current AWS region and account ID
1462
+ data "aws_region" "current" {}
1463
+ data "aws_caller_identity" "current" {}
1464
+
1465
+ # Resources
1466
+
1467
+ # Create Lambda ZIP file from the bundle directory
1468
+ data "archive_file" "lambda_zip" {
1469
+ type = "zip"
1470
+ source_dir = "\${path.module}/../../../../../../../dist/apps/test_api/bundle"
1471
+ output_path = "\${path.module}/../../../../../../../dist/packages/common/terraform/apis/test-api/lambda.zip"
1472
+ }
1473
+
1474
+
1475
+ # Use the core HTTP API module
1476
+ module "http_api" {
1477
+ source = "../../../core/api/http-api"
1478
+
1479
+ api_name = "TestApi"
1480
+ api_description = "TestApi HTTP API"
1481
+ stage_name = "$default"
1482
+ stage_auto_deploy = true
1483
+
1484
+ # CORS Configuration
1485
+ cors_allow_credentials = var.cors_allow_credentials
1486
+ cors_allow_headers = var.cors_allow_headers
1487
+ cors_allow_methods = var.cors_allow_methods
1488
+ cors_allow_origins = var.cors_allow_origins
1489
+ cors_expose_headers = var.cors_expose_headers
1490
+ cors_max_age = var.cors_max_age
1491
+
1492
+ # Tags
1493
+ tags = var.tags
1494
+ }
1495
+
1496
+ # Lambda function
1497
+ # This configures a single "router" lambda to serve all requests
1498
+ resource "aws_lambda_function" "api_lambda" {
1499
+ #checkov:skip=CKV_AWS_117:Lambda function does not need to be in VPC for this use case
1500
+ #checkov:skip=CKV_AWS_116:Dead Letter Queue not required for this simple API use case
1501
+ #checkov:skip=CKV_AWS_272:Code signing not required for this use case
1502
+ #checkov:skip=CKV_AWS_115:Concurrent execution limit not required for this use case
1503
+ #checkov:skip=CKV_AWS_173:Lambda environment variables encrypted by managed key
1504
+ filename = data.archive_file.lambda_zip.output_path
1505
+ function_name = "TestApiHandler"
1506
+ role = aws_iam_role.lambda_execution_role.arn
1507
+ handler = "proj_test_api.main.handler"
1508
+ runtime = "python3.12"
1509
+ timeout = 30
1510
+ memory_size = 128
1511
+
1512
+ source_code_hash = data.archive_file.lambda_zip.output_base64sha256
1513
+
1514
+ # Enable X-Ray tracing
1515
+ tracing_config {
1516
+ mode = "Active"
1517
+ }
1518
+
1519
+ environment {
1520
+ variables = merge({
1521
+ AWS_CONNECTION_REUSE_ENABLED = "1"
1522
+ }, var.env)
1523
+ }
1524
+
1525
+ tags = var.tags
1526
+ }
1527
+
1528
+ # IAM role for Lambda execution
1529
+ resource "aws_iam_role" "lambda_execution_role" {
1530
+ name = "TestApiHandler-execution-role"
1531
+
1532
+ assume_role_policy = jsonencode({
1533
+ Version = "2012-10-17"
1534
+ Statement = [
1535
+ {
1536
+ Action = "sts:AssumeRole"
1537
+ Effect = "Allow"
1538
+ Principal = {
1539
+ Service = "lambda.amazonaws.com"
1540
+ }
1541
+ }
1542
+ ]
1543
+ })
1544
+
1545
+ tags = var.tags
1546
+ }
1547
+
1548
+ # Attach basic execution policy to Lambda role
1549
+ resource "aws_iam_role_policy_attachment" "lambda_basic_execution" {
1550
+ policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
1551
+ role = aws_iam_role.lambda_execution_role.name
1552
+ }
1553
+
1554
+ # Attach X-Ray tracing policy to Lambda role
1555
+ resource "aws_iam_role_policy_attachment" "lambda_xray_execution" {
1556
+ policy_arn = "arn:aws:iam::aws:policy/AWSXRayDaemonWriteAccess"
1557
+ role = aws_iam_role.lambda_execution_role.name
1558
+ }
1559
+
1560
+ # Additional IAM policies for Lambda (if provided)
1561
+ resource "aws_iam_role_policy" "lambda_additional_policies" {
1562
+ count = length(var.additional_iam_policy_statements) > 0 ? 1 : 0
1563
+ name = "TestApiHandler-additional-policies"
1564
+ role = aws_iam_role.lambda_execution_role.id
1565
+
1566
+ policy = jsonencode({
1567
+ Version = "2012-10-17"
1568
+ Statement = var.additional_iam_policy_statements
1569
+ })
1570
+ }
1571
+
1572
+ # CloudWatch Log Group for Lambda
1573
+ resource "aws_cloudwatch_log_group" "lambda_logs" {
1574
+ #checkov:skip=CKV_AWS_158:Using default CloudWatch log encryption
1575
+ #checkov:skip=CKV_AWS_338:Log retention set to forever
1576
+ #checkov:skip=CKV_AWS_66:Log retention set to forever
1577
+ name = "/aws/lambda/TestApiHandler"
1578
+ tags = var.tags
1579
+ }
1580
+
1581
+ # Cognito User Pool Authorizer
1582
+ resource "aws_apigatewayv2_authorizer" "cognito_authorizer" {
1583
+ api_id = module.http_api.api_id
1584
+ authorizer_type = "JWT"
1585
+ identity_sources = ["$request.header.Authorization"]
1586
+ name = "TestApiAuthorizer"
1587
+
1588
+ jwt_configuration {
1589
+ audience = var.user_pool_client_ids
1590
+ issuer = "https://cognito-idp.\${data.aws_region.current.name}.amazonaws.com/\${var.user_pool_id}"
1591
+ }
1592
+ }
1593
+
1594
+ # Lambda integration for HTTP API
1595
+ resource "aws_apigatewayv2_integration" "lambda_integration" {
1596
+ api_id = module.http_api.api_id
1597
+ integration_type = "AWS_PROXY"
1598
+ integration_uri = aws_lambda_function.api_lambda.invoke_arn
1599
+
1600
+ payload_format_version = "2.0"
1601
+ timeout_milliseconds = 30000
1602
+
1603
+ depends_on = [aws_lambda_function.api_lambda]
1604
+ }
1605
+
1606
+ # Route for proxy integration (catches all requests)
1607
+ resource "aws_apigatewayv2_route" "proxy_routes" {
1608
+ # NB: OPTIONS is omitted here since API Gateway manages responding to preflight requests
1609
+ # when cors settings are configured
1610
+ for_each = toset(["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD"])
1611
+
1612
+ api_id = module.http_api.api_id
1613
+ route_key = "\${each.key} /{proxy+}"
1614
+ target = "integrations/\${aws_apigatewayv2_integration.lambda_integration.id}"
1615
+
1616
+ authorization_type = "JWT"
1617
+ authorizer_id = aws_apigatewayv2_authorizer.cognito_authorizer.id
1618
+
1619
+ depends_on = [aws_apigatewayv2_integration.lambda_integration, aws_apigatewayv2_authorizer.cognito_authorizer]
1620
+ }
1621
+
1622
+ # Lambda permission for API Gateway to invoke the function
1623
+ resource "aws_lambda_permission" "api_gateway_invoke" {
1624
+ statement_id = "AllowExecutionFromAPIGateway"
1625
+ action = "lambda:InvokeFunction"
1626
+ function_name = aws_lambda_function.api_lambda.function_name
1627
+ principal = "apigateway.amazonaws.com"
1628
+ source_arn = "\${module.http_api.api_execution_arn}/*/*"
1629
+
1630
+ depends_on = [module.http_api, aws_lambda_function.api_lambda]
1631
+ }
1632
+
1633
+ # Outputs
1634
+
1635
+ # API Gateway Outputs (from core module)
1636
+ output "api_id" {
1637
+ description = "ID of the HTTP API Gateway"
1638
+ value = module.http_api.api_id
1639
+ }
1640
+
1641
+ output "api_arn" {
1642
+ description = "ARN of the HTTP API Gateway"
1643
+ value = module.http_api.api_arn
1644
+ }
1645
+
1646
+ output "api_endpoint" {
1647
+ description = "Base URL of the HTTP API Gateway"
1648
+ value = module.http_api.api_endpoint
1649
+ }
1650
+
1651
+ output "api_execution_arn" {
1652
+ description = "Execution ARN of the HTTP API Gateway"
1653
+ value = module.http_api.api_execution_arn
1654
+ }
1655
+
1656
+ output "stage_invoke_url" {
1657
+ description = "Invoke URL of the API Gateway stage"
1658
+ value = module.http_api.stage_invoke_url
1659
+ }
1660
+
1661
+ output "stage_arn" {
1662
+ description = "ARN of the API Gateway stage"
1663
+ value = module.http_api.stage_arn
1664
+ }
1665
+
1666
+ output "stage_execution_arn" {
1667
+ description = "Execution ARN of the API Gateway stage"
1668
+ value = module.http_api.stage_execution_arn
1669
+ }
1670
+
1671
+ # Lambda Function Outputs
1672
+ output "lambda_function_name" {
1673
+ description = "Name of the Lambda function"
1674
+ value = aws_lambda_function.api_lambda.function_name
1675
+ }
1676
+
1677
+ output "lambda_function_arn" {
1678
+ description = "ARN of the Lambda function"
1679
+ value = aws_lambda_function.api_lambda.arn
1680
+ }
1681
+
1682
+ output "lambda_invoke_arn" {
1683
+ description = "Invoke ARN of the Lambda function"
1684
+ value = aws_lambda_function.api_lambda.invoke_arn
1685
+ }
1686
+
1687
+ output "lambda_qualified_arn" {
1688
+ description = "Qualified ARN of the Lambda function"
1689
+ value = aws_lambda_function.api_lambda.qualified_arn
1690
+ }
1691
+
1692
+ output "lambda_version" {
1693
+ description = "Version of the Lambda function"
1694
+ value = aws_lambda_function.api_lambda.version
1695
+ }
1696
+
1697
+ output "lambda_source_code_hash" {
1698
+ description = "Base64-encoded SHA256 hash of the Lambda deployment package"
1699
+ value = aws_lambda_function.api_lambda.source_code_hash
1700
+ }
1701
+
1702
+ output "lambda_source_code_size" {
1703
+ description = "Size of the Lambda deployment package in bytes"
1704
+ value = aws_lambda_function.api_lambda.source_code_size
1705
+ }
1706
+
1707
+ # IAM Role Outputs
1708
+ output "lambda_execution_role_arn" {
1709
+ description = "ARN of the Lambda execution role"
1710
+ value = aws_iam_role.lambda_execution_role.arn
1711
+ }
1712
+
1713
+ output "lambda_execution_role_name" {
1714
+ description = "Name of the Lambda execution role"
1715
+ value = aws_iam_role.lambda_execution_role.name
1716
+ }
1717
+
1718
+ # Integration Outputs
1719
+ output "integration_id" {
1720
+ description = "ID of the Lambda integration"
1721
+ value = aws_apigatewayv2_integration.lambda_integration.id
1722
+ }
1723
+
1724
+ # CloudWatch Log Groups
1725
+ output "lambda_log_group_name" {
1726
+ description = "Name of the Lambda CloudWatch log group"
1727
+ value = aws_cloudwatch_log_group.lambda_logs.name
1728
+ }
1729
+
1730
+ output "lambda_log_group_arn" {
1731
+ description = "ARN of the Lambda CloudWatch log group"
1732
+ value = aws_cloudwatch_log_group.lambda_logs.arn
1733
+ }
1734
+
1735
+ output "api_log_group_name" {
1736
+ description = "Name of the API Gateway CloudWatch log group"
1737
+ value = module.http_api.api_log_group_name
1738
+ }
1739
+
1740
+ output "api_log_group_arn" {
1741
+ description = "ARN of the API Gateway CloudWatch log group"
1742
+ value = module.http_api.api_log_group_arn
1743
+ }",
1744
+ }
1745
+ `;
1746
+
1747
+ exports[`fastapi project generator > terraform iacProvider > should generate terraform files for HTTP API with IAM auth and snapshot them > terraform-http-iam-files 1`] = `
1748
+ {
1749
+ "http-api.tf": "# Core HTTP API Gateway module
1750
+ # This module creates the API Gateway HTTP API, stage, and logging resources
1751
+
1752
+ terraform {
1753
+ required_version = ">= 1.0"
1754
+
1755
+ required_providers {
1756
+ aws = {
1757
+ source = "hashicorp/aws"
1758
+ version = "~> 6.0"
1759
+ }
1760
+ }
1761
+ }
1762
+
1763
+ # Core HTTP API Gateway Variables
1764
+
1765
+ variable "api_name" {
1766
+ description = "Name of the HTTP API Gateway"
1767
+ type = string
1768
+ }
1769
+
1770
+ variable "api_description" {
1771
+ description = "Description of the HTTP API Gateway"
1772
+ type = string
1773
+ default = "HTTP API Gateway"
1774
+ }
1775
+
1776
+ variable "stage_name" {
1777
+ description = "Name of the API Gateway stage"
1778
+ type = string
1779
+ default = "prod"
1780
+ }
1781
+
1782
+ variable "stage_auto_deploy" {
1783
+ description = "Whether to automatically deploy the API stage"
1784
+ type = bool
1785
+ default = true
1786
+ }
1787
+
1788
+ # CORS Configuration
1789
+
1790
+ variable "cors_allow_credentials" {
1791
+ description = "Whether to allow credentials in CORS requests"
1792
+ type = bool
1793
+ default = false
1794
+ }
1795
+
1796
+ variable "cors_allow_headers" {
1797
+ description = "List of allowed headers for CORS"
1798
+ type = list(string)
1799
+ default = ["authorization", "content-type", "x-amz-content-sha256", "x-amz-date", "x-amz-security-token"]
1800
+ }
1801
+
1802
+ variable "cors_allow_methods" {
1803
+ description = "List of allowed HTTP methods for CORS"
1804
+ type = list(string)
1805
+ default = ["*"]
1806
+ }
1807
+
1808
+ variable "cors_allow_origins" {
1809
+ description = "List of allowed origins for CORS"
1810
+ type = list(string)
1811
+ default = ["*"]
1812
+ }
1813
+
1814
+ variable "cors_expose_headers" {
1815
+ description = "List of headers to expose in CORS responses"
1816
+ type = list(string)
1817
+ default = []
1818
+ }
1819
+
1820
+ variable "cors_max_age" {
1821
+ description = "Maximum age for CORS preflight requests in seconds"
1822
+ type = number
1823
+ default = 86400
1824
+ }
1825
+
1826
+ # Tags
1827
+
1828
+ variable "tags" {
1829
+ description = "Tags to apply to all resources"
1830
+ type = map(string)
1831
+ default = {}
1832
+ }
1833
+
1834
+ # Data sources
1835
+ data "aws_region" "current" {}
1836
+ data "aws_caller_identity" "current" {}
1837
+
1838
+ # Resources
1839
+
1840
+ # KMS key for CloudWatch log group encryption
1841
+ resource "aws_kms_key" "logs_key" {
1842
+ description = "KMS key for CloudWatch log group encryption"
1843
+ deletion_window_in_days = 7
1844
+ enable_key_rotation = true
1845
+
1846
+ policy = jsonencode({
1847
+ Version = "2012-10-17"
1848
+ Statement = [
1849
+ {
1850
+ Sid = "Enable IAM User Permissions"
1851
+ Effect = "Allow"
1852
+ Principal = {
1853
+ AWS = "arn:aws:iam::\${data.aws_caller_identity.current.account_id}:root"
1854
+ }
1855
+ Action = "kms:*"
1856
+ Resource = "*"
1857
+ },
1858
+ {
1859
+ Sid = "Allow CloudWatch Logs"
1860
+ Effect = "Allow"
1861
+ Principal = {
1862
+ Service = "logs.\${data.aws_region.current.name}.amazonaws.com"
1863
+ }
1864
+ Action = [
1865
+ "kms:Encrypt",
1866
+ "kms:Decrypt",
1867
+ "kms:ReEncrypt*",
1868
+ "kms:GenerateDataKey*",
1869
+ "kms:DescribeKey"
1870
+ ]
1871
+ Resource = "*"
1872
+ Condition = {
1873
+ ArnEquals = {
1874
+ "kms:EncryptionContext:aws:logs:arn" = "arn:aws:logs:\${data.aws_region.current.name}:\${data.aws_caller_identity.current.account_id}:log-group:/aws/apigateway/\${var.api_name}"
1875
+ }
1876
+ }
1877
+ }
1878
+ ]
1879
+ })
1880
+
1881
+ tags = var.tags
1882
+ }
1883
+
1884
+ resource "aws_kms_alias" "logs_key_alias" {
1885
+ name = "alias/\${var.api_name}-api-logs-encryption"
1886
+ target_key_id = aws_kms_key.logs_key.key_id
1887
+ }
1888
+
1889
+ # HTTP API Gateway
1890
+ resource "aws_apigatewayv2_api" "http_api" {
1891
+ name = var.api_name
1892
+ protocol_type = "HTTP"
1893
+ description = var.api_description
1894
+
1895
+ cors_configuration {
1896
+ allow_credentials = var.cors_allow_credentials
1897
+ allow_headers = var.cors_allow_headers
1898
+ allow_methods = var.cors_allow_methods
1899
+ allow_origins = var.cors_allow_origins
1900
+ expose_headers = var.cors_expose_headers
1901
+ max_age = var.cors_max_age
1902
+ }
1903
+
1904
+ tags = var.tags
1905
+ }
1906
+
1907
+ # API Gateway stage
1908
+ resource "aws_apigatewayv2_stage" "api_stage" {
1909
+ api_id = aws_apigatewayv2_api.http_api.id
1910
+ name = var.stage_name
1911
+ auto_deploy = var.stage_auto_deploy
1912
+
1913
+ access_log_settings {
1914
+ destination_arn = aws_cloudwatch_log_group.api_logs.arn
1915
+ format = jsonencode({
1916
+ requestId = "$context.requestId"
1917
+ ip = "$context.identity.sourceIp"
1918
+ requestTime = "$context.requestTime"
1919
+ httpMethod = "$context.httpMethod"
1920
+ routeKey = "$context.routeKey"
1921
+ status = "$context.status"
1922
+ protocol = "$context.protocol"
1923
+ responseLength = "$context.responseLength"
1924
+ error = "$context.error.message"
1925
+ integrationError = "$context.integrationErrorMessage"
1926
+ })
1927
+ }
1928
+
1929
+ default_route_settings {
1930
+ throttling_burst_limit = 5000
1931
+ throttling_rate_limit = 10000
1932
+ }
1933
+
1934
+ tags = var.tags
1935
+
1936
+ depends_on = [aws_cloudwatch_log_group.api_logs]
1937
+ }
1938
+
1939
+ # CloudWatch Log Group for API Gateway
1940
+ resource "aws_cloudwatch_log_group" "api_logs" {
1941
+ #checkov:skip=CKV_AWS_338:Log retention set to forever
1942
+ #checkov:skip=CKV_AWS_66:Log retention set to forever
1943
+ name = "/aws/apigateway/\${var.api_name}"
1944
+ kms_key_id = aws_kms_key.logs_key.arn
1945
+ tags = var.tags
1946
+ }
1947
+
1948
+ # Outputs
1949
+
1950
+ output "api_id" {
1951
+ description = "ID of the HTTP API Gateway"
1952
+ value = aws_apigatewayv2_api.http_api.id
1953
+ }
1954
+
1955
+ output "api_arn" {
1956
+ description = "ARN of the HTTP API Gateway"
1957
+ value = aws_apigatewayv2_api.http_api.arn
1958
+ }
1959
+
1960
+ output "api_endpoint" {
1961
+ description = "Base URL of the HTTP API Gateway"
1962
+ value = aws_apigatewayv2_api.http_api.api_endpoint
1963
+ }
1964
+
1965
+ output "api_execution_arn" {
1966
+ description = "Execution ARN of the HTTP API Gateway"
1967
+ value = aws_apigatewayv2_api.http_api.execution_arn
1968
+ }
1969
+
1970
+ output "stage_id" {
1971
+ description = "ID of the API Gateway stage"
1972
+ value = aws_apigatewayv2_stage.api_stage.id
1973
+ }
1974
+
1975
+ output "stage_arn" {
1976
+ description = "ARN of the API Gateway stage"
1977
+ value = aws_apigatewayv2_stage.api_stage.arn
1978
+ }
1979
+
1980
+ output "stage_execution_arn" {
1981
+ description = "Execution ARN of the API Gateway stage"
1982
+ value = aws_apigatewayv2_stage.api_stage.execution_arn
1983
+ }
1984
+
1985
+ output "stage_invoke_url" {
1986
+ description = "Invoke URL of the API Gateway stage"
1987
+ value = aws_apigatewayv2_stage.api_stage.invoke_url
1988
+ }
1989
+
1990
+ output "api_log_group_name" {
1991
+ description = "Name of the API Gateway CloudWatch log group"
1992
+ value = aws_cloudwatch_log_group.api_logs.name
1993
+ }
1994
+
1995
+ output "api_log_group_arn" {
1996
+ description = "ARN of the API Gateway CloudWatch log group"
1997
+ value = aws_cloudwatch_log_group.api_logs.arn
1998
+ }",
1999
+ "test-api.tf": "terraform {
2000
+ required_version = ">= 1.0"
2001
+
2002
+ required_providers {
2003
+ aws = {
2004
+ source = "hashicorp/aws"
2005
+ version = "~> 6.0"
2006
+ }
2007
+ }
2008
+ }
2009
+
2010
+
2011
+ variable "env" {
2012
+ description = "Environment variables for the Lambda function"
2013
+ type = map(string)
2014
+ default = {}
2015
+ }
2016
+
2017
+ variable "additional_iam_policy_statements" {
2018
+ description = "Additional IAM policy statements for the Lambda function"
2019
+ type = list(object({
2020
+ Effect = string
2021
+ Action = list(string)
2022
+ Resource = list(string)
2023
+ }))
2024
+ default = []
2025
+ }
2026
+
2027
+ # CORS Configuration (passed to core module)
2028
+ variable "cors_allow_credentials" {
2029
+ description = "Whether to allow credentials in CORS requests"
2030
+ type = bool
2031
+ default = false
2032
+ }
2033
+
2034
+ variable "cors_allow_headers" {
2035
+ description = "List of allowed headers for CORS"
2036
+ type = list(string)
2037
+ default = ["authorization", "content-type", "x-amz-content-sha256", "x-amz-date", "x-amz-security-token"]
2038
+ }
2039
+
2040
+ variable "cors_allow_methods" {
2041
+ description = "List of allowed HTTP methods for CORS"
2042
+ type = list(string)
2043
+ default = ["*"]
2044
+ }
2045
+
2046
+ variable "cors_allow_origins" {
2047
+ description = "List of allowed origins for CORS"
2048
+ type = list(string)
2049
+ default = ["*"]
2050
+ }
2051
+
2052
+ variable "cors_expose_headers" {
2053
+ description = "List of headers to expose in CORS responses"
2054
+ type = list(string)
2055
+ default = []
2056
+ }
2057
+
2058
+ variable "cors_max_age" {
2059
+ description = "Maximum age for CORS preflight requests in seconds"
2060
+ type = number
2061
+ default = 0
2062
+ }
2063
+
2064
+ # Tags
2065
+ variable "tags" {
2066
+ description = "Tags to apply to all resources"
2067
+ type = map(string)
2068
+ default = {}
2069
+ }
2070
+
2071
+ # Get current AWS region and account ID
2072
+ data "aws_region" "current" {}
2073
+ data "aws_caller_identity" "current" {}
2074
+
2075
+ # Resources
2076
+
2077
+ # Create Lambda ZIP file from the bundle directory
2078
+ data "archive_file" "lambda_zip" {
2079
+ type = "zip"
2080
+ source_dir = "\${path.module}/../../../../../../../dist/apps/test_api/bundle"
2081
+ output_path = "\${path.module}/../../../../../../../dist/packages/common/terraform/apis/test-api/lambda.zip"
2082
+ }
2083
+
2084
+
2085
+ # Use the core HTTP API module
2086
+ module "http_api" {
2087
+ source = "../../../core/api/http-api"
2088
+
2089
+ api_name = "TestApi"
2090
+ api_description = "TestApi HTTP API"
2091
+ stage_name = "$default"
2092
+ stage_auto_deploy = true
2093
+
2094
+ # CORS Configuration
2095
+ cors_allow_credentials = var.cors_allow_credentials
2096
+ cors_allow_headers = var.cors_allow_headers
2097
+ cors_allow_methods = var.cors_allow_methods
2098
+ cors_allow_origins = var.cors_allow_origins
2099
+ cors_expose_headers = var.cors_expose_headers
2100
+ cors_max_age = var.cors_max_age
2101
+
2102
+ # Tags
2103
+ tags = var.tags
2104
+ }
2105
+
2106
+ # Lambda function
2107
+ # This configures a single "router" lambda to serve all requests
2108
+ resource "aws_lambda_function" "api_lambda" {
2109
+ #checkov:skip=CKV_AWS_117:Lambda function does not need to be in VPC for this use case
2110
+ #checkov:skip=CKV_AWS_116:Dead Letter Queue not required for this simple API use case
2111
+ #checkov:skip=CKV_AWS_272:Code signing not required for this use case
2112
+ #checkov:skip=CKV_AWS_115:Concurrent execution limit not required for this use case
2113
+ #checkov:skip=CKV_AWS_173:Lambda environment variables encrypted by managed key
2114
+ filename = data.archive_file.lambda_zip.output_path
2115
+ function_name = "TestApiHandler"
2116
+ role = aws_iam_role.lambda_execution_role.arn
2117
+ handler = "proj_test_api.main.handler"
2118
+ runtime = "python3.12"
2119
+ timeout = 30
2120
+ memory_size = 128
2121
+
2122
+ source_code_hash = data.archive_file.lambda_zip.output_base64sha256
2123
+
2124
+ # Enable X-Ray tracing
2125
+ tracing_config {
2126
+ mode = "Active"
2127
+ }
2128
+
2129
+ environment {
2130
+ variables = merge({
2131
+ AWS_CONNECTION_REUSE_ENABLED = "1"
2132
+ }, var.env)
2133
+ }
2134
+
2135
+ tags = var.tags
2136
+ }
2137
+
2138
+ # IAM role for Lambda execution
2139
+ resource "aws_iam_role" "lambda_execution_role" {
2140
+ name = "TestApiHandler-execution-role"
2141
+
2142
+ assume_role_policy = jsonencode({
2143
+ Version = "2012-10-17"
2144
+ Statement = [
2145
+ {
2146
+ Action = "sts:AssumeRole"
2147
+ Effect = "Allow"
2148
+ Principal = {
2149
+ Service = "lambda.amazonaws.com"
2150
+ }
2151
+ }
2152
+ ]
2153
+ })
2154
+
2155
+ tags = var.tags
2156
+ }
2157
+
2158
+ # Attach basic execution policy to Lambda role
2159
+ resource "aws_iam_role_policy_attachment" "lambda_basic_execution" {
2160
+ policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
2161
+ role = aws_iam_role.lambda_execution_role.name
2162
+ }
2163
+
2164
+ # Attach X-Ray tracing policy to Lambda role
2165
+ resource "aws_iam_role_policy_attachment" "lambda_xray_execution" {
2166
+ policy_arn = "arn:aws:iam::aws:policy/AWSXRayDaemonWriteAccess"
2167
+ role = aws_iam_role.lambda_execution_role.name
2168
+ }
2169
+
2170
+ # Additional IAM policies for Lambda (if provided)
2171
+ resource "aws_iam_role_policy" "lambda_additional_policies" {
2172
+ count = length(var.additional_iam_policy_statements) > 0 ? 1 : 0
2173
+ name = "TestApiHandler-additional-policies"
2174
+ role = aws_iam_role.lambda_execution_role.id
2175
+
2176
+ policy = jsonencode({
2177
+ Version = "2012-10-17"
2178
+ Statement = var.additional_iam_policy_statements
2179
+ })
2180
+ }
2181
+
2182
+ # CloudWatch Log Group for Lambda
2183
+ resource "aws_cloudwatch_log_group" "lambda_logs" {
2184
+ #checkov:skip=CKV_AWS_158:Using default CloudWatch log encryption
2185
+ #checkov:skip=CKV_AWS_338:Log retention set to forever
2186
+ #checkov:skip=CKV_AWS_66:Log retention set to forever
2187
+ name = "/aws/lambda/TestApiHandler"
2188
+ tags = var.tags
2189
+ }
2190
+
2191
+
2192
+ # Lambda integration for HTTP API
2193
+ resource "aws_apigatewayv2_integration" "lambda_integration" {
2194
+ api_id = module.http_api.api_id
2195
+ integration_type = "AWS_PROXY"
2196
+ integration_uri = aws_lambda_function.api_lambda.invoke_arn
2197
+
2198
+ payload_format_version = "2.0"
2199
+ timeout_milliseconds = 30000
2200
+
2201
+ depends_on = [aws_lambda_function.api_lambda]
2202
+ }
2203
+
2204
+ # Route for proxy integration (catches all requests)
2205
+ resource "aws_apigatewayv2_route" "proxy_routes" {
2206
+ # NB: OPTIONS is omitted here since API Gateway manages responding to preflight requests
2207
+ # when cors settings are configured
2208
+ for_each = toset(["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD"])
2209
+
2210
+ api_id = module.http_api.api_id
2211
+ route_key = "\${each.key} /{proxy+}"
2212
+ target = "integrations/\${aws_apigatewayv2_integration.lambda_integration.id}"
2213
+
2214
+ authorization_type = "AWS_IAM"
2215
+
2216
+ depends_on = [aws_apigatewayv2_integration.lambda_integration]
2217
+ }
2218
+
2219
+ # Lambda permission for API Gateway to invoke the function
2220
+ resource "aws_lambda_permission" "api_gateway_invoke" {
2221
+ statement_id = "AllowExecutionFromAPIGateway"
2222
+ action = "lambda:InvokeFunction"
2223
+ function_name = aws_lambda_function.api_lambda.function_name
2224
+ principal = "apigateway.amazonaws.com"
2225
+ source_arn = "\${module.http_api.api_execution_arn}/*/*"
2226
+
2227
+ depends_on = [module.http_api, aws_lambda_function.api_lambda]
2228
+ }
2229
+
2230
+ # Outputs
2231
+
2232
+ # API Gateway Outputs (from core module)
2233
+ output "api_id" {
2234
+ description = "ID of the HTTP API Gateway"
2235
+ value = module.http_api.api_id
2236
+ }
2237
+
2238
+ output "api_arn" {
2239
+ description = "ARN of the HTTP API Gateway"
2240
+ value = module.http_api.api_arn
2241
+ }
2242
+
2243
+ output "api_endpoint" {
2244
+ description = "Base URL of the HTTP API Gateway"
2245
+ value = module.http_api.api_endpoint
2246
+ }
2247
+
2248
+ output "api_execution_arn" {
2249
+ description = "Execution ARN of the HTTP API Gateway"
2250
+ value = module.http_api.api_execution_arn
2251
+ }
2252
+
2253
+ output "stage_invoke_url" {
2254
+ description = "Invoke URL of the API Gateway stage"
2255
+ value = module.http_api.stage_invoke_url
2256
+ }
2257
+
2258
+ output "stage_arn" {
2259
+ description = "ARN of the API Gateway stage"
2260
+ value = module.http_api.stage_arn
2261
+ }
2262
+
2263
+ output "stage_execution_arn" {
2264
+ description = "Execution ARN of the API Gateway stage"
2265
+ value = module.http_api.stage_execution_arn
2266
+ }
2267
+
2268
+ # Lambda Function Outputs
2269
+ output "lambda_function_name" {
2270
+ description = "Name of the Lambda function"
2271
+ value = aws_lambda_function.api_lambda.function_name
2272
+ }
2273
+
2274
+ output "lambda_function_arn" {
2275
+ description = "ARN of the Lambda function"
2276
+ value = aws_lambda_function.api_lambda.arn
2277
+ }
2278
+
2279
+ output "lambda_invoke_arn" {
2280
+ description = "Invoke ARN of the Lambda function"
2281
+ value = aws_lambda_function.api_lambda.invoke_arn
2282
+ }
2283
+
2284
+ output "lambda_qualified_arn" {
2285
+ description = "Qualified ARN of the Lambda function"
2286
+ value = aws_lambda_function.api_lambda.qualified_arn
2287
+ }
2288
+
2289
+ output "lambda_version" {
2290
+ description = "Version of the Lambda function"
2291
+ value = aws_lambda_function.api_lambda.version
2292
+ }
2293
+
2294
+ output "lambda_source_code_hash" {
2295
+ description = "Base64-encoded SHA256 hash of the Lambda deployment package"
2296
+ value = aws_lambda_function.api_lambda.source_code_hash
2297
+ }
2298
+
2299
+ output "lambda_source_code_size" {
2300
+ description = "Size of the Lambda deployment package in bytes"
2301
+ value = aws_lambda_function.api_lambda.source_code_size
2302
+ }
2303
+
2304
+ # IAM Role Outputs
2305
+ output "lambda_execution_role_arn" {
2306
+ description = "ARN of the Lambda execution role"
2307
+ value = aws_iam_role.lambda_execution_role.arn
2308
+ }
2309
+
2310
+ output "lambda_execution_role_name" {
2311
+ description = "Name of the Lambda execution role"
2312
+ value = aws_iam_role.lambda_execution_role.name
2313
+ }
2314
+
2315
+ # Integration Outputs
2316
+ output "integration_id" {
2317
+ description = "ID of the Lambda integration"
2318
+ value = aws_apigatewayv2_integration.lambda_integration.id
2319
+ }
2320
+
2321
+ # CloudWatch Log Groups
2322
+ output "lambda_log_group_name" {
2323
+ description = "Name of the Lambda CloudWatch log group"
2324
+ value = aws_cloudwatch_log_group.lambda_logs.name
2325
+ }
2326
+
2327
+ output "lambda_log_group_arn" {
2328
+ description = "ARN of the Lambda CloudWatch log group"
2329
+ value = aws_cloudwatch_log_group.lambda_logs.arn
2330
+ }
2331
+
2332
+ output "api_log_group_name" {
2333
+ description = "Name of the API Gateway CloudWatch log group"
2334
+ value = module.http_api.api_log_group_name
2335
+ }
2336
+
2337
+ output "api_log_group_arn" {
2338
+ description = "ARN of the API Gateway CloudWatch log group"
2339
+ value = module.http_api.api_log_group_arn
2340
+ }",
2341
+ }
2342
+ `;
2343
+
2344
+ exports[`fastapi project generator > terraform iacProvider > should generate terraform files for HTTP API with None auth and snapshot them > terraform-http-none-files 1`] = `
2345
+ {
2346
+ "http-api.tf": "# Core HTTP API Gateway module
2347
+ # This module creates the API Gateway HTTP API, stage, and logging resources
2348
+
2349
+ terraform {
2350
+ required_version = ">= 1.0"
2351
+
2352
+ required_providers {
2353
+ aws = {
2354
+ source = "hashicorp/aws"
2355
+ version = "~> 6.0"
2356
+ }
2357
+ }
2358
+ }
2359
+
2360
+ # Core HTTP API Gateway Variables
2361
+
2362
+ variable "api_name" {
2363
+ description = "Name of the HTTP API Gateway"
2364
+ type = string
2365
+ }
2366
+
2367
+ variable "api_description" {
2368
+ description = "Description of the HTTP API Gateway"
2369
+ type = string
2370
+ default = "HTTP API Gateway"
2371
+ }
2372
+
2373
+ variable "stage_name" {
2374
+ description = "Name of the API Gateway stage"
2375
+ type = string
2376
+ default = "prod"
2377
+ }
2378
+
2379
+ variable "stage_auto_deploy" {
2380
+ description = "Whether to automatically deploy the API stage"
2381
+ type = bool
2382
+ default = true
2383
+ }
2384
+
2385
+ # CORS Configuration
2386
+
2387
+ variable "cors_allow_credentials" {
2388
+ description = "Whether to allow credentials in CORS requests"
2389
+ type = bool
2390
+ default = false
2391
+ }
2392
+
2393
+ variable "cors_allow_headers" {
2394
+ description = "List of allowed headers for CORS"
2395
+ type = list(string)
2396
+ default = ["authorization", "content-type", "x-amz-content-sha256", "x-amz-date", "x-amz-security-token"]
2397
+ }
2398
+
2399
+ variable "cors_allow_methods" {
2400
+ description = "List of allowed HTTP methods for CORS"
2401
+ type = list(string)
2402
+ default = ["*"]
2403
+ }
2404
+
2405
+ variable "cors_allow_origins" {
2406
+ description = "List of allowed origins for CORS"
2407
+ type = list(string)
2408
+ default = ["*"]
2409
+ }
2410
+
2411
+ variable "cors_expose_headers" {
2412
+ description = "List of headers to expose in CORS responses"
2413
+ type = list(string)
2414
+ default = []
2415
+ }
2416
+
2417
+ variable "cors_max_age" {
2418
+ description = "Maximum age for CORS preflight requests in seconds"
2419
+ type = number
2420
+ default = 86400
2421
+ }
2422
+
2423
+ # Tags
2424
+
2425
+ variable "tags" {
2426
+ description = "Tags to apply to all resources"
2427
+ type = map(string)
2428
+ default = {}
2429
+ }
2430
+
2431
+ # Data sources
2432
+ data "aws_region" "current" {}
2433
+ data "aws_caller_identity" "current" {}
2434
+
2435
+ # Resources
2436
+
2437
+ # KMS key for CloudWatch log group encryption
2438
+ resource "aws_kms_key" "logs_key" {
2439
+ description = "KMS key for CloudWatch log group encryption"
2440
+ deletion_window_in_days = 7
2441
+ enable_key_rotation = true
2442
+
2443
+ policy = jsonencode({
2444
+ Version = "2012-10-17"
2445
+ Statement = [
2446
+ {
2447
+ Sid = "Enable IAM User Permissions"
2448
+ Effect = "Allow"
2449
+ Principal = {
2450
+ AWS = "arn:aws:iam::\${data.aws_caller_identity.current.account_id}:root"
2451
+ }
2452
+ Action = "kms:*"
2453
+ Resource = "*"
2454
+ },
2455
+ {
2456
+ Sid = "Allow CloudWatch Logs"
2457
+ Effect = "Allow"
2458
+ Principal = {
2459
+ Service = "logs.\${data.aws_region.current.name}.amazonaws.com"
2460
+ }
2461
+ Action = [
2462
+ "kms:Encrypt",
2463
+ "kms:Decrypt",
2464
+ "kms:ReEncrypt*",
2465
+ "kms:GenerateDataKey*",
2466
+ "kms:DescribeKey"
2467
+ ]
2468
+ Resource = "*"
2469
+ Condition = {
2470
+ ArnEquals = {
2471
+ "kms:EncryptionContext:aws:logs:arn" = "arn:aws:logs:\${data.aws_region.current.name}:\${data.aws_caller_identity.current.account_id}:log-group:/aws/apigateway/\${var.api_name}"
2472
+ }
2473
+ }
2474
+ }
2475
+ ]
2476
+ })
2477
+
2478
+ tags = var.tags
2479
+ }
2480
+
2481
+ resource "aws_kms_alias" "logs_key_alias" {
2482
+ name = "alias/\${var.api_name}-api-logs-encryption"
2483
+ target_key_id = aws_kms_key.logs_key.key_id
2484
+ }
2485
+
2486
+ # HTTP API Gateway
2487
+ resource "aws_apigatewayv2_api" "http_api" {
2488
+ name = var.api_name
2489
+ protocol_type = "HTTP"
2490
+ description = var.api_description
2491
+
2492
+ cors_configuration {
2493
+ allow_credentials = var.cors_allow_credentials
2494
+ allow_headers = var.cors_allow_headers
2495
+ allow_methods = var.cors_allow_methods
2496
+ allow_origins = var.cors_allow_origins
2497
+ expose_headers = var.cors_expose_headers
2498
+ max_age = var.cors_max_age
2499
+ }
2500
+
2501
+ tags = var.tags
2502
+ }
2503
+
2504
+ # API Gateway stage
2505
+ resource "aws_apigatewayv2_stage" "api_stage" {
2506
+ api_id = aws_apigatewayv2_api.http_api.id
2507
+ name = var.stage_name
2508
+ auto_deploy = var.stage_auto_deploy
2509
+
2510
+ access_log_settings {
2511
+ destination_arn = aws_cloudwatch_log_group.api_logs.arn
2512
+ format = jsonencode({
2513
+ requestId = "$context.requestId"
2514
+ ip = "$context.identity.sourceIp"
2515
+ requestTime = "$context.requestTime"
2516
+ httpMethod = "$context.httpMethod"
2517
+ routeKey = "$context.routeKey"
2518
+ status = "$context.status"
2519
+ protocol = "$context.protocol"
2520
+ responseLength = "$context.responseLength"
2521
+ error = "$context.error.message"
2522
+ integrationError = "$context.integrationErrorMessage"
2523
+ })
2524
+ }
2525
+
2526
+ default_route_settings {
2527
+ throttling_burst_limit = 5000
2528
+ throttling_rate_limit = 10000
2529
+ }
2530
+
2531
+ tags = var.tags
2532
+
2533
+ depends_on = [aws_cloudwatch_log_group.api_logs]
2534
+ }
2535
+
2536
+ # CloudWatch Log Group for API Gateway
2537
+ resource "aws_cloudwatch_log_group" "api_logs" {
2538
+ #checkov:skip=CKV_AWS_338:Log retention set to forever
2539
+ #checkov:skip=CKV_AWS_66:Log retention set to forever
2540
+ name = "/aws/apigateway/\${var.api_name}"
2541
+ kms_key_id = aws_kms_key.logs_key.arn
2542
+ tags = var.tags
2543
+ }
2544
+
2545
+ # Outputs
2546
+
2547
+ output "api_id" {
2548
+ description = "ID of the HTTP API Gateway"
2549
+ value = aws_apigatewayv2_api.http_api.id
2550
+ }
2551
+
2552
+ output "api_arn" {
2553
+ description = "ARN of the HTTP API Gateway"
2554
+ value = aws_apigatewayv2_api.http_api.arn
2555
+ }
2556
+
2557
+ output "api_endpoint" {
2558
+ description = "Base URL of the HTTP API Gateway"
2559
+ value = aws_apigatewayv2_api.http_api.api_endpoint
2560
+ }
2561
+
2562
+ output "api_execution_arn" {
2563
+ description = "Execution ARN of the HTTP API Gateway"
2564
+ value = aws_apigatewayv2_api.http_api.execution_arn
2565
+ }
2566
+
2567
+ output "stage_id" {
2568
+ description = "ID of the API Gateway stage"
2569
+ value = aws_apigatewayv2_stage.api_stage.id
2570
+ }
2571
+
2572
+ output "stage_arn" {
2573
+ description = "ARN of the API Gateway stage"
2574
+ value = aws_apigatewayv2_stage.api_stage.arn
2575
+ }
2576
+
2577
+ output "stage_execution_arn" {
2578
+ description = "Execution ARN of the API Gateway stage"
2579
+ value = aws_apigatewayv2_stage.api_stage.execution_arn
2580
+ }
2581
+
2582
+ output "stage_invoke_url" {
2583
+ description = "Invoke URL of the API Gateway stage"
2584
+ value = aws_apigatewayv2_stage.api_stage.invoke_url
2585
+ }
2586
+
2587
+ output "api_log_group_name" {
2588
+ description = "Name of the API Gateway CloudWatch log group"
2589
+ value = aws_cloudwatch_log_group.api_logs.name
2590
+ }
2591
+
2592
+ output "api_log_group_arn" {
2593
+ description = "ARN of the API Gateway CloudWatch log group"
2594
+ value = aws_cloudwatch_log_group.api_logs.arn
2595
+ }",
2596
+ "test-api.tf": "terraform {
2597
+ required_version = ">= 1.0"
2598
+
2599
+ required_providers {
2600
+ aws = {
2601
+ source = "hashicorp/aws"
2602
+ version = "~> 6.0"
2603
+ }
2604
+ }
2605
+ }
2606
+
2607
+
2608
+ variable "env" {
2609
+ description = "Environment variables for the Lambda function"
2610
+ type = map(string)
2611
+ default = {}
2612
+ }
2613
+
2614
+ variable "additional_iam_policy_statements" {
2615
+ description = "Additional IAM policy statements for the Lambda function"
2616
+ type = list(object({
2617
+ Effect = string
2618
+ Action = list(string)
2619
+ Resource = list(string)
2620
+ }))
2621
+ default = []
2622
+ }
2623
+
2624
+ # CORS Configuration (passed to core module)
2625
+ variable "cors_allow_credentials" {
2626
+ description = "Whether to allow credentials in CORS requests"
2627
+ type = bool
2628
+ default = false
2629
+ }
2630
+
2631
+ variable "cors_allow_headers" {
2632
+ description = "List of allowed headers for CORS"
2633
+ type = list(string)
2634
+ default = ["authorization", "content-type", "x-amz-content-sha256", "x-amz-date", "x-amz-security-token"]
2635
+ }
2636
+
2637
+ variable "cors_allow_methods" {
2638
+ description = "List of allowed HTTP methods for CORS"
2639
+ type = list(string)
2640
+ default = ["*"]
2641
+ }
2642
+
2643
+ variable "cors_allow_origins" {
2644
+ description = "List of allowed origins for CORS"
2645
+ type = list(string)
2646
+ default = ["*"]
2647
+ }
2648
+
2649
+ variable "cors_expose_headers" {
2650
+ description = "List of headers to expose in CORS responses"
2651
+ type = list(string)
2652
+ default = []
2653
+ }
2654
+
2655
+ variable "cors_max_age" {
2656
+ description = "Maximum age for CORS preflight requests in seconds"
2657
+ type = number
2658
+ default = 0
2659
+ }
2660
+
2661
+ # Tags
2662
+ variable "tags" {
2663
+ description = "Tags to apply to all resources"
2664
+ type = map(string)
2665
+ default = {}
2666
+ }
2667
+
2668
+ # Get current AWS region and account ID
2669
+ data "aws_region" "current" {}
2670
+ data "aws_caller_identity" "current" {}
2671
+
2672
+ # Resources
2673
+
2674
+ # Create Lambda ZIP file from the bundle directory
2675
+ data "archive_file" "lambda_zip" {
2676
+ type = "zip"
2677
+ source_dir = "\${path.module}/../../../../../../../dist/apps/test_api/bundle"
2678
+ output_path = "\${path.module}/../../../../../../../dist/packages/common/terraform/apis/test-api/lambda.zip"
2679
+ }
2680
+
2681
+
2682
+ # Use the core HTTP API module
2683
+ module "http_api" {
2684
+ source = "../../../core/api/http-api"
2685
+
2686
+ api_name = "TestApi"
2687
+ api_description = "TestApi HTTP API"
2688
+ stage_name = "$default"
2689
+ stage_auto_deploy = true
2690
+
2691
+ # CORS Configuration
2692
+ cors_allow_credentials = var.cors_allow_credentials
2693
+ cors_allow_headers = var.cors_allow_headers
2694
+ cors_allow_methods = var.cors_allow_methods
2695
+ cors_allow_origins = var.cors_allow_origins
2696
+ cors_expose_headers = var.cors_expose_headers
2697
+ cors_max_age = var.cors_max_age
2698
+
2699
+ # Tags
2700
+ tags = var.tags
2701
+ }
2702
+
2703
+ # Lambda function
2704
+ # This configures a single "router" lambda to serve all requests
2705
+ resource "aws_lambda_function" "api_lambda" {
2706
+ #checkov:skip=CKV_AWS_117:Lambda function does not need to be in VPC for this use case
2707
+ #checkov:skip=CKV_AWS_116:Dead Letter Queue not required for this simple API use case
2708
+ #checkov:skip=CKV_AWS_272:Code signing not required for this use case
2709
+ #checkov:skip=CKV_AWS_115:Concurrent execution limit not required for this use case
2710
+ #checkov:skip=CKV_AWS_173:Lambda environment variables encrypted by managed key
2711
+ filename = data.archive_file.lambda_zip.output_path
2712
+ function_name = "TestApiHandler"
2713
+ role = aws_iam_role.lambda_execution_role.arn
2714
+ handler = "proj_test_api.main.handler"
2715
+ runtime = "python3.12"
2716
+ timeout = 30
2717
+ memory_size = 128
2718
+
2719
+ source_code_hash = data.archive_file.lambda_zip.output_base64sha256
2720
+
2721
+ # Enable X-Ray tracing
2722
+ tracing_config {
2723
+ mode = "Active"
2724
+ }
2725
+
2726
+ environment {
2727
+ variables = merge({
2728
+ AWS_CONNECTION_REUSE_ENABLED = "1"
2729
+ }, var.env)
2730
+ }
2731
+
2732
+ tags = var.tags
2733
+ }
2734
+
2735
+ # IAM role for Lambda execution
2736
+ resource "aws_iam_role" "lambda_execution_role" {
2737
+ name = "TestApiHandler-execution-role"
2738
+
2739
+ assume_role_policy = jsonencode({
2740
+ Version = "2012-10-17"
2741
+ Statement = [
2742
+ {
2743
+ Action = "sts:AssumeRole"
2744
+ Effect = "Allow"
2745
+ Principal = {
2746
+ Service = "lambda.amazonaws.com"
2747
+ }
2748
+ }
2749
+ ]
2750
+ })
2751
+
2752
+ tags = var.tags
2753
+ }
2754
+
2755
+ # Attach basic execution policy to Lambda role
2756
+ resource "aws_iam_role_policy_attachment" "lambda_basic_execution" {
2757
+ policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
2758
+ role = aws_iam_role.lambda_execution_role.name
2759
+ }
2760
+
2761
+ # Attach X-Ray tracing policy to Lambda role
2762
+ resource "aws_iam_role_policy_attachment" "lambda_xray_execution" {
2763
+ policy_arn = "arn:aws:iam::aws:policy/AWSXRayDaemonWriteAccess"
2764
+ role = aws_iam_role.lambda_execution_role.name
2765
+ }
2766
+
2767
+ # Additional IAM policies for Lambda (if provided)
2768
+ resource "aws_iam_role_policy" "lambda_additional_policies" {
2769
+ count = length(var.additional_iam_policy_statements) > 0 ? 1 : 0
2770
+ name = "TestApiHandler-additional-policies"
2771
+ role = aws_iam_role.lambda_execution_role.id
2772
+
2773
+ policy = jsonencode({
2774
+ Version = "2012-10-17"
2775
+ Statement = var.additional_iam_policy_statements
2776
+ })
2777
+ }
2778
+
2779
+ # CloudWatch Log Group for Lambda
2780
+ resource "aws_cloudwatch_log_group" "lambda_logs" {
2781
+ #checkov:skip=CKV_AWS_158:Using default CloudWatch log encryption
2782
+ #checkov:skip=CKV_AWS_338:Log retention set to forever
2783
+ #checkov:skip=CKV_AWS_66:Log retention set to forever
2784
+ name = "/aws/lambda/TestApiHandler"
2785
+ tags = var.tags
2786
+ }
2787
+
2788
+
2789
+ # Lambda integration for HTTP API
2790
+ resource "aws_apigatewayv2_integration" "lambda_integration" {
2791
+ api_id = module.http_api.api_id
2792
+ integration_type = "AWS_PROXY"
2793
+ integration_uri = aws_lambda_function.api_lambda.invoke_arn
2794
+
2795
+ payload_format_version = "2.0"
2796
+ timeout_milliseconds = 30000
2797
+
2798
+ depends_on = [aws_lambda_function.api_lambda]
2799
+ }
2800
+
2801
+ # Route for proxy integration (catches all requests)
2802
+ resource "aws_apigatewayv2_route" "proxy_routes" {
2803
+ # NB: OPTIONS is omitted here since API Gateway manages responding to preflight requests
2804
+ # when cors settings are configured
2805
+ for_each = toset(["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD"])
2806
+
2807
+ api_id = module.http_api.api_id
2808
+ route_key = "\${each.key} /{proxy+}"
2809
+ target = "integrations/\${aws_apigatewayv2_integration.lambda_integration.id}"
2810
+
2811
+ # Note: you may wish to suppress the checkov rule CKV_AWS_309 if you are absolutely sure you
2812
+ # need a public API without authentication
2813
+ authorization_type = "NONE"
2814
+
2815
+ depends_on = [aws_apigatewayv2_integration.lambda_integration]
2816
+ }
2817
+
2818
+ # Lambda permission for API Gateway to invoke the function
2819
+ resource "aws_lambda_permission" "api_gateway_invoke" {
2820
+ statement_id = "AllowExecutionFromAPIGateway"
2821
+ action = "lambda:InvokeFunction"
2822
+ function_name = aws_lambda_function.api_lambda.function_name
2823
+ principal = "apigateway.amazonaws.com"
2824
+ source_arn = "\${module.http_api.api_execution_arn}/*/*"
2825
+
2826
+ depends_on = [module.http_api, aws_lambda_function.api_lambda]
2827
+ }
2828
+
2829
+ # Outputs
2830
+
2831
+ # API Gateway Outputs (from core module)
2832
+ output "api_id" {
2833
+ description = "ID of the HTTP API Gateway"
2834
+ value = module.http_api.api_id
2835
+ }
2836
+
2837
+ output "api_arn" {
2838
+ description = "ARN of the HTTP API Gateway"
2839
+ value = module.http_api.api_arn
2840
+ }
2841
+
2842
+ output "api_endpoint" {
2843
+ description = "Base URL of the HTTP API Gateway"
2844
+ value = module.http_api.api_endpoint
2845
+ }
2846
+
2847
+ output "api_execution_arn" {
2848
+ description = "Execution ARN of the HTTP API Gateway"
2849
+ value = module.http_api.api_execution_arn
2850
+ }
2851
+
2852
+ output "stage_invoke_url" {
2853
+ description = "Invoke URL of the API Gateway stage"
2854
+ value = module.http_api.stage_invoke_url
2855
+ }
2856
+
2857
+ output "stage_arn" {
2858
+ description = "ARN of the API Gateway stage"
2859
+ value = module.http_api.stage_arn
2860
+ }
2861
+
2862
+ output "stage_execution_arn" {
2863
+ description = "Execution ARN of the API Gateway stage"
2864
+ value = module.http_api.stage_execution_arn
2865
+ }
2866
+
2867
+ # Lambda Function Outputs
2868
+ output "lambda_function_name" {
2869
+ description = "Name of the Lambda function"
2870
+ value = aws_lambda_function.api_lambda.function_name
2871
+ }
2872
+
2873
+ output "lambda_function_arn" {
2874
+ description = "ARN of the Lambda function"
2875
+ value = aws_lambda_function.api_lambda.arn
2876
+ }
2877
+
2878
+ output "lambda_invoke_arn" {
2879
+ description = "Invoke ARN of the Lambda function"
2880
+ value = aws_lambda_function.api_lambda.invoke_arn
2881
+ }
2882
+
2883
+ output "lambda_qualified_arn" {
2884
+ description = "Qualified ARN of the Lambda function"
2885
+ value = aws_lambda_function.api_lambda.qualified_arn
2886
+ }
2887
+
2888
+ output "lambda_version" {
2889
+ description = "Version of the Lambda function"
2890
+ value = aws_lambda_function.api_lambda.version
2891
+ }
2892
+
2893
+ output "lambda_source_code_hash" {
2894
+ description = "Base64-encoded SHA256 hash of the Lambda deployment package"
2895
+ value = aws_lambda_function.api_lambda.source_code_hash
2896
+ }
2897
+
2898
+ output "lambda_source_code_size" {
2899
+ description = "Size of the Lambda deployment package in bytes"
2900
+ value = aws_lambda_function.api_lambda.source_code_size
2901
+ }
2902
+
2903
+ # IAM Role Outputs
2904
+ output "lambda_execution_role_arn" {
2905
+ description = "ARN of the Lambda execution role"
2906
+ value = aws_iam_role.lambda_execution_role.arn
2907
+ }
2908
+
2909
+ output "lambda_execution_role_name" {
2910
+ description = "Name of the Lambda execution role"
2911
+ value = aws_iam_role.lambda_execution_role.name
2912
+ }
2913
+
2914
+ # Integration Outputs
2915
+ output "integration_id" {
2916
+ description = "ID of the Lambda integration"
2917
+ value = aws_apigatewayv2_integration.lambda_integration.id
2918
+ }
2919
+
2920
+ # CloudWatch Log Groups
2921
+ output "lambda_log_group_name" {
2922
+ description = "Name of the Lambda CloudWatch log group"
2923
+ value = aws_cloudwatch_log_group.lambda_logs.name
2924
+ }
2925
+
2926
+ output "lambda_log_group_arn" {
2927
+ description = "ARN of the Lambda CloudWatch log group"
2928
+ value = aws_cloudwatch_log_group.lambda_logs.arn
2929
+ }
2930
+
2931
+ output "api_log_group_name" {
2932
+ description = "Name of the API Gateway CloudWatch log group"
2933
+ value = module.http_api.api_log_group_name
2934
+ }
2935
+
2936
+ output "api_log_group_arn" {
2937
+ description = "ARN of the API Gateway CloudWatch log group"
2938
+ value = module.http_api.api_log_group_arn
2939
+ }",
2940
+ }
2941
+ `;
2942
+
2943
+ exports[`fastapi project generator > terraform iacProvider > should generate terraform files for REST API with Cognito auth and snapshot them > terraform-rest-cognito-files 1`] = `
2944
+ {
2945
+ "rest-api.tf": "# Core REST API Gateway module
2946
+ # This module creates the API Gateway REST API, deployment, stage, and logging resources
2947
+
2948
+ terraform {
2949
+ required_version = ">= 1.0"
2950
+
2951
+ required_providers {
2952
+ aws = {
2953
+ source = "hashicorp/aws"
2954
+ version = "~> 6.0"
2955
+ }
2956
+ }
2957
+ }
2958
+
2959
+ # Core REST API Gateway Variables
2960
+
2961
+ variable "api_name" {
2962
+ description = "Name of the REST API Gateway"
2963
+ type = string
2964
+ }
2965
+
2966
+ variable "api_description" {
2967
+ description = "Description of the REST API Gateway"
2968
+ type = string
2969
+ default = "REST API Gateway"
2970
+ }
2971
+
2972
+ variable "stage_name" {
2973
+ description = "Name of the API Gateway stage"
2974
+ type = string
2975
+ default = "prod"
2976
+ }
2977
+
2978
+ variable "stage_auto_deploy" {
2979
+ description = "Whether to automatically deploy the API stage"
2980
+ type = bool
2981
+ default = true
2982
+ }
2983
+
2984
+ # CORS Configuration
2985
+
2986
+ variable "cors_allow_headers" {
2987
+ description = "List of allowed headers for CORS"
2988
+ type = list(string)
2989
+ default = ["authorization", "content-type", "x-amz-content-sha256", "x-amz-date", "x-amz-security-token"]
2990
+ }
2991
+
2992
+ variable "cors_allow_methods" {
2993
+ description = "List of allowed HTTP methods for CORS"
2994
+ type = list(string)
2995
+ default = ["*"]
2996
+ }
2997
+
2998
+ variable "cors_allow_origins" {
2999
+ description = "List of allowed origins for CORS"
3000
+ type = list(string)
3001
+ default = ["*"]
3002
+ }
3003
+
3004
+ # Tags
3005
+
3006
+ variable "tags" {
3007
+ description = "Tags to apply to all resources"
3008
+ type = map(string)
3009
+ default = {}
3010
+ }
3011
+
3012
+ # Data sources
3013
+ data "aws_region" "current" {}
3014
+ data "aws_caller_identity" "current" {}
3015
+
3016
+ # Resources
3017
+
3018
+ # Note: CloudWatch logging removed due to account-level CloudWatch Logs role ARN requirement
3019
+
3020
+ # REST API Gateway
3021
+ resource "aws_api_gateway_rest_api" "rest_api" {
3022
+ name = var.api_name
3023
+ description = var.api_description
3024
+
3025
+ endpoint_configuration {
3026
+ types = ["REGIONAL"]
3027
+ }
3028
+
3029
+ lifecycle {
3030
+ create_before_destroy = true
3031
+ }
3032
+
3033
+ tags = var.tags
3034
+ }
3035
+
3036
+ # Note: Deployment and stage are created in the consuming module (e.g., foo-api.tf)
3037
+ # after all methods and integrations are defined
3038
+
3039
+ # Note: CloudWatch Log Group removed due to account-level CloudWatch Logs role ARN requirement
3040
+
3041
+ # Gateway Response for CORS (4XX errors)
3042
+ resource "aws_api_gateway_gateway_response" "cors_4xx" {
3043
+ rest_api_id = aws_api_gateway_rest_api.rest_api.id
3044
+ response_type = "DEFAULT_4XX"
3045
+
3046
+ response_parameters = {
3047
+ "gatewayresponse.header.Access-Control-Allow-Origin" = "'\${join(",", var.cors_allow_origins)}'"
3048
+ "gatewayresponse.header.Access-Control-Allow-Headers" = "'\${join(",", var.cors_allow_headers)}'"
3049
+ "gatewayresponse.header.Access-Control-Allow-Methods" = "'\${join(",", var.cors_allow_methods)}'"
3050
+ }
3051
+ }
3052
+
3053
+ # Gateway Response for CORS (5XX errors)
3054
+ resource "aws_api_gateway_gateway_response" "cors_5xx" {
3055
+ rest_api_id = aws_api_gateway_rest_api.rest_api.id
3056
+ response_type = "DEFAULT_5XX"
3057
+
3058
+ response_parameters = {
3059
+ "gatewayresponse.header.Access-Control-Allow-Origin" = "'\${join(",", var.cors_allow_origins)}'"
3060
+ "gatewayresponse.header.Access-Control-Allow-Headers" = "'\${join(",", var.cors_allow_headers)}'"
3061
+ "gatewayresponse.header.Access-Control-Allow-Methods" = "'\${join(",", var.cors_allow_methods)}'"
3062
+ }
3063
+ }
3064
+
3065
+ # Outputs
3066
+
3067
+ output "api_id" {
3068
+ description = "ID of the REST API Gateway"
3069
+ value = aws_api_gateway_rest_api.rest_api.id
3070
+ }
3071
+
3072
+ output "api_arn" {
3073
+ description = "ARN of the REST API Gateway"
3074
+ value = aws_api_gateway_rest_api.rest_api.arn
3075
+ }
3076
+
3077
+ output "api_endpoint" {
3078
+ description = "Base URL of the REST API Gateway"
3079
+ value = "https://\${aws_api_gateway_rest_api.rest_api.id}.execute-api.\${data.aws_region.current.id}.amazonaws.com"
3080
+ }
3081
+
3082
+ output "api_execution_arn" {
3083
+ description = "Execution ARN of the REST API Gateway"
3084
+ value = aws_api_gateway_rest_api.rest_api.execution_arn
3085
+ }
3086
+
3087
+ output "api_root_resource_id" {
3088
+ description = "Root resource ID of the REST API Gateway"
3089
+ value = aws_api_gateway_rest_api.rest_api.root_resource_id
3090
+ }
3091
+
3092
+ # Note: Stage and deployment outputs are provided by the consuming module
3093
+
3094
+ # Note: CloudWatch log group outputs removed due to account-level CloudWatch Logs role ARN requirement",
3095
+ "test-api.tf": "terraform {
3096
+ required_version = ">= 1.0"
3097
+
3098
+ required_providers {
3099
+ aws = {
3100
+ source = "hashicorp/aws"
3101
+ version = "~> 6.0"
3102
+ }
3103
+ }
3104
+ }
3105
+
3106
+ # Authentication Configuration
3107
+ variable "user_pool_id" {
3108
+ description = "Cognito User Pool ID for authentication"
3109
+ type = string
3110
+ }
3111
+
3112
+ variable "user_pool_client_ids" {
3113
+ description = "List of Cognito User Pool Client IDs"
3114
+ type = list(string)
3115
+ }
3116
+
3117
+ variable "env" {
3118
+ description = "Environment variables for the Lambda function"
3119
+ type = map(string)
3120
+ default = {}
3121
+ }
3122
+
3123
+ variable "additional_iam_policy_statements" {
3124
+ description = "Additional IAM policy statements for the Lambda function"
3125
+ type = list(object({
3126
+ Effect = string
3127
+ Action = list(string)
3128
+ Resource = list(string)
3129
+ }))
3130
+ default = []
3131
+ }
3132
+
3133
+ # CORS Configuration (passed to core module)
3134
+
3135
+ variable "cors_allow_headers" {
3136
+ description = "List of allowed headers for CORS"
3137
+ type = list(string)
3138
+ default = ["authorization", "content-type", "x-amz-content-sha256", "x-amz-date", "x-amz-security-token"]
3139
+ }
3140
+
3141
+ variable "cors_allow_methods" {
3142
+ description = "List of allowed HTTP methods for CORS"
3143
+ type = list(string)
3144
+ default = ["*"]
3145
+ }
3146
+
3147
+ variable "cors_allow_origins" {
3148
+ description = "List of allowed origins for CORS"
3149
+ type = list(string)
3150
+ default = ["*"]
3151
+ }
3152
+
3153
+ # Tags
3154
+ variable "tags" {
3155
+ description = "Tags to apply to all resources"
3156
+ type = map(string)
3157
+ default = {}
3158
+ }
3159
+
3160
+ # Get current AWS region and account ID
3161
+ data "aws_region" "current" {}
3162
+ data "aws_caller_identity" "current" {}
3163
+
3164
+ # Resources
3165
+
3166
+ # Create Lambda ZIP file from the FastAPI bundle directory
3167
+ data "archive_file" "lambda_zip" {
3168
+ type = "zip"
3169
+ source_dir = "\${path.module}/../../../../../../../dist/apps/test_api/bundle"
3170
+ output_path = "\${path.module}/../../../../../../../dist/packages/common/terraform/apis/test-api/lambda.zip"
3171
+ }
3172
+
3173
+ # Use the core REST API module
3174
+ module "rest_api" {
3175
+ source = "../../../core/api/rest-api"
3176
+
3177
+ api_name = "TestApi"
3178
+ api_description = "TestApi REST API"
3179
+ stage_name = "prod"
3180
+ stage_auto_deploy = true
3181
+
3182
+ # CORS Configuration
3183
+ cors_allow_headers = var.cors_allow_headers
3184
+ cors_allow_methods = var.cors_allow_methods
3185
+ cors_allow_origins = var.cors_allow_origins
3186
+
3187
+ # Tags
3188
+ tags = var.tags
3189
+ }
3190
+
3191
+ # Lambda function
3192
+ resource "aws_lambda_function" "api_lambda" {
3193
+ #checkov:skip=CKV_AWS_117:Lambda function does not need to be in VPC for this use case
3194
+ #checkov:skip=CKV_AWS_116:Dead Letter Queue not required for this simple API use case
3195
+ #checkov:skip=CKV_AWS_272:Code signing not required for this use case
3196
+ #checkov:skip=CKV_AWS_115:Concurrent execution limit not required for this use case
3197
+ #checkov:skip=CKV_AWS_173:Lambda environment variables encrypted by managed key
3198
+ filename = data.archive_file.lambda_zip.output_path
3199
+ function_name = "TestApiHandler"
3200
+ role = aws_iam_role.lambda_execution_role.arn
3201
+ handler = "proj_test_api.main.handler"
3202
+ runtime = "python3.12"
3203
+ timeout = 30
3204
+ memory_size = 128
3205
+
3206
+ source_code_hash = data.archive_file.lambda_zip.output_base64sha256
3207
+
3208
+ # Enable X-Ray tracing
3209
+ tracing_config {
3210
+ mode = "Active"
3211
+ }
3212
+
3213
+ environment {
3214
+ variables = merge({
3215
+ AWS_CONNECTION_REUSE_ENABLED = "1"
3216
+ }, var.env)
3217
+ }
3218
+
3219
+ tags = var.tags
3220
+ }
3221
+
3222
+ # IAM role for Lambda execution
3223
+ resource "aws_iam_role" "lambda_execution_role" {
3224
+ name = "TestApiHandler-execution-role"
3225
+
3226
+ assume_role_policy = jsonencode({
3227
+ Version = "2012-10-17"
3228
+ Statement = [
3229
+ {
3230
+ Action = "sts:AssumeRole"
3231
+ Effect = "Allow"
3232
+ Principal = {
3233
+ Service = "lambda.amazonaws.com"
3234
+ }
3235
+ }
3236
+ ]
3237
+ })
3238
+
3239
+ tags = var.tags
3240
+ }
3241
+
3242
+ # Attach basic execution policy to Lambda role
3243
+ resource "aws_iam_role_policy_attachment" "lambda_basic_execution" {
3244
+ policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
3245
+ role = aws_iam_role.lambda_execution_role.name
3246
+ }
3247
+
3248
+ # Attach X-Ray tracing policy to Lambda role
3249
+ resource "aws_iam_role_policy_attachment" "lambda_xray_execution" {
3250
+ policy_arn = "arn:aws:iam::aws:policy/AWSXRayDaemonWriteAccess"
3251
+ role = aws_iam_role.lambda_execution_role.name
3252
+ }
3253
+
3254
+ # Additional IAM policies for Lambda (if provided)
3255
+ resource "aws_iam_role_policy" "lambda_additional_policies" {
3256
+ count = length(var.additional_iam_policy_statements) > 0 ? 1 : 0
3257
+ name = "TestApiHandler-additional-policies"
3258
+ role = aws_iam_role.lambda_execution_role.id
3259
+
3260
+ policy = jsonencode({
3261
+ Version = "2012-10-17"
3262
+ Statement = var.additional_iam_policy_statements
3263
+ })
3264
+ }
3265
+
3266
+ # CloudWatch Log Group for Lambda
3267
+ resource "aws_cloudwatch_log_group" "lambda_logs" {
3268
+ #checkov:skip=CKV_AWS_158:Using default CloudWatch log encryption
3269
+ #checkov:skip=CKV_AWS_338:Log retention set to forever
3270
+ #checkov:skip=CKV_AWS_66:Log retention set to forever
3271
+ name = "/aws/lambda/TestApiHandler"
3272
+ tags = var.tags
3273
+ }
3274
+
3275
+ # Cognito User Pool Authorizer
3276
+ resource "aws_api_gateway_authorizer" "cognito_authorizer" {
3277
+ name = "TestApiAuthorizer"
3278
+ rest_api_id = module.rest_api.api_id
3279
+ type = "COGNITO_USER_POOLS"
3280
+ provider_arns = ["arn:aws:cognito-idp:\${data.aws_region.current.name}:\${data.aws_caller_identity.current.account_id}:userpool/\${var.user_pool_id}"]
3281
+ identity_source = "method.request.header.Authorization"
3282
+ }
3283
+
3284
+ # Create proxy resource (captures all paths)
3285
+ resource "aws_api_gateway_resource" "proxy_resource" {
3286
+ rest_api_id = module.rest_api.api_id
3287
+ parent_id = module.rest_api.api_root_resource_id
3288
+ path_part = "{proxy+}"
3289
+ }
3290
+
3291
+ # Lambda integration for REST API
3292
+ resource "aws_api_gateway_integration" "lambda_integration" {
3293
+ rest_api_id = module.rest_api.api_id
3294
+ resource_id = aws_api_gateway_resource.proxy_resource.id
3295
+ http_method = aws_api_gateway_method.proxy_method.http_method
3296
+
3297
+ integration_http_method = "POST"
3298
+ type = "AWS_PROXY"
3299
+ uri = aws_lambda_function.api_lambda.invoke_arn
3300
+
3301
+ depends_on = [aws_lambda_function.api_lambda]
3302
+ }
3303
+
3304
+ # Method for proxy integration
3305
+ resource "aws_api_gateway_method" "proxy_method" {
3306
+ #checkov:skip=CKV2_AWS_53:Request validation not required for proxy integration as Lambda handles validation
3307
+ rest_api_id = module.rest_api.api_id
3308
+ resource_id = aws_api_gateway_resource.proxy_resource.id
3309
+ http_method = "ANY"
3310
+
3311
+ authorization = "COGNITO_USER_POOLS"
3312
+ authorizer_id = aws_api_gateway_authorizer.cognito_authorizer.id
3313
+
3314
+ request_parameters = {
3315
+ "method.request.path.proxy" = true
3316
+ }
3317
+
3318
+ depends_on = [aws_api_gateway_authorizer.cognito_authorizer]
3319
+ }
3320
+
3321
+ # OPTIONS method for CORS preflight
3322
+ resource "aws_api_gateway_method" "options_method" {
3323
+ #checkov:skip=CKV2_AWS_70:OPTIONS method must be unauthenticated for CORS preflight requests
3324
+ #checkov:skip=CKV2_AWS_53:Request validation not required for OPTIONS CORS preflight method
3325
+ rest_api_id = module.rest_api.api_id
3326
+ resource_id = aws_api_gateway_resource.proxy_resource.id
3327
+ http_method = "OPTIONS"
3328
+ authorization = "NONE"
3329
+ }
3330
+
3331
+ # CORS integration for OPTIONS method
3332
+ resource "aws_api_gateway_integration" "options_integration" {
3333
+ rest_api_id = module.rest_api.api_id
3334
+ resource_id = aws_api_gateway_resource.proxy_resource.id
3335
+ http_method = aws_api_gateway_method.options_method.http_method
3336
+
3337
+ type = "MOCK"
3338
+ request_templates = {
3339
+ "application/json" = "{\\"statusCode\\": 204}"
3340
+ }
3341
+ }
3342
+
3343
+ # OPTIONS method response
3344
+ resource "aws_api_gateway_method_response" "options_response" {
3345
+ rest_api_id = module.rest_api.api_id
3346
+ resource_id = aws_api_gateway_resource.proxy_resource.id
3347
+ http_method = aws_api_gateway_method.options_method.http_method
3348
+ status_code = "204"
3349
+
3350
+ response_parameters = {
3351
+ "method.response.header.Access-Control-Allow-Headers" = true
3352
+ "method.response.header.Access-Control-Allow-Methods" = true
3353
+ "method.response.header.Access-Control-Allow-Origin" = true
3354
+ }
3355
+ }
3356
+
3357
+ # OPTIONS integration response
3358
+ resource "aws_api_gateway_integration_response" "options_integration_response" {
3359
+ rest_api_id = module.rest_api.api_id
3360
+ resource_id = aws_api_gateway_resource.proxy_resource.id
3361
+ http_method = aws_api_gateway_method.options_method.http_method
3362
+ status_code = aws_api_gateway_method_response.options_response.status_code
3363
+
3364
+ response_parameters = {
3365
+ "method.response.header.Access-Control-Allow-Headers" = "'\${join(",", var.cors_allow_headers)}'"
3366
+ "method.response.header.Access-Control-Allow-Methods" = "'\${join(",", var.cors_allow_methods)}'"
3367
+ "method.response.header.Access-Control-Allow-Origin" = "'\${join(",", var.cors_allow_origins)}'"
3368
+ }
3369
+ }
3370
+
3371
+ # API Gateway deployment
3372
+ resource "aws_api_gateway_deployment" "api_deployment" {
3373
+ rest_api_id = module.rest_api.api_id
3374
+
3375
+ triggers = {
3376
+ redeployment = sha1(jsonencode([
3377
+ aws_api_gateway_resource.proxy_resource.id,
3378
+ aws_api_gateway_method.proxy_method.id,
3379
+ aws_api_gateway_integration.lambda_integration.id,
3380
+ aws_api_gateway_method.options_method.id,
3381
+ aws_api_gateway_integration.options_integration.id,
3382
+ ]))
3383
+ }
3384
+
3385
+ lifecycle {
3386
+ create_before_destroy = true
3387
+ }
3388
+
3389
+ depends_on = [
3390
+ aws_api_gateway_method.proxy_method,
3391
+ aws_api_gateway_integration.lambda_integration,
3392
+ aws_api_gateway_method.options_method,
3393
+ aws_api_gateway_integration.options_integration,
3394
+ aws_api_gateway_method_response.options_response,
3395
+ aws_api_gateway_integration_response.options_integration_response,
3396
+ ]
3397
+ }
3398
+
3399
+ # API Gateway stage
3400
+ resource "aws_api_gateway_stage" "api_stage" {
3401
+ #checkov:skip=CKV_AWS_120:API Gateway caching not required for this use case
3402
+ #checkov:skip=CKV_AWS_76:API Gateway access logging disabled due to account-level CloudWatch Logs role ARN requirement
3403
+ #checkov:skip=CKV2_AWS_4:API Gateway logging level not applicable as access logging is disabled
3404
+ #checkov:skip=CKV2_AWS_51:Client certificate authentication not required for this use case
3405
+ deployment_id = aws_api_gateway_deployment.api_deployment.id
3406
+ rest_api_id = module.rest_api.api_id
3407
+ stage_name = "prod"
3408
+ xray_tracing_enabled = true
3409
+
3410
+ tags = var.tags
3411
+
3412
+ depends_on = [aws_api_gateway_deployment.api_deployment]
3413
+ }
3414
+
3415
+ # API Gateway Resource Policy
3416
+ resource "aws_api_gateway_rest_api_policy" "api_policy" {
3417
+ rest_api_id = module.rest_api.api_id
3418
+
3419
+ policy = jsonencode({
3420
+ Version = "2012-10-17"
3421
+ Statement = [
3422
+ {
3423
+ # Allow all callers to invoke the API in the resource policy, since auth is handled by Cognito
3424
+ Effect = "Allow"
3425
+ Principal = "*"
3426
+ Action = "execute-api:Invoke"
3427
+ Resource = "execute-api:/*"
3428
+ }
3429
+ ]
3430
+ })
3431
+ }
3432
+
3433
+ # Lambda permission for API Gateway to invoke the function
3434
+ resource "aws_lambda_permission" "api_gateway_invoke" {
3435
+ statement_id = "AllowExecutionFromAPIGateway"
3436
+ action = "lambda:InvokeFunction"
3437
+ function_name = aws_lambda_function.api_lambda.function_name
3438
+ principal = "apigateway.amazonaws.com"
3439
+ source_arn = "\${module.rest_api.api_execution_arn}/*/*"
3440
+
3441
+ depends_on = [module.rest_api, aws_lambda_function.api_lambda]
3442
+ }
3443
+
3444
+ # Outputs
3445
+
3446
+ # API Gateway Outputs (from core module)
3447
+ output "api_id" {
3448
+ description = "ID of the REST API Gateway"
3449
+ value = module.rest_api.api_id
3450
+ }
3451
+
3452
+ output "api_arn" {
3453
+ description = "ARN of the REST API Gateway"
3454
+ value = module.rest_api.api_arn
3455
+ }
3456
+
3457
+ output "api_endpoint" {
3458
+ description = "Base URL of the REST API Gateway"
3459
+ value = module.rest_api.api_endpoint
3460
+ }
3461
+
3462
+ output "api_execution_arn" {
3463
+ description = "Execution ARN of the REST API Gateway"
3464
+ value = module.rest_api.api_execution_arn
3465
+ }
3466
+
3467
+ output "stage_invoke_url" {
3468
+ description = "Invoke URL of the API Gateway stage"
3469
+ value = aws_api_gateway_stage.api_stage.invoke_url
3470
+ }
3471
+
3472
+ output "stage_arn" {
3473
+ description = "ARN of the API Gateway stage"
3474
+ value = aws_api_gateway_stage.api_stage.arn
3475
+ }
3476
+
3477
+ output "stage_execution_arn" {
3478
+ description = "Execution ARN of the API Gateway stage"
3479
+ value = aws_api_gateway_stage.api_stage.execution_arn
3480
+ }
3481
+
3482
+ output "deployment_id" {
3483
+ description = "ID of the API Gateway deployment"
3484
+ value = aws_api_gateway_deployment.api_deployment.id
3485
+ }
3486
+
3487
+ output "stage_id" {
3488
+ description = "ID of the API Gateway stage"
3489
+ value = aws_api_gateway_stage.api_stage.id
3490
+ }
3491
+
3492
+ # Lambda Function Outputs
3493
+ output "lambda_function_name" {
3494
+ description = "Name of the Lambda function"
3495
+ value = aws_lambda_function.api_lambda.function_name
3496
+ }
3497
+
3498
+ output "lambda_function_arn" {
3499
+ description = "ARN of the Lambda function"
3500
+ value = aws_lambda_function.api_lambda.arn
3501
+ }
3502
+
3503
+ output "lambda_invoke_arn" {
3504
+ description = "Invoke ARN of the Lambda function"
3505
+ value = aws_lambda_function.api_lambda.invoke_arn
3506
+ }
3507
+
3508
+ output "lambda_qualified_arn" {
3509
+ description = "Qualified ARN of the Lambda function"
3510
+ value = aws_lambda_function.api_lambda.qualified_arn
3511
+ }
3512
+
3513
+ output "lambda_version" {
3514
+ description = "Version of the Lambda function"
3515
+ value = aws_lambda_function.api_lambda.version
3516
+ }
3517
+
3518
+ output "lambda_source_code_hash" {
3519
+ description = "Base64-encoded SHA256 hash of the Lambda deployment package"
3520
+ value = aws_lambda_function.api_lambda.source_code_hash
3521
+ }
3522
+
3523
+ output "lambda_source_code_size" {
3524
+ description = "Size of the Lambda deployment package in bytes"
3525
+ value = aws_lambda_function.api_lambda.source_code_size
3526
+ }
3527
+
3528
+ # IAM Role Outputs
3529
+ output "lambda_execution_role_arn" {
3530
+ description = "ARN of the Lambda execution role"
3531
+ value = aws_iam_role.lambda_execution_role.arn
3532
+ }
3533
+
3534
+ output "lambda_execution_role_name" {
3535
+ description = "Name of the Lambda execution role"
3536
+ value = aws_iam_role.lambda_execution_role.name
3537
+ }
3538
+
3539
+ # Integration Outputs
3540
+ output "integration_id" {
3541
+ description = "ID of the Lambda integration"
3542
+ value = aws_api_gateway_integration.lambda_integration.id
3543
+ }
3544
+
3545
+ output "proxy_resource_id" {
3546
+ description = "ID of the proxy resource"
3547
+ value = aws_api_gateway_resource.proxy_resource.id
3548
+ }
3549
+
3550
+ output "proxy_method_id" {
3551
+ description = "ID of the proxy method"
3552
+ value = aws_api_gateway_method.proxy_method.id
3553
+ }
3554
+
3555
+ # CloudWatch Log Groups
3556
+ output "lambda_log_group_name" {
3557
+ description = "Name of the Lambda CloudWatch log group"
3558
+ value = aws_cloudwatch_log_group.lambda_logs.name
3559
+ }
3560
+
3561
+ output "lambda_log_group_arn" {
3562
+ description = "ARN of the Lambda CloudWatch log group"
3563
+ value = aws_cloudwatch_log_group.lambda_logs.arn
3564
+ }
3565
+ ",
3566
+ }
3567
+ `;
3568
+
3569
+ exports[`fastapi project generator > terraform iacProvider > should generate terraform files for REST API with IAM auth and snapshot them > terraform-rest-iam-files 1`] = `
3570
+ {
3571
+ "rest-api.tf": "# Core REST API Gateway module
3572
+ # This module creates the API Gateway REST API, deployment, stage, and logging resources
3573
+
3574
+ terraform {
3575
+ required_version = ">= 1.0"
3576
+
3577
+ required_providers {
3578
+ aws = {
3579
+ source = "hashicorp/aws"
3580
+ version = "~> 6.0"
3581
+ }
3582
+ }
3583
+ }
3584
+
3585
+ # Core REST API Gateway Variables
3586
+
3587
+ variable "api_name" {
3588
+ description = "Name of the REST API Gateway"
3589
+ type = string
3590
+ }
3591
+
3592
+ variable "api_description" {
3593
+ description = "Description of the REST API Gateway"
3594
+ type = string
3595
+ default = "REST API Gateway"
3596
+ }
3597
+
3598
+ variable "stage_name" {
3599
+ description = "Name of the API Gateway stage"
3600
+ type = string
3601
+ default = "prod"
3602
+ }
3603
+
3604
+ variable "stage_auto_deploy" {
3605
+ description = "Whether to automatically deploy the API stage"
3606
+ type = bool
3607
+ default = true
3608
+ }
3609
+
3610
+ # CORS Configuration
3611
+
3612
+ variable "cors_allow_headers" {
3613
+ description = "List of allowed headers for CORS"
3614
+ type = list(string)
3615
+ default = ["authorization", "content-type", "x-amz-content-sha256", "x-amz-date", "x-amz-security-token"]
3616
+ }
3617
+
3618
+ variable "cors_allow_methods" {
3619
+ description = "List of allowed HTTP methods for CORS"
3620
+ type = list(string)
3621
+ default = ["*"]
3622
+ }
3623
+
3624
+ variable "cors_allow_origins" {
3625
+ description = "List of allowed origins for CORS"
3626
+ type = list(string)
3627
+ default = ["*"]
3628
+ }
3629
+
3630
+ # Tags
3631
+
3632
+ variable "tags" {
3633
+ description = "Tags to apply to all resources"
3634
+ type = map(string)
3635
+ default = {}
3636
+ }
3637
+
3638
+ # Data sources
3639
+ data "aws_region" "current" {}
3640
+ data "aws_caller_identity" "current" {}
3641
+
3642
+ # Resources
3643
+
3644
+ # Note: CloudWatch logging removed due to account-level CloudWatch Logs role ARN requirement
3645
+
3646
+ # REST API Gateway
3647
+ resource "aws_api_gateway_rest_api" "rest_api" {
3648
+ name = var.api_name
3649
+ description = var.api_description
3650
+
3651
+ endpoint_configuration {
3652
+ types = ["REGIONAL"]
3653
+ }
3654
+
3655
+ lifecycle {
3656
+ create_before_destroy = true
3657
+ }
3658
+
3659
+ tags = var.tags
3660
+ }
3661
+
3662
+ # Note: Deployment and stage are created in the consuming module (e.g., foo-api.tf)
3663
+ # after all methods and integrations are defined
3664
+
3665
+ # Note: CloudWatch Log Group removed due to account-level CloudWatch Logs role ARN requirement
3666
+
3667
+ # Gateway Response for CORS (4XX errors)
3668
+ resource "aws_api_gateway_gateway_response" "cors_4xx" {
3669
+ rest_api_id = aws_api_gateway_rest_api.rest_api.id
3670
+ response_type = "DEFAULT_4XX"
3671
+
3672
+ response_parameters = {
3673
+ "gatewayresponse.header.Access-Control-Allow-Origin" = "'\${join(",", var.cors_allow_origins)}'"
3674
+ "gatewayresponse.header.Access-Control-Allow-Headers" = "'\${join(",", var.cors_allow_headers)}'"
3675
+ "gatewayresponse.header.Access-Control-Allow-Methods" = "'\${join(",", var.cors_allow_methods)}'"
3676
+ }
3677
+ }
3678
+
3679
+ # Gateway Response for CORS (5XX errors)
3680
+ resource "aws_api_gateway_gateway_response" "cors_5xx" {
3681
+ rest_api_id = aws_api_gateway_rest_api.rest_api.id
3682
+ response_type = "DEFAULT_5XX"
3683
+
3684
+ response_parameters = {
3685
+ "gatewayresponse.header.Access-Control-Allow-Origin" = "'\${join(",", var.cors_allow_origins)}'"
3686
+ "gatewayresponse.header.Access-Control-Allow-Headers" = "'\${join(",", var.cors_allow_headers)}'"
3687
+ "gatewayresponse.header.Access-Control-Allow-Methods" = "'\${join(",", var.cors_allow_methods)}'"
3688
+ }
3689
+ }
3690
+
3691
+ # Outputs
3692
+
3693
+ output "api_id" {
3694
+ description = "ID of the REST API Gateway"
3695
+ value = aws_api_gateway_rest_api.rest_api.id
3696
+ }
3697
+
3698
+ output "api_arn" {
3699
+ description = "ARN of the REST API Gateway"
3700
+ value = aws_api_gateway_rest_api.rest_api.arn
3701
+ }
3702
+
3703
+ output "api_endpoint" {
3704
+ description = "Base URL of the REST API Gateway"
3705
+ value = "https://\${aws_api_gateway_rest_api.rest_api.id}.execute-api.\${data.aws_region.current.id}.amazonaws.com"
3706
+ }
3707
+
3708
+ output "api_execution_arn" {
3709
+ description = "Execution ARN of the REST API Gateway"
3710
+ value = aws_api_gateway_rest_api.rest_api.execution_arn
3711
+ }
3712
+
3713
+ output "api_root_resource_id" {
3714
+ description = "Root resource ID of the REST API Gateway"
3715
+ value = aws_api_gateway_rest_api.rest_api.root_resource_id
3716
+ }
3717
+
3718
+ # Note: Stage and deployment outputs are provided by the consuming module
3719
+
3720
+ # Note: CloudWatch log group outputs removed due to account-level CloudWatch Logs role ARN requirement",
3721
+ "test-api.tf": "terraform {
3722
+ required_version = ">= 1.0"
3723
+
3724
+ required_providers {
3725
+ aws = {
3726
+ source = "hashicorp/aws"
3727
+ version = "~> 6.0"
3728
+ }
3729
+ }
3730
+ }
3731
+
3732
+
3733
+ variable "env" {
3734
+ description = "Environment variables for the Lambda function"
3735
+ type = map(string)
3736
+ default = {}
3737
+ }
3738
+
3739
+ variable "additional_iam_policy_statements" {
3740
+ description = "Additional IAM policy statements for the Lambda function"
3741
+ type = list(object({
3742
+ Effect = string
3743
+ Action = list(string)
3744
+ Resource = list(string)
3745
+ }))
3746
+ default = []
3747
+ }
3748
+
3749
+ # CORS Configuration (passed to core module)
3750
+
3751
+ variable "cors_allow_headers" {
3752
+ description = "List of allowed headers for CORS"
3753
+ type = list(string)
3754
+ default = ["authorization", "content-type", "x-amz-content-sha256", "x-amz-date", "x-amz-security-token"]
3755
+ }
3756
+
3757
+ variable "cors_allow_methods" {
3758
+ description = "List of allowed HTTP methods for CORS"
3759
+ type = list(string)
3760
+ default = ["*"]
3761
+ }
3762
+
3763
+ variable "cors_allow_origins" {
3764
+ description = "List of allowed origins for CORS"
3765
+ type = list(string)
3766
+ default = ["*"]
3767
+ }
3768
+
3769
+ # Tags
3770
+ variable "tags" {
3771
+ description = "Tags to apply to all resources"
3772
+ type = map(string)
3773
+ default = {}
3774
+ }
3775
+
3776
+ # Get current AWS region and account ID
3777
+ data "aws_region" "current" {}
3778
+ data "aws_caller_identity" "current" {}
3779
+
3780
+ # Resources
3781
+
3782
+ # Create Lambda ZIP file from the FastAPI bundle directory
3783
+ data "archive_file" "lambda_zip" {
3784
+ type = "zip"
3785
+ source_dir = "\${path.module}/../../../../../../../dist/apps/test_api/bundle"
3786
+ output_path = "\${path.module}/../../../../../../../dist/packages/common/terraform/apis/test-api/lambda.zip"
3787
+ }
3788
+
3789
+ # Use the core REST API module
3790
+ module "rest_api" {
3791
+ source = "../../../core/api/rest-api"
3792
+
3793
+ api_name = "TestApi"
3794
+ api_description = "TestApi REST API"
3795
+ stage_name = "prod"
3796
+ stage_auto_deploy = true
3797
+
3798
+ # CORS Configuration
3799
+ cors_allow_headers = var.cors_allow_headers
3800
+ cors_allow_methods = var.cors_allow_methods
3801
+ cors_allow_origins = var.cors_allow_origins
3802
+
3803
+ # Tags
3804
+ tags = var.tags
3805
+ }
3806
+
3807
+ # Lambda function
3808
+ resource "aws_lambda_function" "api_lambda" {
3809
+ #checkov:skip=CKV_AWS_117:Lambda function does not need to be in VPC for this use case
3810
+ #checkov:skip=CKV_AWS_116:Dead Letter Queue not required for this simple API use case
3811
+ #checkov:skip=CKV_AWS_272:Code signing not required for this use case
3812
+ #checkov:skip=CKV_AWS_115:Concurrent execution limit not required for this use case
3813
+ #checkov:skip=CKV_AWS_173:Lambda environment variables encrypted by managed key
3814
+ filename = data.archive_file.lambda_zip.output_path
3815
+ function_name = "TestApiHandler"
3816
+ role = aws_iam_role.lambda_execution_role.arn
3817
+ handler = "proj_test_api.main.handler"
3818
+ runtime = "python3.12"
3819
+ timeout = 30
3820
+ memory_size = 128
3821
+
3822
+ source_code_hash = data.archive_file.lambda_zip.output_base64sha256
3823
+
3824
+ # Enable X-Ray tracing
3825
+ tracing_config {
3826
+ mode = "Active"
3827
+ }
3828
+
3829
+ environment {
3830
+ variables = merge({
3831
+ AWS_CONNECTION_REUSE_ENABLED = "1"
3832
+ }, var.env)
3833
+ }
3834
+
3835
+ tags = var.tags
3836
+ }
3837
+
3838
+ # IAM role for Lambda execution
3839
+ resource "aws_iam_role" "lambda_execution_role" {
3840
+ name = "TestApiHandler-execution-role"
3841
+
3842
+ assume_role_policy = jsonencode({
3843
+ Version = "2012-10-17"
3844
+ Statement = [
3845
+ {
3846
+ Action = "sts:AssumeRole"
3847
+ Effect = "Allow"
3848
+ Principal = {
3849
+ Service = "lambda.amazonaws.com"
3850
+ }
3851
+ }
3852
+ ]
3853
+ })
3854
+
3855
+ tags = var.tags
3856
+ }
3857
+
3858
+ # Attach basic execution policy to Lambda role
3859
+ resource "aws_iam_role_policy_attachment" "lambda_basic_execution" {
3860
+ policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
3861
+ role = aws_iam_role.lambda_execution_role.name
3862
+ }
3863
+
3864
+ # Attach X-Ray tracing policy to Lambda role
3865
+ resource "aws_iam_role_policy_attachment" "lambda_xray_execution" {
3866
+ policy_arn = "arn:aws:iam::aws:policy/AWSXRayDaemonWriteAccess"
3867
+ role = aws_iam_role.lambda_execution_role.name
3868
+ }
3869
+
3870
+ # Additional IAM policies for Lambda (if provided)
3871
+ resource "aws_iam_role_policy" "lambda_additional_policies" {
3872
+ count = length(var.additional_iam_policy_statements) > 0 ? 1 : 0
3873
+ name = "TestApiHandler-additional-policies"
3874
+ role = aws_iam_role.lambda_execution_role.id
3875
+
3876
+ policy = jsonencode({
3877
+ Version = "2012-10-17"
3878
+ Statement = var.additional_iam_policy_statements
3879
+ })
3880
+ }
3881
+
3882
+ # CloudWatch Log Group for Lambda
3883
+ resource "aws_cloudwatch_log_group" "lambda_logs" {
3884
+ #checkov:skip=CKV_AWS_158:Using default CloudWatch log encryption
3885
+ #checkov:skip=CKV_AWS_338:Log retention set to forever
3886
+ #checkov:skip=CKV_AWS_66:Log retention set to forever
3887
+ name = "/aws/lambda/TestApiHandler"
3888
+ tags = var.tags
3889
+ }
3890
+
3891
+
3892
+ # Create proxy resource (captures all paths)
3893
+ resource "aws_api_gateway_resource" "proxy_resource" {
3894
+ rest_api_id = module.rest_api.api_id
3895
+ parent_id = module.rest_api.api_root_resource_id
3896
+ path_part = "{proxy+}"
3897
+ }
3898
+
3899
+ # Lambda integration for REST API
3900
+ resource "aws_api_gateway_integration" "lambda_integration" {
3901
+ rest_api_id = module.rest_api.api_id
3902
+ resource_id = aws_api_gateway_resource.proxy_resource.id
3903
+ http_method = aws_api_gateway_method.proxy_method.http_method
3904
+
3905
+ integration_http_method = "POST"
3906
+ type = "AWS_PROXY"
3907
+ uri = aws_lambda_function.api_lambda.invoke_arn
3908
+
3909
+ depends_on = [aws_lambda_function.api_lambda]
3910
+ }
3911
+
3912
+ # Method for proxy integration
3913
+ resource "aws_api_gateway_method" "proxy_method" {
3914
+ #checkov:skip=CKV2_AWS_53:Request validation not required for proxy integration as Lambda handles validation
3915
+ rest_api_id = module.rest_api.api_id
3916
+ resource_id = aws_api_gateway_resource.proxy_resource.id
3917
+ http_method = "ANY"
3918
+
3919
+ authorization = "AWS_IAM"
3920
+
3921
+ request_parameters = {
3922
+ "method.request.path.proxy" = true
3923
+ }
3924
+
3925
+ depends_on = []
3926
+ }
3927
+
3928
+ # OPTIONS method for CORS preflight
3929
+ resource "aws_api_gateway_method" "options_method" {
3930
+ #checkov:skip=CKV2_AWS_70:OPTIONS method must be unauthenticated for CORS preflight requests
3931
+ #checkov:skip=CKV2_AWS_53:Request validation not required for OPTIONS CORS preflight method
3932
+ rest_api_id = module.rest_api.api_id
3933
+ resource_id = aws_api_gateway_resource.proxy_resource.id
3934
+ http_method = "OPTIONS"
3935
+ authorization = "NONE"
3936
+ }
3937
+
3938
+ # CORS integration for OPTIONS method
3939
+ resource "aws_api_gateway_integration" "options_integration" {
3940
+ rest_api_id = module.rest_api.api_id
3941
+ resource_id = aws_api_gateway_resource.proxy_resource.id
3942
+ http_method = aws_api_gateway_method.options_method.http_method
3943
+
3944
+ type = "MOCK"
3945
+ request_templates = {
3946
+ "application/json" = "{\\"statusCode\\": 204}"
3947
+ }
3948
+ }
3949
+
3950
+ # OPTIONS method response
3951
+ resource "aws_api_gateway_method_response" "options_response" {
3952
+ rest_api_id = module.rest_api.api_id
3953
+ resource_id = aws_api_gateway_resource.proxy_resource.id
3954
+ http_method = aws_api_gateway_method.options_method.http_method
3955
+ status_code = "204"
3956
+
3957
+ response_parameters = {
3958
+ "method.response.header.Access-Control-Allow-Headers" = true
3959
+ "method.response.header.Access-Control-Allow-Methods" = true
3960
+ "method.response.header.Access-Control-Allow-Origin" = true
3961
+ }
3962
+ }
3963
+
3964
+ # OPTIONS integration response
3965
+ resource "aws_api_gateway_integration_response" "options_integration_response" {
3966
+ rest_api_id = module.rest_api.api_id
3967
+ resource_id = aws_api_gateway_resource.proxy_resource.id
3968
+ http_method = aws_api_gateway_method.options_method.http_method
3969
+ status_code = aws_api_gateway_method_response.options_response.status_code
3970
+
3971
+ response_parameters = {
3972
+ "method.response.header.Access-Control-Allow-Headers" = "'\${join(",", var.cors_allow_headers)}'"
3973
+ "method.response.header.Access-Control-Allow-Methods" = "'\${join(",", var.cors_allow_methods)}'"
3974
+ "method.response.header.Access-Control-Allow-Origin" = "'\${join(",", var.cors_allow_origins)}'"
3975
+ }
3976
+ }
3977
+
3978
+ # API Gateway deployment
3979
+ resource "aws_api_gateway_deployment" "api_deployment" {
3980
+ rest_api_id = module.rest_api.api_id
3981
+
3982
+ triggers = {
3983
+ redeployment = sha1(jsonencode([
3984
+ aws_api_gateway_resource.proxy_resource.id,
3985
+ aws_api_gateway_method.proxy_method.id,
3986
+ aws_api_gateway_integration.lambda_integration.id,
3987
+ aws_api_gateway_method.options_method.id,
3988
+ aws_api_gateway_integration.options_integration.id,
3989
+ ]))
3990
+ }
3991
+
3992
+ lifecycle {
3993
+ create_before_destroy = true
3994
+ }
3995
+
3996
+ depends_on = [
3997
+ aws_api_gateway_method.proxy_method,
3998
+ aws_api_gateway_integration.lambda_integration,
3999
+ aws_api_gateway_method.options_method,
4000
+ aws_api_gateway_integration.options_integration,
4001
+ aws_api_gateway_method_response.options_response,
4002
+ aws_api_gateway_integration_response.options_integration_response,
4003
+ ]
4004
+ }
4005
+
4006
+ # API Gateway stage
4007
+ resource "aws_api_gateway_stage" "api_stage" {
4008
+ #checkov:skip=CKV_AWS_120:API Gateway caching not required for this use case
4009
+ #checkov:skip=CKV_AWS_76:API Gateway access logging disabled due to account-level CloudWatch Logs role ARN requirement
4010
+ #checkov:skip=CKV2_AWS_4:API Gateway logging level not applicable as access logging is disabled
4011
+ #checkov:skip=CKV2_AWS_51:Client certificate authentication not required for this use case
4012
+ deployment_id = aws_api_gateway_deployment.api_deployment.id
4013
+ rest_api_id = module.rest_api.api_id
4014
+ stage_name = "prod"
4015
+ xray_tracing_enabled = true
4016
+
4017
+ tags = var.tags
4018
+
4019
+ depends_on = [aws_api_gateway_deployment.api_deployment]
4020
+ }
4021
+
4022
+ # API Gateway Resource Policy
4023
+ resource "aws_api_gateway_rest_api_policy" "api_policy" {
4024
+ rest_api_id = module.rest_api.api_id
4025
+
4026
+ policy = jsonencode({
4027
+ Version = "2012-10-17"
4028
+ Statement = [
4029
+ {
4030
+ # Grant any AWS credentials from the account to call the API
4031
+ # Machine to machine fine-grained access can be defined here using more specific principals
4032
+ # (eg roles or users) and resources (eg which api paths may be invoked by which principal) if required
4033
+ Effect = "Allow"
4034
+ Principal = {
4035
+ AWS = "arn:aws:iam::\${data.aws_caller_identity.current.account_id}:root"
4036
+ }
4037
+ Action = "execute-api:Invoke"
4038
+ Resource = "execute-api:/*"
4039
+ },
4040
+ {
4041
+ # Open up OPTIONS to allow browsers to make unauthenticated preflight requests
4042
+ Effect = "Allow"
4043
+ Principal = "*"
4044
+ Action = "execute-api:Invoke"
4045
+ Resource = "execute-api:/*/OPTIONS/*"
4046
+ }
4047
+ ]
4048
+ })
4049
+ }
4050
+
4051
+ # Lambda permission for API Gateway to invoke the function
4052
+ resource "aws_lambda_permission" "api_gateway_invoke" {
4053
+ statement_id = "AllowExecutionFromAPIGateway"
4054
+ action = "lambda:InvokeFunction"
4055
+ function_name = aws_lambda_function.api_lambda.function_name
4056
+ principal = "apigateway.amazonaws.com"
4057
+ source_arn = "\${module.rest_api.api_execution_arn}/*/*"
4058
+
4059
+ depends_on = [module.rest_api, aws_lambda_function.api_lambda]
4060
+ }
4061
+
4062
+ # Outputs
4063
+
4064
+ # API Gateway Outputs (from core module)
4065
+ output "api_id" {
4066
+ description = "ID of the REST API Gateway"
4067
+ value = module.rest_api.api_id
4068
+ }
4069
+
4070
+ output "api_arn" {
4071
+ description = "ARN of the REST API Gateway"
4072
+ value = module.rest_api.api_arn
4073
+ }
4074
+
4075
+ output "api_endpoint" {
4076
+ description = "Base URL of the REST API Gateway"
4077
+ value = module.rest_api.api_endpoint
4078
+ }
4079
+
4080
+ output "api_execution_arn" {
4081
+ description = "Execution ARN of the REST API Gateway"
4082
+ value = module.rest_api.api_execution_arn
4083
+ }
4084
+
4085
+ output "stage_invoke_url" {
4086
+ description = "Invoke URL of the API Gateway stage"
4087
+ value = aws_api_gateway_stage.api_stage.invoke_url
4088
+ }
4089
+
4090
+ output "stage_arn" {
4091
+ description = "ARN of the API Gateway stage"
4092
+ value = aws_api_gateway_stage.api_stage.arn
4093
+ }
4094
+
4095
+ output "stage_execution_arn" {
4096
+ description = "Execution ARN of the API Gateway stage"
4097
+ value = aws_api_gateway_stage.api_stage.execution_arn
4098
+ }
4099
+
4100
+ output "deployment_id" {
4101
+ description = "ID of the API Gateway deployment"
4102
+ value = aws_api_gateway_deployment.api_deployment.id
4103
+ }
4104
+
4105
+ output "stage_id" {
4106
+ description = "ID of the API Gateway stage"
4107
+ value = aws_api_gateway_stage.api_stage.id
4108
+ }
4109
+
4110
+ # Lambda Function Outputs
4111
+ output "lambda_function_name" {
4112
+ description = "Name of the Lambda function"
4113
+ value = aws_lambda_function.api_lambda.function_name
4114
+ }
4115
+
4116
+ output "lambda_function_arn" {
4117
+ description = "ARN of the Lambda function"
4118
+ value = aws_lambda_function.api_lambda.arn
4119
+ }
4120
+
4121
+ output "lambda_invoke_arn" {
4122
+ description = "Invoke ARN of the Lambda function"
4123
+ value = aws_lambda_function.api_lambda.invoke_arn
4124
+ }
4125
+
4126
+ output "lambda_qualified_arn" {
4127
+ description = "Qualified ARN of the Lambda function"
4128
+ value = aws_lambda_function.api_lambda.qualified_arn
4129
+ }
4130
+
4131
+ output "lambda_version" {
4132
+ description = "Version of the Lambda function"
4133
+ value = aws_lambda_function.api_lambda.version
4134
+ }
4135
+
4136
+ output "lambda_source_code_hash" {
4137
+ description = "Base64-encoded SHA256 hash of the Lambda deployment package"
4138
+ value = aws_lambda_function.api_lambda.source_code_hash
4139
+ }
4140
+
4141
+ output "lambda_source_code_size" {
4142
+ description = "Size of the Lambda deployment package in bytes"
4143
+ value = aws_lambda_function.api_lambda.source_code_size
4144
+ }
4145
+
4146
+ # IAM Role Outputs
4147
+ output "lambda_execution_role_arn" {
4148
+ description = "ARN of the Lambda execution role"
4149
+ value = aws_iam_role.lambda_execution_role.arn
4150
+ }
4151
+
4152
+ output "lambda_execution_role_name" {
4153
+ description = "Name of the Lambda execution role"
4154
+ value = aws_iam_role.lambda_execution_role.name
4155
+ }
4156
+
4157
+ # Integration Outputs
4158
+ output "integration_id" {
4159
+ description = "ID of the Lambda integration"
4160
+ value = aws_api_gateway_integration.lambda_integration.id
4161
+ }
4162
+
4163
+ output "proxy_resource_id" {
4164
+ description = "ID of the proxy resource"
4165
+ value = aws_api_gateway_resource.proxy_resource.id
4166
+ }
4167
+
4168
+ output "proxy_method_id" {
4169
+ description = "ID of the proxy method"
4170
+ value = aws_api_gateway_method.proxy_method.id
4171
+ }
4172
+
4173
+ # CloudWatch Log Groups
4174
+ output "lambda_log_group_name" {
4175
+ description = "Name of the Lambda CloudWatch log group"
4176
+ value = aws_cloudwatch_log_group.lambda_logs.name
4177
+ }
4178
+
4179
+ output "lambda_log_group_arn" {
4180
+ description = "ARN of the Lambda CloudWatch log group"
4181
+ value = aws_cloudwatch_log_group.lambda_logs.arn
4182
+ }
4183
+ ",
4184
+ }
4185
+ `;
4186
+
4187
+ exports[`fastapi project generator > terraform iacProvider > should generate terraform files for REST API with None auth and snapshot them > terraform-rest-none-files 1`] = `
4188
+ {
4189
+ "rest-api.tf": "# Core REST API Gateway module
4190
+ # This module creates the API Gateway REST API, deployment, stage, and logging resources
4191
+
4192
+ terraform {
4193
+ required_version = ">= 1.0"
4194
+
4195
+ required_providers {
4196
+ aws = {
4197
+ source = "hashicorp/aws"
4198
+ version = "~> 6.0"
4199
+ }
4200
+ }
4201
+ }
4202
+
4203
+ # Core REST API Gateway Variables
4204
+
4205
+ variable "api_name" {
4206
+ description = "Name of the REST API Gateway"
4207
+ type = string
4208
+ }
4209
+
4210
+ variable "api_description" {
4211
+ description = "Description of the REST API Gateway"
4212
+ type = string
4213
+ default = "REST API Gateway"
4214
+ }
4215
+
4216
+ variable "stage_name" {
4217
+ description = "Name of the API Gateway stage"
4218
+ type = string
4219
+ default = "prod"
4220
+ }
4221
+
4222
+ variable "stage_auto_deploy" {
4223
+ description = "Whether to automatically deploy the API stage"
4224
+ type = bool
4225
+ default = true
4226
+ }
4227
+
4228
+ # CORS Configuration
4229
+
4230
+ variable "cors_allow_headers" {
4231
+ description = "List of allowed headers for CORS"
4232
+ type = list(string)
4233
+ default = ["authorization", "content-type", "x-amz-content-sha256", "x-amz-date", "x-amz-security-token"]
4234
+ }
4235
+
4236
+ variable "cors_allow_methods" {
4237
+ description = "List of allowed HTTP methods for CORS"
4238
+ type = list(string)
4239
+ default = ["*"]
4240
+ }
4241
+
4242
+ variable "cors_allow_origins" {
4243
+ description = "List of allowed origins for CORS"
4244
+ type = list(string)
4245
+ default = ["*"]
4246
+ }
4247
+
4248
+ # Tags
4249
+
4250
+ variable "tags" {
4251
+ description = "Tags to apply to all resources"
4252
+ type = map(string)
4253
+ default = {}
4254
+ }
4255
+
4256
+ # Data sources
4257
+ data "aws_region" "current" {}
4258
+ data "aws_caller_identity" "current" {}
4259
+
4260
+ # Resources
4261
+
4262
+ # Note: CloudWatch logging removed due to account-level CloudWatch Logs role ARN requirement
4263
+
4264
+ # REST API Gateway
4265
+ resource "aws_api_gateway_rest_api" "rest_api" {
4266
+ name = var.api_name
4267
+ description = var.api_description
4268
+
4269
+ endpoint_configuration {
4270
+ types = ["REGIONAL"]
4271
+ }
4272
+
4273
+ lifecycle {
4274
+ create_before_destroy = true
4275
+ }
4276
+
4277
+ tags = var.tags
4278
+ }
4279
+
4280
+ # Note: Deployment and stage are created in the consuming module (e.g., foo-api.tf)
4281
+ # after all methods and integrations are defined
4282
+
4283
+ # Note: CloudWatch Log Group removed due to account-level CloudWatch Logs role ARN requirement
4284
+
4285
+ # Gateway Response for CORS (4XX errors)
4286
+ resource "aws_api_gateway_gateway_response" "cors_4xx" {
4287
+ rest_api_id = aws_api_gateway_rest_api.rest_api.id
4288
+ response_type = "DEFAULT_4XX"
4289
+
4290
+ response_parameters = {
4291
+ "gatewayresponse.header.Access-Control-Allow-Origin" = "'\${join(",", var.cors_allow_origins)}'"
4292
+ "gatewayresponse.header.Access-Control-Allow-Headers" = "'\${join(",", var.cors_allow_headers)}'"
4293
+ "gatewayresponse.header.Access-Control-Allow-Methods" = "'\${join(",", var.cors_allow_methods)}'"
4294
+ }
4295
+ }
4296
+
4297
+ # Gateway Response for CORS (5XX errors)
4298
+ resource "aws_api_gateway_gateway_response" "cors_5xx" {
4299
+ rest_api_id = aws_api_gateway_rest_api.rest_api.id
4300
+ response_type = "DEFAULT_5XX"
4301
+
4302
+ response_parameters = {
4303
+ "gatewayresponse.header.Access-Control-Allow-Origin" = "'\${join(",", var.cors_allow_origins)}'"
4304
+ "gatewayresponse.header.Access-Control-Allow-Headers" = "'\${join(",", var.cors_allow_headers)}'"
4305
+ "gatewayresponse.header.Access-Control-Allow-Methods" = "'\${join(",", var.cors_allow_methods)}'"
4306
+ }
4307
+ }
4308
+
4309
+ # Outputs
4310
+
4311
+ output "api_id" {
4312
+ description = "ID of the REST API Gateway"
4313
+ value = aws_api_gateway_rest_api.rest_api.id
4314
+ }
4315
+
4316
+ output "api_arn" {
4317
+ description = "ARN of the REST API Gateway"
4318
+ value = aws_api_gateway_rest_api.rest_api.arn
4319
+ }
4320
+
4321
+ output "api_endpoint" {
4322
+ description = "Base URL of the REST API Gateway"
4323
+ value = "https://\${aws_api_gateway_rest_api.rest_api.id}.execute-api.\${data.aws_region.current.id}.amazonaws.com"
4324
+ }
4325
+
4326
+ output "api_execution_arn" {
4327
+ description = "Execution ARN of the REST API Gateway"
4328
+ value = aws_api_gateway_rest_api.rest_api.execution_arn
4329
+ }
4330
+
4331
+ output "api_root_resource_id" {
4332
+ description = "Root resource ID of the REST API Gateway"
4333
+ value = aws_api_gateway_rest_api.rest_api.root_resource_id
4334
+ }
4335
+
4336
+ # Note: Stage and deployment outputs are provided by the consuming module
4337
+
4338
+ # Note: CloudWatch log group outputs removed due to account-level CloudWatch Logs role ARN requirement",
4339
+ "test-api.tf": "terraform {
4340
+ required_version = ">= 1.0"
4341
+
4342
+ required_providers {
4343
+ aws = {
4344
+ source = "hashicorp/aws"
4345
+ version = "~> 6.0"
4346
+ }
4347
+ }
4348
+ }
4349
+
4350
+
4351
+ variable "env" {
4352
+ description = "Environment variables for the Lambda function"
4353
+ type = map(string)
4354
+ default = {}
4355
+ }
4356
+
4357
+ variable "additional_iam_policy_statements" {
4358
+ description = "Additional IAM policy statements for the Lambda function"
4359
+ type = list(object({
4360
+ Effect = string
4361
+ Action = list(string)
4362
+ Resource = list(string)
4363
+ }))
4364
+ default = []
4365
+ }
4366
+
4367
+ # CORS Configuration (passed to core module)
4368
+
4369
+ variable "cors_allow_headers" {
4370
+ description = "List of allowed headers for CORS"
4371
+ type = list(string)
4372
+ default = ["authorization", "content-type", "x-amz-content-sha256", "x-amz-date", "x-amz-security-token"]
4373
+ }
4374
+
4375
+ variable "cors_allow_methods" {
4376
+ description = "List of allowed HTTP methods for CORS"
4377
+ type = list(string)
4378
+ default = ["*"]
4379
+ }
4380
+
4381
+ variable "cors_allow_origins" {
4382
+ description = "List of allowed origins for CORS"
4383
+ type = list(string)
4384
+ default = ["*"]
4385
+ }
4386
+
4387
+ # Tags
4388
+ variable "tags" {
4389
+ description = "Tags to apply to all resources"
4390
+ type = map(string)
4391
+ default = {}
4392
+ }
4393
+
4394
+ # Get current AWS region and account ID
4395
+ data "aws_region" "current" {}
4396
+ data "aws_caller_identity" "current" {}
4397
+
4398
+ # Resources
4399
+
4400
+ # Create Lambda ZIP file from the FastAPI bundle directory
4401
+ data "archive_file" "lambda_zip" {
4402
+ type = "zip"
4403
+ source_dir = "\${path.module}/../../../../../../../dist/apps/test_api/bundle"
4404
+ output_path = "\${path.module}/../../../../../../../dist/packages/common/terraform/apis/test-api/lambda.zip"
4405
+ }
4406
+
4407
+ # Use the core REST API module
4408
+ module "rest_api" {
4409
+ source = "../../../core/api/rest-api"
4410
+
4411
+ api_name = "TestApi"
4412
+ api_description = "TestApi REST API"
4413
+ stage_name = "prod"
4414
+ stage_auto_deploy = true
4415
+
4416
+ # CORS Configuration
4417
+ cors_allow_headers = var.cors_allow_headers
4418
+ cors_allow_methods = var.cors_allow_methods
4419
+ cors_allow_origins = var.cors_allow_origins
4420
+
4421
+ # Tags
4422
+ tags = var.tags
4423
+ }
4424
+
4425
+ # Lambda function
4426
+ resource "aws_lambda_function" "api_lambda" {
4427
+ #checkov:skip=CKV_AWS_117:Lambda function does not need to be in VPC for this use case
4428
+ #checkov:skip=CKV_AWS_116:Dead Letter Queue not required for this simple API use case
4429
+ #checkov:skip=CKV_AWS_272:Code signing not required for this use case
4430
+ #checkov:skip=CKV_AWS_115:Concurrent execution limit not required for this use case
4431
+ #checkov:skip=CKV_AWS_173:Lambda environment variables encrypted by managed key
4432
+ filename = data.archive_file.lambda_zip.output_path
4433
+ function_name = "TestApiHandler"
4434
+ role = aws_iam_role.lambda_execution_role.arn
4435
+ handler = "proj_test_api.main.handler"
4436
+ runtime = "python3.12"
4437
+ timeout = 30
4438
+ memory_size = 128
4439
+
4440
+ source_code_hash = data.archive_file.lambda_zip.output_base64sha256
4441
+
4442
+ # Enable X-Ray tracing
4443
+ tracing_config {
4444
+ mode = "Active"
4445
+ }
4446
+
4447
+ environment {
4448
+ variables = merge({
4449
+ AWS_CONNECTION_REUSE_ENABLED = "1"
4450
+ }, var.env)
4451
+ }
4452
+
4453
+ tags = var.tags
4454
+ }
4455
+
4456
+ # IAM role for Lambda execution
4457
+ resource "aws_iam_role" "lambda_execution_role" {
4458
+ name = "TestApiHandler-execution-role"
4459
+
4460
+ assume_role_policy = jsonencode({
4461
+ Version = "2012-10-17"
4462
+ Statement = [
4463
+ {
4464
+ Action = "sts:AssumeRole"
4465
+ Effect = "Allow"
4466
+ Principal = {
4467
+ Service = "lambda.amazonaws.com"
4468
+ }
4469
+ }
4470
+ ]
4471
+ })
4472
+
4473
+ tags = var.tags
4474
+ }
4475
+
4476
+ # Attach basic execution policy to Lambda role
4477
+ resource "aws_iam_role_policy_attachment" "lambda_basic_execution" {
4478
+ policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
4479
+ role = aws_iam_role.lambda_execution_role.name
4480
+ }
4481
+
4482
+ # Attach X-Ray tracing policy to Lambda role
4483
+ resource "aws_iam_role_policy_attachment" "lambda_xray_execution" {
4484
+ policy_arn = "arn:aws:iam::aws:policy/AWSXRayDaemonWriteAccess"
4485
+ role = aws_iam_role.lambda_execution_role.name
4486
+ }
4487
+
4488
+ # Additional IAM policies for Lambda (if provided)
4489
+ resource "aws_iam_role_policy" "lambda_additional_policies" {
4490
+ count = length(var.additional_iam_policy_statements) > 0 ? 1 : 0
4491
+ name = "TestApiHandler-additional-policies"
4492
+ role = aws_iam_role.lambda_execution_role.id
4493
+
4494
+ policy = jsonencode({
4495
+ Version = "2012-10-17"
4496
+ Statement = var.additional_iam_policy_statements
4497
+ })
4498
+ }
4499
+
4500
+ # CloudWatch Log Group for Lambda
4501
+ resource "aws_cloudwatch_log_group" "lambda_logs" {
4502
+ #checkov:skip=CKV_AWS_158:Using default CloudWatch log encryption
4503
+ #checkov:skip=CKV_AWS_338:Log retention set to forever
4504
+ #checkov:skip=CKV_AWS_66:Log retention set to forever
4505
+ name = "/aws/lambda/TestApiHandler"
4506
+ tags = var.tags
4507
+ }
4508
+
4509
+
4510
+ # Create proxy resource (captures all paths)
4511
+ resource "aws_api_gateway_resource" "proxy_resource" {
4512
+ rest_api_id = module.rest_api.api_id
4513
+ parent_id = module.rest_api.api_root_resource_id
4514
+ path_part = "{proxy+}"
4515
+ }
4516
+
4517
+ # Lambda integration for REST API
4518
+ resource "aws_api_gateway_integration" "lambda_integration" {
4519
+ rest_api_id = module.rest_api.api_id
4520
+ resource_id = aws_api_gateway_resource.proxy_resource.id
4521
+ http_method = aws_api_gateway_method.proxy_method.http_method
4522
+
4523
+ integration_http_method = "POST"
4524
+ type = "AWS_PROXY"
4525
+ uri = aws_lambda_function.api_lambda.invoke_arn
4526
+
4527
+ depends_on = [aws_lambda_function.api_lambda]
4528
+ }
4529
+
4530
+ # Method for proxy integration
4531
+ resource "aws_api_gateway_method" "proxy_method" {
4532
+ #checkov:skip=CKV2_AWS_53:Request validation not required for proxy integration as Lambda handles validation
4533
+ rest_api_id = module.rest_api.api_id
4534
+ resource_id = aws_api_gateway_resource.proxy_resource.id
4535
+ http_method = "ANY"
4536
+
4537
+ # Note: you may wish to suppress the checkov rule CKV_AWS_59 if you are absolutely sure you
4538
+ # need a public API without authentication
4539
+ authorization = "NONE"
4540
+
4541
+ request_parameters = {
4542
+ "method.request.path.proxy" = true
4543
+ }
4544
+
4545
+ depends_on = []
4546
+ }
4547
+
4548
+ # OPTIONS method for CORS preflight
4549
+ resource "aws_api_gateway_method" "options_method" {
4550
+ #checkov:skip=CKV2_AWS_70:OPTIONS method must be unauthenticated for CORS preflight requests
4551
+ #checkov:skip=CKV2_AWS_53:Request validation not required for OPTIONS CORS preflight method
4552
+ rest_api_id = module.rest_api.api_id
4553
+ resource_id = aws_api_gateway_resource.proxy_resource.id
4554
+ http_method = "OPTIONS"
4555
+ authorization = "NONE"
4556
+ }
4557
+
4558
+ # CORS integration for OPTIONS method
4559
+ resource "aws_api_gateway_integration" "options_integration" {
4560
+ rest_api_id = module.rest_api.api_id
4561
+ resource_id = aws_api_gateway_resource.proxy_resource.id
4562
+ http_method = aws_api_gateway_method.options_method.http_method
4563
+
4564
+ type = "MOCK"
4565
+ request_templates = {
4566
+ "application/json" = "{\\"statusCode\\": 204}"
4567
+ }
4568
+ }
4569
+
4570
+ # OPTIONS method response
4571
+ resource "aws_api_gateway_method_response" "options_response" {
4572
+ rest_api_id = module.rest_api.api_id
4573
+ resource_id = aws_api_gateway_resource.proxy_resource.id
4574
+ http_method = aws_api_gateway_method.options_method.http_method
4575
+ status_code = "204"
4576
+
4577
+ response_parameters = {
4578
+ "method.response.header.Access-Control-Allow-Headers" = true
4579
+ "method.response.header.Access-Control-Allow-Methods" = true
4580
+ "method.response.header.Access-Control-Allow-Origin" = true
4581
+ }
4582
+ }
4583
+
4584
+ # OPTIONS integration response
4585
+ resource "aws_api_gateway_integration_response" "options_integration_response" {
4586
+ rest_api_id = module.rest_api.api_id
4587
+ resource_id = aws_api_gateway_resource.proxy_resource.id
4588
+ http_method = aws_api_gateway_method.options_method.http_method
4589
+ status_code = aws_api_gateway_method_response.options_response.status_code
4590
+
4591
+ response_parameters = {
4592
+ "method.response.header.Access-Control-Allow-Headers" = "'\${join(",", var.cors_allow_headers)}'"
4593
+ "method.response.header.Access-Control-Allow-Methods" = "'\${join(",", var.cors_allow_methods)}'"
4594
+ "method.response.header.Access-Control-Allow-Origin" = "'\${join(",", var.cors_allow_origins)}'"
4595
+ }
4596
+ }
4597
+
4598
+ # API Gateway deployment
4599
+ resource "aws_api_gateway_deployment" "api_deployment" {
4600
+ rest_api_id = module.rest_api.api_id
4601
+
4602
+ triggers = {
4603
+ redeployment = sha1(jsonencode([
4604
+ aws_api_gateway_resource.proxy_resource.id,
4605
+ aws_api_gateway_method.proxy_method.id,
4606
+ aws_api_gateway_integration.lambda_integration.id,
4607
+ aws_api_gateway_method.options_method.id,
4608
+ aws_api_gateway_integration.options_integration.id,
4609
+ ]))
4610
+ }
4611
+
4612
+ lifecycle {
4613
+ create_before_destroy = true
4614
+ }
4615
+
4616
+ depends_on = [
4617
+ aws_api_gateway_method.proxy_method,
4618
+ aws_api_gateway_integration.lambda_integration,
4619
+ aws_api_gateway_method.options_method,
4620
+ aws_api_gateway_integration.options_integration,
4621
+ aws_api_gateway_method_response.options_response,
4622
+ aws_api_gateway_integration_response.options_integration_response,
4623
+ ]
4624
+ }
4625
+
4626
+ # API Gateway stage
4627
+ resource "aws_api_gateway_stage" "api_stage" {
4628
+ #checkov:skip=CKV_AWS_120:API Gateway caching not required for this use case
4629
+ #checkov:skip=CKV_AWS_76:API Gateway access logging disabled due to account-level CloudWatch Logs role ARN requirement
4630
+ #checkov:skip=CKV2_AWS_4:API Gateway logging level not applicable as access logging is disabled
4631
+ #checkov:skip=CKV2_AWS_51:Client certificate authentication not required for this use case
4632
+ deployment_id = aws_api_gateway_deployment.api_deployment.id
4633
+ rest_api_id = module.rest_api.api_id
4634
+ stage_name = "prod"
4635
+ xray_tracing_enabled = true
4636
+
4637
+ tags = var.tags
4638
+
4639
+ depends_on = [aws_api_gateway_deployment.api_deployment]
4640
+ }
4641
+
4642
+ # API Gateway Resource Policy
4643
+ resource "aws_api_gateway_rest_api_policy" "api_policy" {
4644
+ rest_api_id = module.rest_api.api_id
4645
+
4646
+ policy = jsonencode({
4647
+ Version = "2012-10-17"
4648
+ Statement = [
4649
+ {
4650
+ # Allow all callers to invoke the API in the resource policy
4651
+ Effect = "Allow"
4652
+ Principal = "*"
4653
+ Action = "execute-api:Invoke"
4654
+ Resource = "execute-api:/*"
4655
+ }
4656
+ ]
4657
+ })
4658
+ }
4659
+
4660
+ # Lambda permission for API Gateway to invoke the function
4661
+ resource "aws_lambda_permission" "api_gateway_invoke" {
4662
+ statement_id = "AllowExecutionFromAPIGateway"
4663
+ action = "lambda:InvokeFunction"
4664
+ function_name = aws_lambda_function.api_lambda.function_name
4665
+ principal = "apigateway.amazonaws.com"
4666
+ source_arn = "\${module.rest_api.api_execution_arn}/*/*"
4667
+
4668
+ depends_on = [module.rest_api, aws_lambda_function.api_lambda]
4669
+ }
4670
+
4671
+ # Outputs
4672
+
4673
+ # API Gateway Outputs (from core module)
4674
+ output "api_id" {
4675
+ description = "ID of the REST API Gateway"
4676
+ value = module.rest_api.api_id
4677
+ }
4678
+
4679
+ output "api_arn" {
4680
+ description = "ARN of the REST API Gateway"
4681
+ value = module.rest_api.api_arn
4682
+ }
4683
+
4684
+ output "api_endpoint" {
4685
+ description = "Base URL of the REST API Gateway"
4686
+ value = module.rest_api.api_endpoint
4687
+ }
4688
+
4689
+ output "api_execution_arn" {
4690
+ description = "Execution ARN of the REST API Gateway"
4691
+ value = module.rest_api.api_execution_arn
4692
+ }
4693
+
4694
+ output "stage_invoke_url" {
4695
+ description = "Invoke URL of the API Gateway stage"
4696
+ value = aws_api_gateway_stage.api_stage.invoke_url
4697
+ }
4698
+
4699
+ output "stage_arn" {
4700
+ description = "ARN of the API Gateway stage"
4701
+ value = aws_api_gateway_stage.api_stage.arn
4702
+ }
4703
+
4704
+ output "stage_execution_arn" {
4705
+ description = "Execution ARN of the API Gateway stage"
4706
+ value = aws_api_gateway_stage.api_stage.execution_arn
4707
+ }
4708
+
4709
+ output "deployment_id" {
4710
+ description = "ID of the API Gateway deployment"
4711
+ value = aws_api_gateway_deployment.api_deployment.id
4712
+ }
4713
+
4714
+ output "stage_id" {
4715
+ description = "ID of the API Gateway stage"
4716
+ value = aws_api_gateway_stage.api_stage.id
4717
+ }
4718
+
4719
+ # Lambda Function Outputs
4720
+ output "lambda_function_name" {
4721
+ description = "Name of the Lambda function"
4722
+ value = aws_lambda_function.api_lambda.function_name
4723
+ }
4724
+
4725
+ output "lambda_function_arn" {
4726
+ description = "ARN of the Lambda function"
4727
+ value = aws_lambda_function.api_lambda.arn
4728
+ }
4729
+
4730
+ output "lambda_invoke_arn" {
4731
+ description = "Invoke ARN of the Lambda function"
4732
+ value = aws_lambda_function.api_lambda.invoke_arn
4733
+ }
4734
+
4735
+ output "lambda_qualified_arn" {
4736
+ description = "Qualified ARN of the Lambda function"
4737
+ value = aws_lambda_function.api_lambda.qualified_arn
4738
+ }
4739
+
4740
+ output "lambda_version" {
4741
+ description = "Version of the Lambda function"
4742
+ value = aws_lambda_function.api_lambda.version
4743
+ }
4744
+
4745
+ output "lambda_source_code_hash" {
4746
+ description = "Base64-encoded SHA256 hash of the Lambda deployment package"
4747
+ value = aws_lambda_function.api_lambda.source_code_hash
4748
+ }
4749
+
4750
+ output "lambda_source_code_size" {
4751
+ description = "Size of the Lambda deployment package in bytes"
4752
+ value = aws_lambda_function.api_lambda.source_code_size
4753
+ }
4754
+
4755
+ # IAM Role Outputs
4756
+ output "lambda_execution_role_arn" {
4757
+ description = "ARN of the Lambda execution role"
4758
+ value = aws_iam_role.lambda_execution_role.arn
4759
+ }
4760
+
4761
+ output "lambda_execution_role_name" {
4762
+ description = "Name of the Lambda execution role"
4763
+ value = aws_iam_role.lambda_execution_role.name
4764
+ }
4765
+
4766
+ # Integration Outputs
4767
+ output "integration_id" {
4768
+ description = "ID of the Lambda integration"
4769
+ value = aws_api_gateway_integration.lambda_integration.id
4770
+ }
4771
+
4772
+ output "proxy_resource_id" {
4773
+ description = "ID of the proxy resource"
4774
+ value = aws_api_gateway_resource.proxy_resource.id
4775
+ }
4776
+
4777
+ output "proxy_method_id" {
4778
+ description = "ID of the proxy method"
4779
+ value = aws_api_gateway_method.proxy_method.id
4780
+ }
4781
+
4782
+ # CloudWatch Log Groups
4783
+ output "lambda_log_group_name" {
4784
+ description = "Name of the Lambda CloudWatch log group"
4785
+ value = aws_cloudwatch_log_group.lambda_logs.name
4786
+ }
4787
+
4788
+ output "lambda_log_group_arn" {
4789
+ description = "ARN of the Lambda CloudWatch log group"
4790
+ value = aws_cloudwatch_log_group.lambda_logs.arn
4791
+ }
4792
+ ",
4793
+ }
4794
+ `;