@aws/nx-plugin 0.45.1 → 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 (63) hide show
  1. package/package.json +1 -1
  2. package/src/py/fast-api/__snapshots__/generator.spec.ts.snap +3669 -0
  3. package/src/py/fast-api/generator.js +57 -50
  4. package/src/py/fast-api/generator.js.map +1 -1
  5. package/src/py/fast-api/schema.d.ts +1 -0
  6. package/src/py/fast-api/schema.json +8 -0
  7. package/src/py/mcp-server/__snapshots__/generator.spec.ts.snap +590 -0
  8. package/src/py/mcp-server/generator.js +4 -18
  9. package/src/py/mcp-server/generator.js.map +1 -1
  10. package/src/py/mcp-server/schema.d.ts +1 -0
  11. package/src/py/mcp-server/schema.json +8 -0
  12. package/src/py/strands-agent/__snapshots__/generator.spec.ts.snap +590 -0
  13. package/src/py/strands-agent/generator.js +4 -18
  14. package/src/py/strands-agent/generator.js.map +1 -1
  15. package/src/py/strands-agent/schema.d.ts +1 -0
  16. package/src/py/strands-agent/schema.json +8 -0
  17. package/src/terraform/project/generator.js +23 -7
  18. package/src/terraform/project/generator.js.map +1 -1
  19. package/src/trpc/backend/__snapshots__/generator.spec.ts.snap +3669 -0
  20. package/src/trpc/backend/generator.js +6 -17
  21. package/src/trpc/backend/generator.js.map +1 -1
  22. package/src/trpc/backend/schema.d.ts +1 -0
  23. package/src/trpc/backend/schema.json +8 -0
  24. package/src/ts/mcp-server/__snapshots__/generator.spec.ts.snap +590 -0
  25. package/src/ts/mcp-server/generator.js +4 -18
  26. package/src/ts/mcp-server/generator.js.map +1 -1
  27. package/src/ts/mcp-server/schema.d.ts +1 -0
  28. package/src/ts/mcp-server/schema.json +8 -0
  29. package/src/ts/nx-plugin/generator.js +1 -0
  30. package/src/ts/nx-plugin/generator.js.map +1 -1
  31. package/src/utils/agent-core-constructs/agent-core-constructs.d.ts +11 -5
  32. package/src/utils/agent-core-constructs/agent-core-constructs.js +51 -10
  33. package/src/utils/agent-core-constructs/agent-core-constructs.js.map +1 -1
  34. package/src/utils/agent-core-constructs/files/terraform/app/agent-core/__nameKebabCase__/__nameKebabCase__.tf.template +46 -0
  35. package/src/utils/agent-core-constructs/files/terraform/core/agent-core/runtime.tf.template +536 -0
  36. package/src/utils/api-constructs/api-constructs.d.ts +4 -4
  37. package/src/utils/api-constructs/api-constructs.js +45 -5
  38. package/src/utils/api-constructs/api-constructs.js.map +1 -1
  39. package/src/utils/api-constructs/files/terraform/app/apis/http/__apiNameKebabCase__/__apiNameKebabCase__.tf.template +382 -0
  40. package/src/utils/api-constructs/files/terraform/app/apis/rest/__apiNameKebabCase__/__apiNameKebabCase__.tf.template +508 -0
  41. package/src/utils/api-constructs/files/terraform/core/api/http/http-api/http-api.tf.template +250 -0
  42. package/src/utils/api-constructs/files/terraform/core/api/rest/rest-api/rest-api.tf.template +150 -0
  43. package/src/utils/files/terraform/src/metrics/metrics.tf.template +3 -2
  44. package/src/utils/py.d.ts +5 -0
  45. package/src/utils/py.js +9 -1
  46. package/src/utils/py.js.map +1 -1
  47. package/src/utils/shared-constructs-constants.d.ts +2 -0
  48. package/src/utils/shared-constructs-constants.js +3 -1
  49. package/src/utils/shared-constructs-constants.js.map +1 -1
  50. package/src/utils/shared-constructs.js +2 -2
  51. package/src/utils/shared-constructs.js.map +1 -1
  52. package/src/utils/versions.d.ts +3 -1
  53. package/src/utils/versions.js +2 -0
  54. package/src/utils/versions.js.map +1 -1
  55. /package/src/utils/agent-core-constructs/files/{app → cdk/app}/agent-core/__nameKebabCase__/Dockerfile.template +0 -0
  56. /package/src/utils/agent-core-constructs/files/{app → cdk/app}/agent-core/__nameKebabCase__/__nameKebabCase__.ts.template +0 -0
  57. /package/src/utils/agent-core-constructs/files/{core → cdk/core}/agent-core/runtime.ts.template +0 -0
  58. /package/src/utils/api-constructs/files/{app → cdk/app}/apis/http/__apiNameKebabCase__.ts.template +0 -0
  59. /package/src/utils/api-constructs/files/{app → cdk/app}/apis/rest/__apiNameKebabCase__.ts.template +0 -0
  60. /package/src/utils/api-constructs/files/{core → cdk/core}/api/http/http-api.ts.template +0 -0
  61. /package/src/utils/api-constructs/files/{core → cdk/core}/api/rest/rest-api.ts.template +0 -0
  62. /package/src/utils/api-constructs/files/{core → cdk/core}/api/trpc/trpc-utils.ts.template +0 -0
  63. /package/src/utils/api-constructs/files/{core → cdk/core}/api/utils/utils.ts.template +0 -0
@@ -2015,3 +2015,3672 @@ export class IntegrationBuilder<
2015
2015
  }
2016
2016
  "
2017
2017
  `;
2018
+
2019
+ exports[`trpc backend generator > terraform iacProvider > should generate terraform files for HTTP API with Cognito auth and snapshot them > terraform-http-cognito-files 1`] = `
2020
+ {
2021
+ "http-api.tf": "# Core HTTP API Gateway module
2022
+ # This module creates the API Gateway HTTP API, stage, and logging resources
2023
+
2024
+ terraform {
2025
+ required_version = ">= 1.0"
2026
+
2027
+ required_providers {
2028
+ aws = {
2029
+ source = "hashicorp/aws"
2030
+ version = "~> 6.0"
2031
+ }
2032
+ }
2033
+ }
2034
+
2035
+ # Core HTTP API Gateway Variables
2036
+
2037
+ variable "api_name" {
2038
+ description = "Name of the HTTP API Gateway"
2039
+ type = string
2040
+ }
2041
+
2042
+ variable "api_description" {
2043
+ description = "Description of the HTTP API Gateway"
2044
+ type = string
2045
+ default = "HTTP API Gateway"
2046
+ }
2047
+
2048
+ variable "stage_name" {
2049
+ description = "Name of the API Gateway stage"
2050
+ type = string
2051
+ default = "prod"
2052
+ }
2053
+
2054
+ variable "stage_auto_deploy" {
2055
+ description = "Whether to automatically deploy the API stage"
2056
+ type = bool
2057
+ default = true
2058
+ }
2059
+
2060
+ # CORS Configuration
2061
+
2062
+ variable "cors_allow_credentials" {
2063
+ description = "Whether to allow credentials in CORS requests"
2064
+ type = bool
2065
+ default = false
2066
+ }
2067
+
2068
+ variable "cors_allow_headers" {
2069
+ description = "List of allowed headers for CORS"
2070
+ type = list(string)
2071
+ default = ["authorization", "content-type", "x-amz-content-sha256", "x-amz-date", "x-amz-security-token"]
2072
+ }
2073
+
2074
+ variable "cors_allow_methods" {
2075
+ description = "List of allowed HTTP methods for CORS"
2076
+ type = list(string)
2077
+ default = ["*"]
2078
+ }
2079
+
2080
+ variable "cors_allow_origins" {
2081
+ description = "List of allowed origins for CORS"
2082
+ type = list(string)
2083
+ default = ["*"]
2084
+ }
2085
+
2086
+ variable "cors_expose_headers" {
2087
+ description = "List of headers to expose in CORS responses"
2088
+ type = list(string)
2089
+ default = []
2090
+ }
2091
+
2092
+ variable "cors_max_age" {
2093
+ description = "Maximum age for CORS preflight requests in seconds"
2094
+ type = number
2095
+ default = 86400
2096
+ }
2097
+
2098
+ # Tags
2099
+
2100
+ variable "tags" {
2101
+ description = "Tags to apply to all resources"
2102
+ type = map(string)
2103
+ default = {}
2104
+ }
2105
+
2106
+ # Data sources
2107
+ data "aws_region" "current" {}
2108
+ data "aws_caller_identity" "current" {}
2109
+
2110
+ # Resources
2111
+
2112
+ # KMS key for CloudWatch log group encryption
2113
+ resource "aws_kms_key" "logs_key" {
2114
+ description = "KMS key for CloudWatch log group encryption"
2115
+ deletion_window_in_days = 7
2116
+ enable_key_rotation = true
2117
+
2118
+ policy = jsonencode({
2119
+ Version = "2012-10-17"
2120
+ Statement = [
2121
+ {
2122
+ Sid = "Enable IAM User Permissions"
2123
+ Effect = "Allow"
2124
+ Principal = {
2125
+ AWS = "arn:aws:iam::\${data.aws_caller_identity.current.account_id}:root"
2126
+ }
2127
+ Action = "kms:*"
2128
+ Resource = "*"
2129
+ },
2130
+ {
2131
+ Sid = "Allow CloudWatch Logs"
2132
+ Effect = "Allow"
2133
+ Principal = {
2134
+ Service = "logs.\${data.aws_region.current.name}.amazonaws.com"
2135
+ }
2136
+ Action = [
2137
+ "kms:Encrypt",
2138
+ "kms:Decrypt",
2139
+ "kms:ReEncrypt*",
2140
+ "kms:GenerateDataKey*",
2141
+ "kms:DescribeKey"
2142
+ ]
2143
+ Resource = "*"
2144
+ Condition = {
2145
+ ArnEquals = {
2146
+ "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}"
2147
+ }
2148
+ }
2149
+ }
2150
+ ]
2151
+ })
2152
+
2153
+ tags = var.tags
2154
+ }
2155
+
2156
+ resource "aws_kms_alias" "logs_key_alias" {
2157
+ name = "alias/\${var.api_name}-api-logs-encryption"
2158
+ target_key_id = aws_kms_key.logs_key.key_id
2159
+ }
2160
+
2161
+ # HTTP API Gateway
2162
+ resource "aws_apigatewayv2_api" "http_api" {
2163
+ name = var.api_name
2164
+ protocol_type = "HTTP"
2165
+ description = var.api_description
2166
+
2167
+ cors_configuration {
2168
+ allow_credentials = var.cors_allow_credentials
2169
+ allow_headers = var.cors_allow_headers
2170
+ allow_methods = var.cors_allow_methods
2171
+ allow_origins = var.cors_allow_origins
2172
+ expose_headers = var.cors_expose_headers
2173
+ max_age = var.cors_max_age
2174
+ }
2175
+
2176
+ tags = var.tags
2177
+ }
2178
+
2179
+ # API Gateway stage
2180
+ resource "aws_apigatewayv2_stage" "api_stage" {
2181
+ api_id = aws_apigatewayv2_api.http_api.id
2182
+ name = var.stage_name
2183
+ auto_deploy = var.stage_auto_deploy
2184
+
2185
+ access_log_settings {
2186
+ destination_arn = aws_cloudwatch_log_group.api_logs.arn
2187
+ format = jsonencode({
2188
+ requestId = "$context.requestId"
2189
+ ip = "$context.identity.sourceIp"
2190
+ requestTime = "$context.requestTime"
2191
+ httpMethod = "$context.httpMethod"
2192
+ routeKey = "$context.routeKey"
2193
+ status = "$context.status"
2194
+ protocol = "$context.protocol"
2195
+ responseLength = "$context.responseLength"
2196
+ error = "$context.error.message"
2197
+ integrationError = "$context.integrationErrorMessage"
2198
+ })
2199
+ }
2200
+
2201
+ default_route_settings {
2202
+ throttling_burst_limit = 5000
2203
+ throttling_rate_limit = 10000
2204
+ }
2205
+
2206
+ tags = var.tags
2207
+
2208
+ depends_on = [aws_cloudwatch_log_group.api_logs]
2209
+ }
2210
+
2211
+ # CloudWatch Log Group for API Gateway
2212
+ resource "aws_cloudwatch_log_group" "api_logs" {
2213
+ #checkov:skip=CKV_AWS_338:Log retention set to forever
2214
+ #checkov:skip=CKV_AWS_66:Log retention set to forever
2215
+ name = "/aws/apigateway/\${var.api_name}"
2216
+ kms_key_id = aws_kms_key.logs_key.arn
2217
+ tags = var.tags
2218
+ }
2219
+
2220
+ # Outputs
2221
+
2222
+ output "api_id" {
2223
+ description = "ID of the HTTP API Gateway"
2224
+ value = aws_apigatewayv2_api.http_api.id
2225
+ }
2226
+
2227
+ output "api_arn" {
2228
+ description = "ARN of the HTTP API Gateway"
2229
+ value = aws_apigatewayv2_api.http_api.arn
2230
+ }
2231
+
2232
+ output "api_endpoint" {
2233
+ description = "Base URL of the HTTP API Gateway"
2234
+ value = aws_apigatewayv2_api.http_api.api_endpoint
2235
+ }
2236
+
2237
+ output "api_execution_arn" {
2238
+ description = "Execution ARN of the HTTP API Gateway"
2239
+ value = aws_apigatewayv2_api.http_api.execution_arn
2240
+ }
2241
+
2242
+ output "stage_id" {
2243
+ description = "ID of the API Gateway stage"
2244
+ value = aws_apigatewayv2_stage.api_stage.id
2245
+ }
2246
+
2247
+ output "stage_arn" {
2248
+ description = "ARN of the API Gateway stage"
2249
+ value = aws_apigatewayv2_stage.api_stage.arn
2250
+ }
2251
+
2252
+ output "stage_execution_arn" {
2253
+ description = "Execution ARN of the API Gateway stage"
2254
+ value = aws_apigatewayv2_stage.api_stage.execution_arn
2255
+ }
2256
+
2257
+ output "stage_invoke_url" {
2258
+ description = "Invoke URL of the API Gateway stage"
2259
+ value = aws_apigatewayv2_stage.api_stage.invoke_url
2260
+ }
2261
+
2262
+ output "api_log_group_name" {
2263
+ description = "Name of the API Gateway CloudWatch log group"
2264
+ value = aws_cloudwatch_log_group.api_logs.name
2265
+ }
2266
+
2267
+ output "api_log_group_arn" {
2268
+ description = "ARN of the API Gateway CloudWatch log group"
2269
+ value = aws_cloudwatch_log_group.api_logs.arn
2270
+ }",
2271
+ "test-api.tf": "terraform {
2272
+ required_version = ">= 1.0"
2273
+
2274
+ required_providers {
2275
+ aws = {
2276
+ source = "hashicorp/aws"
2277
+ version = "~> 6.0"
2278
+ }
2279
+ }
2280
+ }
2281
+
2282
+ # Authentication Configuration
2283
+ variable "user_pool_id" {
2284
+ description = "Cognito User Pool ID for authentication"
2285
+ type = string
2286
+ }
2287
+
2288
+ variable "user_pool_client_ids" {
2289
+ description = "List of Cognito User Pool Client IDs"
2290
+ type = list(string)
2291
+ }
2292
+
2293
+ variable "env" {
2294
+ description = "Environment variables for the Lambda function"
2295
+ type = map(string)
2296
+ default = {}
2297
+ }
2298
+
2299
+ variable "additional_iam_policy_statements" {
2300
+ description = "Additional IAM policy statements for the Lambda function"
2301
+ type = list(object({
2302
+ Effect = string
2303
+ Action = list(string)
2304
+ Resource = list(string)
2305
+ }))
2306
+ default = []
2307
+ }
2308
+
2309
+ # CORS Configuration (passed to core module)
2310
+ variable "cors_allow_credentials" {
2311
+ description = "Whether to allow credentials in CORS requests"
2312
+ type = bool
2313
+ default = false
2314
+ }
2315
+
2316
+ variable "cors_allow_headers" {
2317
+ description = "List of allowed headers for CORS"
2318
+ type = list(string)
2319
+ default = ["authorization", "content-type", "x-amz-content-sha256", "x-amz-date", "x-amz-security-token"]
2320
+ }
2321
+
2322
+ variable "cors_allow_methods" {
2323
+ description = "List of allowed HTTP methods for CORS"
2324
+ type = list(string)
2325
+ default = ["*"]
2326
+ }
2327
+
2328
+ variable "cors_allow_origins" {
2329
+ description = "List of allowed origins for CORS"
2330
+ type = list(string)
2331
+ default = ["*"]
2332
+ }
2333
+
2334
+ variable "cors_expose_headers" {
2335
+ description = "List of headers to expose in CORS responses"
2336
+ type = list(string)
2337
+ default = []
2338
+ }
2339
+
2340
+ variable "cors_max_age" {
2341
+ description = "Maximum age for CORS preflight requests in seconds"
2342
+ type = number
2343
+ default = 0
2344
+ }
2345
+
2346
+ # Tags
2347
+ variable "tags" {
2348
+ description = "Tags to apply to all resources"
2349
+ type = map(string)
2350
+ default = {}
2351
+ }
2352
+
2353
+ # Get current AWS region and account ID
2354
+ data "aws_region" "current" {}
2355
+ data "aws_caller_identity" "current" {}
2356
+
2357
+ # Resources
2358
+
2359
+ # Create Lambda ZIP file from the bundle directory
2360
+ data "archive_file" "lambda_zip" {
2361
+ type = "zip"
2362
+ source_dir = "\${path.module}/../../../../../../../dist/apps/test-api/bundle"
2363
+ output_path = "\${path.module}/../../../../../../../dist/packages/common/terraform/apis/test-api/lambda.zip"
2364
+ }
2365
+
2366
+
2367
+ # Use the core HTTP API module
2368
+ module "http_api" {
2369
+ source = "../../../core/api/http-api"
2370
+
2371
+ api_name = "TestApi"
2372
+ api_description = "TestApi HTTP API"
2373
+ stage_name = "$default"
2374
+ stage_auto_deploy = true
2375
+
2376
+ # CORS Configuration
2377
+ cors_allow_credentials = var.cors_allow_credentials
2378
+ cors_allow_headers = var.cors_allow_headers
2379
+ cors_allow_methods = var.cors_allow_methods
2380
+ cors_allow_origins = var.cors_allow_origins
2381
+ cors_expose_headers = var.cors_expose_headers
2382
+ cors_max_age = var.cors_max_age
2383
+
2384
+ # Tags
2385
+ tags = var.tags
2386
+ }
2387
+
2388
+ # Lambda function
2389
+ # This configures a single "router" lambda to serve all requests
2390
+ resource "aws_lambda_function" "api_lambda" {
2391
+ #checkov:skip=CKV_AWS_117:Lambda function does not need to be in VPC for this use case
2392
+ #checkov:skip=CKV_AWS_116:Dead Letter Queue not required for this simple API use case
2393
+ #checkov:skip=CKV_AWS_272:Code signing not required for this use case
2394
+ #checkov:skip=CKV_AWS_115:Concurrent execution limit not required for this use case
2395
+ #checkov:skip=CKV_AWS_173:Lambda environment variables encrypted by managed key
2396
+ filename = data.archive_file.lambda_zip.output_path
2397
+ function_name = "TestApiHandler"
2398
+ role = aws_iam_role.lambda_execution_role.arn
2399
+ handler = "index.handler"
2400
+ runtime = "nodejs22.x"
2401
+ timeout = 30
2402
+ memory_size = 128
2403
+
2404
+ source_code_hash = data.archive_file.lambda_zip.output_base64sha256
2405
+
2406
+ # Enable X-Ray tracing
2407
+ tracing_config {
2408
+ mode = "Active"
2409
+ }
2410
+
2411
+ environment {
2412
+ variables = merge({
2413
+ AWS_CONNECTION_REUSE_ENABLED = "1"
2414
+ }, var.env)
2415
+ }
2416
+
2417
+ tags = var.tags
2418
+ }
2419
+
2420
+ # IAM role for Lambda execution
2421
+ resource "aws_iam_role" "lambda_execution_role" {
2422
+ name = "TestApiHandler-execution-role"
2423
+
2424
+ assume_role_policy = jsonencode({
2425
+ Version = "2012-10-17"
2426
+ Statement = [
2427
+ {
2428
+ Action = "sts:AssumeRole"
2429
+ Effect = "Allow"
2430
+ Principal = {
2431
+ Service = "lambda.amazonaws.com"
2432
+ }
2433
+ }
2434
+ ]
2435
+ })
2436
+
2437
+ tags = var.tags
2438
+ }
2439
+
2440
+ # Attach basic execution policy to Lambda role
2441
+ resource "aws_iam_role_policy_attachment" "lambda_basic_execution" {
2442
+ policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
2443
+ role = aws_iam_role.lambda_execution_role.name
2444
+ }
2445
+
2446
+ # Attach X-Ray tracing policy to Lambda role
2447
+ resource "aws_iam_role_policy_attachment" "lambda_xray_execution" {
2448
+ policy_arn = "arn:aws:iam::aws:policy/AWSXRayDaemonWriteAccess"
2449
+ role = aws_iam_role.lambda_execution_role.name
2450
+ }
2451
+
2452
+ # Additional IAM policies for Lambda (if provided)
2453
+ resource "aws_iam_role_policy" "lambda_additional_policies" {
2454
+ count = length(var.additional_iam_policy_statements) > 0 ? 1 : 0
2455
+ name = "TestApiHandler-additional-policies"
2456
+ role = aws_iam_role.lambda_execution_role.id
2457
+
2458
+ policy = jsonencode({
2459
+ Version = "2012-10-17"
2460
+ Statement = var.additional_iam_policy_statements
2461
+ })
2462
+ }
2463
+
2464
+ # CloudWatch Log Group for Lambda
2465
+ resource "aws_cloudwatch_log_group" "lambda_logs" {
2466
+ #checkov:skip=CKV_AWS_158:Using default CloudWatch log encryption
2467
+ #checkov:skip=CKV_AWS_338:Log retention set to forever
2468
+ #checkov:skip=CKV_AWS_66:Log retention set to forever
2469
+ name = "/aws/lambda/TestApiHandler"
2470
+ tags = var.tags
2471
+ }
2472
+
2473
+ # Cognito User Pool Authorizer
2474
+ resource "aws_apigatewayv2_authorizer" "cognito_authorizer" {
2475
+ api_id = module.http_api.api_id
2476
+ authorizer_type = "JWT"
2477
+ identity_sources = ["$request.header.Authorization"]
2478
+ name = "TestApiAuthorizer"
2479
+
2480
+ jwt_configuration {
2481
+ audience = var.user_pool_client_ids
2482
+ issuer = "https://cognito-idp.\${data.aws_region.current.name}.amazonaws.com/\${var.user_pool_id}"
2483
+ }
2484
+ }
2485
+
2486
+ # Lambda integration for HTTP API
2487
+ resource "aws_apigatewayv2_integration" "lambda_integration" {
2488
+ api_id = module.http_api.api_id
2489
+ integration_type = "AWS_PROXY"
2490
+ integration_uri = aws_lambda_function.api_lambda.invoke_arn
2491
+
2492
+ payload_format_version = "2.0"
2493
+ timeout_milliseconds = 30000
2494
+
2495
+ depends_on = [aws_lambda_function.api_lambda]
2496
+ }
2497
+
2498
+ # Route for proxy integration (catches all requests)
2499
+ resource "aws_apigatewayv2_route" "proxy_routes" {
2500
+ # NB: OPTIONS is omitted here since API Gateway manages responding to preflight requests
2501
+ # when cors settings are configured
2502
+ for_each = toset(["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD"])
2503
+
2504
+ api_id = module.http_api.api_id
2505
+ route_key = "\${each.key} /{proxy+}"
2506
+ target = "integrations/\${aws_apigatewayv2_integration.lambda_integration.id}"
2507
+
2508
+ authorization_type = "JWT"
2509
+ authorizer_id = aws_apigatewayv2_authorizer.cognito_authorizer.id
2510
+
2511
+ depends_on = [aws_apigatewayv2_integration.lambda_integration, aws_apigatewayv2_authorizer.cognito_authorizer]
2512
+ }
2513
+
2514
+ # Lambda permission for API Gateway to invoke the function
2515
+ resource "aws_lambda_permission" "api_gateway_invoke" {
2516
+ statement_id = "AllowExecutionFromAPIGateway"
2517
+ action = "lambda:InvokeFunction"
2518
+ function_name = aws_lambda_function.api_lambda.function_name
2519
+ principal = "apigateway.amazonaws.com"
2520
+ source_arn = "\${module.http_api.api_execution_arn}/*/*"
2521
+
2522
+ depends_on = [module.http_api, aws_lambda_function.api_lambda]
2523
+ }
2524
+
2525
+ # Outputs
2526
+
2527
+ # API Gateway Outputs (from core module)
2528
+ output "api_id" {
2529
+ description = "ID of the HTTP API Gateway"
2530
+ value = module.http_api.api_id
2531
+ }
2532
+
2533
+ output "api_arn" {
2534
+ description = "ARN of the HTTP API Gateway"
2535
+ value = module.http_api.api_arn
2536
+ }
2537
+
2538
+ output "api_endpoint" {
2539
+ description = "Base URL of the HTTP API Gateway"
2540
+ value = module.http_api.api_endpoint
2541
+ }
2542
+
2543
+ output "api_execution_arn" {
2544
+ description = "Execution ARN of the HTTP API Gateway"
2545
+ value = module.http_api.api_execution_arn
2546
+ }
2547
+
2548
+ output "stage_invoke_url" {
2549
+ description = "Invoke URL of the API Gateway stage"
2550
+ value = module.http_api.stage_invoke_url
2551
+ }
2552
+
2553
+ output "stage_arn" {
2554
+ description = "ARN of the API Gateway stage"
2555
+ value = module.http_api.stage_arn
2556
+ }
2557
+
2558
+ output "stage_execution_arn" {
2559
+ description = "Execution ARN of the API Gateway stage"
2560
+ value = module.http_api.stage_execution_arn
2561
+ }
2562
+
2563
+ # Lambda Function Outputs
2564
+ output "lambda_function_name" {
2565
+ description = "Name of the Lambda function"
2566
+ value = aws_lambda_function.api_lambda.function_name
2567
+ }
2568
+
2569
+ output "lambda_function_arn" {
2570
+ description = "ARN of the Lambda function"
2571
+ value = aws_lambda_function.api_lambda.arn
2572
+ }
2573
+
2574
+ output "lambda_invoke_arn" {
2575
+ description = "Invoke ARN of the Lambda function"
2576
+ value = aws_lambda_function.api_lambda.invoke_arn
2577
+ }
2578
+
2579
+ output "lambda_qualified_arn" {
2580
+ description = "Qualified ARN of the Lambda function"
2581
+ value = aws_lambda_function.api_lambda.qualified_arn
2582
+ }
2583
+
2584
+ output "lambda_version" {
2585
+ description = "Version of the Lambda function"
2586
+ value = aws_lambda_function.api_lambda.version
2587
+ }
2588
+
2589
+ output "lambda_source_code_hash" {
2590
+ description = "Base64-encoded SHA256 hash of the Lambda deployment package"
2591
+ value = aws_lambda_function.api_lambda.source_code_hash
2592
+ }
2593
+
2594
+ output "lambda_source_code_size" {
2595
+ description = "Size of the Lambda deployment package in bytes"
2596
+ value = aws_lambda_function.api_lambda.source_code_size
2597
+ }
2598
+
2599
+ # IAM Role Outputs
2600
+ output "lambda_execution_role_arn" {
2601
+ description = "ARN of the Lambda execution role"
2602
+ value = aws_iam_role.lambda_execution_role.arn
2603
+ }
2604
+
2605
+ output "lambda_execution_role_name" {
2606
+ description = "Name of the Lambda execution role"
2607
+ value = aws_iam_role.lambda_execution_role.name
2608
+ }
2609
+
2610
+ # Integration Outputs
2611
+ output "integration_id" {
2612
+ description = "ID of the Lambda integration"
2613
+ value = aws_apigatewayv2_integration.lambda_integration.id
2614
+ }
2615
+
2616
+ # CloudWatch Log Groups
2617
+ output "lambda_log_group_name" {
2618
+ description = "Name of the Lambda CloudWatch log group"
2619
+ value = aws_cloudwatch_log_group.lambda_logs.name
2620
+ }
2621
+
2622
+ output "lambda_log_group_arn" {
2623
+ description = "ARN of the Lambda CloudWatch log group"
2624
+ value = aws_cloudwatch_log_group.lambda_logs.arn
2625
+ }
2626
+
2627
+ output "api_log_group_name" {
2628
+ description = "Name of the API Gateway CloudWatch log group"
2629
+ value = module.http_api.api_log_group_name
2630
+ }
2631
+
2632
+ output "api_log_group_arn" {
2633
+ description = "ARN of the API Gateway CloudWatch log group"
2634
+ value = module.http_api.api_log_group_arn
2635
+ }",
2636
+ }
2637
+ `;
2638
+
2639
+ exports[`trpc backend generator > terraform iacProvider > should generate terraform files for HTTP API with IAM auth and snapshot them > terraform-http-iam-files 1`] = `
2640
+ {
2641
+ "http-api.tf": "# Core HTTP API Gateway module
2642
+ # This module creates the API Gateway HTTP API, stage, and logging resources
2643
+
2644
+ terraform {
2645
+ required_version = ">= 1.0"
2646
+
2647
+ required_providers {
2648
+ aws = {
2649
+ source = "hashicorp/aws"
2650
+ version = "~> 6.0"
2651
+ }
2652
+ }
2653
+ }
2654
+
2655
+ # Core HTTP API Gateway Variables
2656
+
2657
+ variable "api_name" {
2658
+ description = "Name of the HTTP API Gateway"
2659
+ type = string
2660
+ }
2661
+
2662
+ variable "api_description" {
2663
+ description = "Description of the HTTP API Gateway"
2664
+ type = string
2665
+ default = "HTTP API Gateway"
2666
+ }
2667
+
2668
+ variable "stage_name" {
2669
+ description = "Name of the API Gateway stage"
2670
+ type = string
2671
+ default = "prod"
2672
+ }
2673
+
2674
+ variable "stage_auto_deploy" {
2675
+ description = "Whether to automatically deploy the API stage"
2676
+ type = bool
2677
+ default = true
2678
+ }
2679
+
2680
+ # CORS Configuration
2681
+
2682
+ variable "cors_allow_credentials" {
2683
+ description = "Whether to allow credentials in CORS requests"
2684
+ type = bool
2685
+ default = false
2686
+ }
2687
+
2688
+ variable "cors_allow_headers" {
2689
+ description = "List of allowed headers for CORS"
2690
+ type = list(string)
2691
+ default = ["authorization", "content-type", "x-amz-content-sha256", "x-amz-date", "x-amz-security-token"]
2692
+ }
2693
+
2694
+ variable "cors_allow_methods" {
2695
+ description = "List of allowed HTTP methods for CORS"
2696
+ type = list(string)
2697
+ default = ["*"]
2698
+ }
2699
+
2700
+ variable "cors_allow_origins" {
2701
+ description = "List of allowed origins for CORS"
2702
+ type = list(string)
2703
+ default = ["*"]
2704
+ }
2705
+
2706
+ variable "cors_expose_headers" {
2707
+ description = "List of headers to expose in CORS responses"
2708
+ type = list(string)
2709
+ default = []
2710
+ }
2711
+
2712
+ variable "cors_max_age" {
2713
+ description = "Maximum age for CORS preflight requests in seconds"
2714
+ type = number
2715
+ default = 86400
2716
+ }
2717
+
2718
+ # Tags
2719
+
2720
+ variable "tags" {
2721
+ description = "Tags to apply to all resources"
2722
+ type = map(string)
2723
+ default = {}
2724
+ }
2725
+
2726
+ # Data sources
2727
+ data "aws_region" "current" {}
2728
+ data "aws_caller_identity" "current" {}
2729
+
2730
+ # Resources
2731
+
2732
+ # KMS key for CloudWatch log group encryption
2733
+ resource "aws_kms_key" "logs_key" {
2734
+ description = "KMS key for CloudWatch log group encryption"
2735
+ deletion_window_in_days = 7
2736
+ enable_key_rotation = true
2737
+
2738
+ policy = jsonencode({
2739
+ Version = "2012-10-17"
2740
+ Statement = [
2741
+ {
2742
+ Sid = "Enable IAM User Permissions"
2743
+ Effect = "Allow"
2744
+ Principal = {
2745
+ AWS = "arn:aws:iam::\${data.aws_caller_identity.current.account_id}:root"
2746
+ }
2747
+ Action = "kms:*"
2748
+ Resource = "*"
2749
+ },
2750
+ {
2751
+ Sid = "Allow CloudWatch Logs"
2752
+ Effect = "Allow"
2753
+ Principal = {
2754
+ Service = "logs.\${data.aws_region.current.name}.amazonaws.com"
2755
+ }
2756
+ Action = [
2757
+ "kms:Encrypt",
2758
+ "kms:Decrypt",
2759
+ "kms:ReEncrypt*",
2760
+ "kms:GenerateDataKey*",
2761
+ "kms:DescribeKey"
2762
+ ]
2763
+ Resource = "*"
2764
+ Condition = {
2765
+ ArnEquals = {
2766
+ "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}"
2767
+ }
2768
+ }
2769
+ }
2770
+ ]
2771
+ })
2772
+
2773
+ tags = var.tags
2774
+ }
2775
+
2776
+ resource "aws_kms_alias" "logs_key_alias" {
2777
+ name = "alias/\${var.api_name}-api-logs-encryption"
2778
+ target_key_id = aws_kms_key.logs_key.key_id
2779
+ }
2780
+
2781
+ # HTTP API Gateway
2782
+ resource "aws_apigatewayv2_api" "http_api" {
2783
+ name = var.api_name
2784
+ protocol_type = "HTTP"
2785
+ description = var.api_description
2786
+
2787
+ cors_configuration {
2788
+ allow_credentials = var.cors_allow_credentials
2789
+ allow_headers = var.cors_allow_headers
2790
+ allow_methods = var.cors_allow_methods
2791
+ allow_origins = var.cors_allow_origins
2792
+ expose_headers = var.cors_expose_headers
2793
+ max_age = var.cors_max_age
2794
+ }
2795
+
2796
+ tags = var.tags
2797
+ }
2798
+
2799
+ # API Gateway stage
2800
+ resource "aws_apigatewayv2_stage" "api_stage" {
2801
+ api_id = aws_apigatewayv2_api.http_api.id
2802
+ name = var.stage_name
2803
+ auto_deploy = var.stage_auto_deploy
2804
+
2805
+ access_log_settings {
2806
+ destination_arn = aws_cloudwatch_log_group.api_logs.arn
2807
+ format = jsonencode({
2808
+ requestId = "$context.requestId"
2809
+ ip = "$context.identity.sourceIp"
2810
+ requestTime = "$context.requestTime"
2811
+ httpMethod = "$context.httpMethod"
2812
+ routeKey = "$context.routeKey"
2813
+ status = "$context.status"
2814
+ protocol = "$context.protocol"
2815
+ responseLength = "$context.responseLength"
2816
+ error = "$context.error.message"
2817
+ integrationError = "$context.integrationErrorMessage"
2818
+ })
2819
+ }
2820
+
2821
+ default_route_settings {
2822
+ throttling_burst_limit = 5000
2823
+ throttling_rate_limit = 10000
2824
+ }
2825
+
2826
+ tags = var.tags
2827
+
2828
+ depends_on = [aws_cloudwatch_log_group.api_logs]
2829
+ }
2830
+
2831
+ # CloudWatch Log Group for API Gateway
2832
+ resource "aws_cloudwatch_log_group" "api_logs" {
2833
+ #checkov:skip=CKV_AWS_338:Log retention set to forever
2834
+ #checkov:skip=CKV_AWS_66:Log retention set to forever
2835
+ name = "/aws/apigateway/\${var.api_name}"
2836
+ kms_key_id = aws_kms_key.logs_key.arn
2837
+ tags = var.tags
2838
+ }
2839
+
2840
+ # Outputs
2841
+
2842
+ output "api_id" {
2843
+ description = "ID of the HTTP API Gateway"
2844
+ value = aws_apigatewayv2_api.http_api.id
2845
+ }
2846
+
2847
+ output "api_arn" {
2848
+ description = "ARN of the HTTP API Gateway"
2849
+ value = aws_apigatewayv2_api.http_api.arn
2850
+ }
2851
+
2852
+ output "api_endpoint" {
2853
+ description = "Base URL of the HTTP API Gateway"
2854
+ value = aws_apigatewayv2_api.http_api.api_endpoint
2855
+ }
2856
+
2857
+ output "api_execution_arn" {
2858
+ description = "Execution ARN of the HTTP API Gateway"
2859
+ value = aws_apigatewayv2_api.http_api.execution_arn
2860
+ }
2861
+
2862
+ output "stage_id" {
2863
+ description = "ID of the API Gateway stage"
2864
+ value = aws_apigatewayv2_stage.api_stage.id
2865
+ }
2866
+
2867
+ output "stage_arn" {
2868
+ description = "ARN of the API Gateway stage"
2869
+ value = aws_apigatewayv2_stage.api_stage.arn
2870
+ }
2871
+
2872
+ output "stage_execution_arn" {
2873
+ description = "Execution ARN of the API Gateway stage"
2874
+ value = aws_apigatewayv2_stage.api_stage.execution_arn
2875
+ }
2876
+
2877
+ output "stage_invoke_url" {
2878
+ description = "Invoke URL of the API Gateway stage"
2879
+ value = aws_apigatewayv2_stage.api_stage.invoke_url
2880
+ }
2881
+
2882
+ output "api_log_group_name" {
2883
+ description = "Name of the API Gateway CloudWatch log group"
2884
+ value = aws_cloudwatch_log_group.api_logs.name
2885
+ }
2886
+
2887
+ output "api_log_group_arn" {
2888
+ description = "ARN of the API Gateway CloudWatch log group"
2889
+ value = aws_cloudwatch_log_group.api_logs.arn
2890
+ }",
2891
+ "test-api.tf": "terraform {
2892
+ required_version = ">= 1.0"
2893
+
2894
+ required_providers {
2895
+ aws = {
2896
+ source = "hashicorp/aws"
2897
+ version = "~> 6.0"
2898
+ }
2899
+ }
2900
+ }
2901
+
2902
+
2903
+ variable "env" {
2904
+ description = "Environment variables for the Lambda function"
2905
+ type = map(string)
2906
+ default = {}
2907
+ }
2908
+
2909
+ variable "additional_iam_policy_statements" {
2910
+ description = "Additional IAM policy statements for the Lambda function"
2911
+ type = list(object({
2912
+ Effect = string
2913
+ Action = list(string)
2914
+ Resource = list(string)
2915
+ }))
2916
+ default = []
2917
+ }
2918
+
2919
+ # CORS Configuration (passed to core module)
2920
+ variable "cors_allow_credentials" {
2921
+ description = "Whether to allow credentials in CORS requests"
2922
+ type = bool
2923
+ default = false
2924
+ }
2925
+
2926
+ variable "cors_allow_headers" {
2927
+ description = "List of allowed headers for CORS"
2928
+ type = list(string)
2929
+ default = ["authorization", "content-type", "x-amz-content-sha256", "x-amz-date", "x-amz-security-token"]
2930
+ }
2931
+
2932
+ variable "cors_allow_methods" {
2933
+ description = "List of allowed HTTP methods for CORS"
2934
+ type = list(string)
2935
+ default = ["*"]
2936
+ }
2937
+
2938
+ variable "cors_allow_origins" {
2939
+ description = "List of allowed origins for CORS"
2940
+ type = list(string)
2941
+ default = ["*"]
2942
+ }
2943
+
2944
+ variable "cors_expose_headers" {
2945
+ description = "List of headers to expose in CORS responses"
2946
+ type = list(string)
2947
+ default = []
2948
+ }
2949
+
2950
+ variable "cors_max_age" {
2951
+ description = "Maximum age for CORS preflight requests in seconds"
2952
+ type = number
2953
+ default = 0
2954
+ }
2955
+
2956
+ # Tags
2957
+ variable "tags" {
2958
+ description = "Tags to apply to all resources"
2959
+ type = map(string)
2960
+ default = {}
2961
+ }
2962
+
2963
+ # Get current AWS region and account ID
2964
+ data "aws_region" "current" {}
2965
+ data "aws_caller_identity" "current" {}
2966
+
2967
+ # Resources
2968
+
2969
+ # Create Lambda ZIP file from the bundle directory
2970
+ data "archive_file" "lambda_zip" {
2971
+ type = "zip"
2972
+ source_dir = "\${path.module}/../../../../../../../dist/apps/test-api/bundle"
2973
+ output_path = "\${path.module}/../../../../../../../dist/packages/common/terraform/apis/test-api/lambda.zip"
2974
+ }
2975
+
2976
+
2977
+ # Use the core HTTP API module
2978
+ module "http_api" {
2979
+ source = "../../../core/api/http-api"
2980
+
2981
+ api_name = "TestApi"
2982
+ api_description = "TestApi HTTP API"
2983
+ stage_name = "$default"
2984
+ stage_auto_deploy = true
2985
+
2986
+ # CORS Configuration
2987
+ cors_allow_credentials = var.cors_allow_credentials
2988
+ cors_allow_headers = var.cors_allow_headers
2989
+ cors_allow_methods = var.cors_allow_methods
2990
+ cors_allow_origins = var.cors_allow_origins
2991
+ cors_expose_headers = var.cors_expose_headers
2992
+ cors_max_age = var.cors_max_age
2993
+
2994
+ # Tags
2995
+ tags = var.tags
2996
+ }
2997
+
2998
+ # Lambda function
2999
+ # This configures a single "router" lambda to serve all requests
3000
+ resource "aws_lambda_function" "api_lambda" {
3001
+ #checkov:skip=CKV_AWS_117:Lambda function does not need to be in VPC for this use case
3002
+ #checkov:skip=CKV_AWS_116:Dead Letter Queue not required for this simple API use case
3003
+ #checkov:skip=CKV_AWS_272:Code signing not required for this use case
3004
+ #checkov:skip=CKV_AWS_115:Concurrent execution limit not required for this use case
3005
+ #checkov:skip=CKV_AWS_173:Lambda environment variables encrypted by managed key
3006
+ filename = data.archive_file.lambda_zip.output_path
3007
+ function_name = "TestApiHandler"
3008
+ role = aws_iam_role.lambda_execution_role.arn
3009
+ handler = "index.handler"
3010
+ runtime = "nodejs22.x"
3011
+ timeout = 30
3012
+ memory_size = 128
3013
+
3014
+ source_code_hash = data.archive_file.lambda_zip.output_base64sha256
3015
+
3016
+ # Enable X-Ray tracing
3017
+ tracing_config {
3018
+ mode = "Active"
3019
+ }
3020
+
3021
+ environment {
3022
+ variables = merge({
3023
+ AWS_CONNECTION_REUSE_ENABLED = "1"
3024
+ }, var.env)
3025
+ }
3026
+
3027
+ tags = var.tags
3028
+ }
3029
+
3030
+ # IAM role for Lambda execution
3031
+ resource "aws_iam_role" "lambda_execution_role" {
3032
+ name = "TestApiHandler-execution-role"
3033
+
3034
+ assume_role_policy = jsonencode({
3035
+ Version = "2012-10-17"
3036
+ Statement = [
3037
+ {
3038
+ Action = "sts:AssumeRole"
3039
+ Effect = "Allow"
3040
+ Principal = {
3041
+ Service = "lambda.amazonaws.com"
3042
+ }
3043
+ }
3044
+ ]
3045
+ })
3046
+
3047
+ tags = var.tags
3048
+ }
3049
+
3050
+ # Attach basic execution policy to Lambda role
3051
+ resource "aws_iam_role_policy_attachment" "lambda_basic_execution" {
3052
+ policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
3053
+ role = aws_iam_role.lambda_execution_role.name
3054
+ }
3055
+
3056
+ # Attach X-Ray tracing policy to Lambda role
3057
+ resource "aws_iam_role_policy_attachment" "lambda_xray_execution" {
3058
+ policy_arn = "arn:aws:iam::aws:policy/AWSXRayDaemonWriteAccess"
3059
+ role = aws_iam_role.lambda_execution_role.name
3060
+ }
3061
+
3062
+ # Additional IAM policies for Lambda (if provided)
3063
+ resource "aws_iam_role_policy" "lambda_additional_policies" {
3064
+ count = length(var.additional_iam_policy_statements) > 0 ? 1 : 0
3065
+ name = "TestApiHandler-additional-policies"
3066
+ role = aws_iam_role.lambda_execution_role.id
3067
+
3068
+ policy = jsonencode({
3069
+ Version = "2012-10-17"
3070
+ Statement = var.additional_iam_policy_statements
3071
+ })
3072
+ }
3073
+
3074
+ # CloudWatch Log Group for Lambda
3075
+ resource "aws_cloudwatch_log_group" "lambda_logs" {
3076
+ #checkov:skip=CKV_AWS_158:Using default CloudWatch log encryption
3077
+ #checkov:skip=CKV_AWS_338:Log retention set to forever
3078
+ #checkov:skip=CKV_AWS_66:Log retention set to forever
3079
+ name = "/aws/lambda/TestApiHandler"
3080
+ tags = var.tags
3081
+ }
3082
+
3083
+
3084
+ # Lambda integration for HTTP API
3085
+ resource "aws_apigatewayv2_integration" "lambda_integration" {
3086
+ api_id = module.http_api.api_id
3087
+ integration_type = "AWS_PROXY"
3088
+ integration_uri = aws_lambda_function.api_lambda.invoke_arn
3089
+
3090
+ payload_format_version = "2.0"
3091
+ timeout_milliseconds = 30000
3092
+
3093
+ depends_on = [aws_lambda_function.api_lambda]
3094
+ }
3095
+
3096
+ # Route for proxy integration (catches all requests)
3097
+ resource "aws_apigatewayv2_route" "proxy_routes" {
3098
+ # NB: OPTIONS is omitted here since API Gateway manages responding to preflight requests
3099
+ # when cors settings are configured
3100
+ for_each = toset(["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD"])
3101
+
3102
+ api_id = module.http_api.api_id
3103
+ route_key = "\${each.key} /{proxy+}"
3104
+ target = "integrations/\${aws_apigatewayv2_integration.lambda_integration.id}"
3105
+
3106
+ authorization_type = "AWS_IAM"
3107
+
3108
+ depends_on = [aws_apigatewayv2_integration.lambda_integration]
3109
+ }
3110
+
3111
+ # Lambda permission for API Gateway to invoke the function
3112
+ resource "aws_lambda_permission" "api_gateway_invoke" {
3113
+ statement_id = "AllowExecutionFromAPIGateway"
3114
+ action = "lambda:InvokeFunction"
3115
+ function_name = aws_lambda_function.api_lambda.function_name
3116
+ principal = "apigateway.amazonaws.com"
3117
+ source_arn = "\${module.http_api.api_execution_arn}/*/*"
3118
+
3119
+ depends_on = [module.http_api, aws_lambda_function.api_lambda]
3120
+ }
3121
+
3122
+ # Outputs
3123
+
3124
+ # API Gateway Outputs (from core module)
3125
+ output "api_id" {
3126
+ description = "ID of the HTTP API Gateway"
3127
+ value = module.http_api.api_id
3128
+ }
3129
+
3130
+ output "api_arn" {
3131
+ description = "ARN of the HTTP API Gateway"
3132
+ value = module.http_api.api_arn
3133
+ }
3134
+
3135
+ output "api_endpoint" {
3136
+ description = "Base URL of the HTTP API Gateway"
3137
+ value = module.http_api.api_endpoint
3138
+ }
3139
+
3140
+ output "api_execution_arn" {
3141
+ description = "Execution ARN of the HTTP API Gateway"
3142
+ value = module.http_api.api_execution_arn
3143
+ }
3144
+
3145
+ output "stage_invoke_url" {
3146
+ description = "Invoke URL of the API Gateway stage"
3147
+ value = module.http_api.stage_invoke_url
3148
+ }
3149
+
3150
+ output "stage_arn" {
3151
+ description = "ARN of the API Gateway stage"
3152
+ value = module.http_api.stage_arn
3153
+ }
3154
+
3155
+ output "stage_execution_arn" {
3156
+ description = "Execution ARN of the API Gateway stage"
3157
+ value = module.http_api.stage_execution_arn
3158
+ }
3159
+
3160
+ # Lambda Function Outputs
3161
+ output "lambda_function_name" {
3162
+ description = "Name of the Lambda function"
3163
+ value = aws_lambda_function.api_lambda.function_name
3164
+ }
3165
+
3166
+ output "lambda_function_arn" {
3167
+ description = "ARN of the Lambda function"
3168
+ value = aws_lambda_function.api_lambda.arn
3169
+ }
3170
+
3171
+ output "lambda_invoke_arn" {
3172
+ description = "Invoke ARN of the Lambda function"
3173
+ value = aws_lambda_function.api_lambda.invoke_arn
3174
+ }
3175
+
3176
+ output "lambda_qualified_arn" {
3177
+ description = "Qualified ARN of the Lambda function"
3178
+ value = aws_lambda_function.api_lambda.qualified_arn
3179
+ }
3180
+
3181
+ output "lambda_version" {
3182
+ description = "Version of the Lambda function"
3183
+ value = aws_lambda_function.api_lambda.version
3184
+ }
3185
+
3186
+ output "lambda_source_code_hash" {
3187
+ description = "Base64-encoded SHA256 hash of the Lambda deployment package"
3188
+ value = aws_lambda_function.api_lambda.source_code_hash
3189
+ }
3190
+
3191
+ output "lambda_source_code_size" {
3192
+ description = "Size of the Lambda deployment package in bytes"
3193
+ value = aws_lambda_function.api_lambda.source_code_size
3194
+ }
3195
+
3196
+ # IAM Role Outputs
3197
+ output "lambda_execution_role_arn" {
3198
+ description = "ARN of the Lambda execution role"
3199
+ value = aws_iam_role.lambda_execution_role.arn
3200
+ }
3201
+
3202
+ output "lambda_execution_role_name" {
3203
+ description = "Name of the Lambda execution role"
3204
+ value = aws_iam_role.lambda_execution_role.name
3205
+ }
3206
+
3207
+ # Integration Outputs
3208
+ output "integration_id" {
3209
+ description = "ID of the Lambda integration"
3210
+ value = aws_apigatewayv2_integration.lambda_integration.id
3211
+ }
3212
+
3213
+ # CloudWatch Log Groups
3214
+ output "lambda_log_group_name" {
3215
+ description = "Name of the Lambda CloudWatch log group"
3216
+ value = aws_cloudwatch_log_group.lambda_logs.name
3217
+ }
3218
+
3219
+ output "lambda_log_group_arn" {
3220
+ description = "ARN of the Lambda CloudWatch log group"
3221
+ value = aws_cloudwatch_log_group.lambda_logs.arn
3222
+ }
3223
+
3224
+ output "api_log_group_name" {
3225
+ description = "Name of the API Gateway CloudWatch log group"
3226
+ value = module.http_api.api_log_group_name
3227
+ }
3228
+
3229
+ output "api_log_group_arn" {
3230
+ description = "ARN of the API Gateway CloudWatch log group"
3231
+ value = module.http_api.api_log_group_arn
3232
+ }",
3233
+ }
3234
+ `;
3235
+
3236
+ exports[`trpc backend generator > terraform iacProvider > should generate terraform files for HTTP API with None auth and snapshot them > terraform-http-none-files 1`] = `
3237
+ {
3238
+ "http-api.tf": "# Core HTTP API Gateway module
3239
+ # This module creates the API Gateway HTTP API, stage, and logging resources
3240
+
3241
+ terraform {
3242
+ required_version = ">= 1.0"
3243
+
3244
+ required_providers {
3245
+ aws = {
3246
+ source = "hashicorp/aws"
3247
+ version = "~> 6.0"
3248
+ }
3249
+ }
3250
+ }
3251
+
3252
+ # Core HTTP API Gateway Variables
3253
+
3254
+ variable "api_name" {
3255
+ description = "Name of the HTTP API Gateway"
3256
+ type = string
3257
+ }
3258
+
3259
+ variable "api_description" {
3260
+ description = "Description of the HTTP API Gateway"
3261
+ type = string
3262
+ default = "HTTP API Gateway"
3263
+ }
3264
+
3265
+ variable "stage_name" {
3266
+ description = "Name of the API Gateway stage"
3267
+ type = string
3268
+ default = "prod"
3269
+ }
3270
+
3271
+ variable "stage_auto_deploy" {
3272
+ description = "Whether to automatically deploy the API stage"
3273
+ type = bool
3274
+ default = true
3275
+ }
3276
+
3277
+ # CORS Configuration
3278
+
3279
+ variable "cors_allow_credentials" {
3280
+ description = "Whether to allow credentials in CORS requests"
3281
+ type = bool
3282
+ default = false
3283
+ }
3284
+
3285
+ variable "cors_allow_headers" {
3286
+ description = "List of allowed headers for CORS"
3287
+ type = list(string)
3288
+ default = ["authorization", "content-type", "x-amz-content-sha256", "x-amz-date", "x-amz-security-token"]
3289
+ }
3290
+
3291
+ variable "cors_allow_methods" {
3292
+ description = "List of allowed HTTP methods for CORS"
3293
+ type = list(string)
3294
+ default = ["*"]
3295
+ }
3296
+
3297
+ variable "cors_allow_origins" {
3298
+ description = "List of allowed origins for CORS"
3299
+ type = list(string)
3300
+ default = ["*"]
3301
+ }
3302
+
3303
+ variable "cors_expose_headers" {
3304
+ description = "List of headers to expose in CORS responses"
3305
+ type = list(string)
3306
+ default = []
3307
+ }
3308
+
3309
+ variable "cors_max_age" {
3310
+ description = "Maximum age for CORS preflight requests in seconds"
3311
+ type = number
3312
+ default = 86400
3313
+ }
3314
+
3315
+ # Tags
3316
+
3317
+ variable "tags" {
3318
+ description = "Tags to apply to all resources"
3319
+ type = map(string)
3320
+ default = {}
3321
+ }
3322
+
3323
+ # Data sources
3324
+ data "aws_region" "current" {}
3325
+ data "aws_caller_identity" "current" {}
3326
+
3327
+ # Resources
3328
+
3329
+ # KMS key for CloudWatch log group encryption
3330
+ resource "aws_kms_key" "logs_key" {
3331
+ description = "KMS key for CloudWatch log group encryption"
3332
+ deletion_window_in_days = 7
3333
+ enable_key_rotation = true
3334
+
3335
+ policy = jsonencode({
3336
+ Version = "2012-10-17"
3337
+ Statement = [
3338
+ {
3339
+ Sid = "Enable IAM User Permissions"
3340
+ Effect = "Allow"
3341
+ Principal = {
3342
+ AWS = "arn:aws:iam::\${data.aws_caller_identity.current.account_id}:root"
3343
+ }
3344
+ Action = "kms:*"
3345
+ Resource = "*"
3346
+ },
3347
+ {
3348
+ Sid = "Allow CloudWatch Logs"
3349
+ Effect = "Allow"
3350
+ Principal = {
3351
+ Service = "logs.\${data.aws_region.current.name}.amazonaws.com"
3352
+ }
3353
+ Action = [
3354
+ "kms:Encrypt",
3355
+ "kms:Decrypt",
3356
+ "kms:ReEncrypt*",
3357
+ "kms:GenerateDataKey*",
3358
+ "kms:DescribeKey"
3359
+ ]
3360
+ Resource = "*"
3361
+ Condition = {
3362
+ ArnEquals = {
3363
+ "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}"
3364
+ }
3365
+ }
3366
+ }
3367
+ ]
3368
+ })
3369
+
3370
+ tags = var.tags
3371
+ }
3372
+
3373
+ resource "aws_kms_alias" "logs_key_alias" {
3374
+ name = "alias/\${var.api_name}-api-logs-encryption"
3375
+ target_key_id = aws_kms_key.logs_key.key_id
3376
+ }
3377
+
3378
+ # HTTP API Gateway
3379
+ resource "aws_apigatewayv2_api" "http_api" {
3380
+ name = var.api_name
3381
+ protocol_type = "HTTP"
3382
+ description = var.api_description
3383
+
3384
+ cors_configuration {
3385
+ allow_credentials = var.cors_allow_credentials
3386
+ allow_headers = var.cors_allow_headers
3387
+ allow_methods = var.cors_allow_methods
3388
+ allow_origins = var.cors_allow_origins
3389
+ expose_headers = var.cors_expose_headers
3390
+ max_age = var.cors_max_age
3391
+ }
3392
+
3393
+ tags = var.tags
3394
+ }
3395
+
3396
+ # API Gateway stage
3397
+ resource "aws_apigatewayv2_stage" "api_stage" {
3398
+ api_id = aws_apigatewayv2_api.http_api.id
3399
+ name = var.stage_name
3400
+ auto_deploy = var.stage_auto_deploy
3401
+
3402
+ access_log_settings {
3403
+ destination_arn = aws_cloudwatch_log_group.api_logs.arn
3404
+ format = jsonencode({
3405
+ requestId = "$context.requestId"
3406
+ ip = "$context.identity.sourceIp"
3407
+ requestTime = "$context.requestTime"
3408
+ httpMethod = "$context.httpMethod"
3409
+ routeKey = "$context.routeKey"
3410
+ status = "$context.status"
3411
+ protocol = "$context.protocol"
3412
+ responseLength = "$context.responseLength"
3413
+ error = "$context.error.message"
3414
+ integrationError = "$context.integrationErrorMessage"
3415
+ })
3416
+ }
3417
+
3418
+ default_route_settings {
3419
+ throttling_burst_limit = 5000
3420
+ throttling_rate_limit = 10000
3421
+ }
3422
+
3423
+ tags = var.tags
3424
+
3425
+ depends_on = [aws_cloudwatch_log_group.api_logs]
3426
+ }
3427
+
3428
+ # CloudWatch Log Group for API Gateway
3429
+ resource "aws_cloudwatch_log_group" "api_logs" {
3430
+ #checkov:skip=CKV_AWS_338:Log retention set to forever
3431
+ #checkov:skip=CKV_AWS_66:Log retention set to forever
3432
+ name = "/aws/apigateway/\${var.api_name}"
3433
+ kms_key_id = aws_kms_key.logs_key.arn
3434
+ tags = var.tags
3435
+ }
3436
+
3437
+ # Outputs
3438
+
3439
+ output "api_id" {
3440
+ description = "ID of the HTTP API Gateway"
3441
+ value = aws_apigatewayv2_api.http_api.id
3442
+ }
3443
+
3444
+ output "api_arn" {
3445
+ description = "ARN of the HTTP API Gateway"
3446
+ value = aws_apigatewayv2_api.http_api.arn
3447
+ }
3448
+
3449
+ output "api_endpoint" {
3450
+ description = "Base URL of the HTTP API Gateway"
3451
+ value = aws_apigatewayv2_api.http_api.api_endpoint
3452
+ }
3453
+
3454
+ output "api_execution_arn" {
3455
+ description = "Execution ARN of the HTTP API Gateway"
3456
+ value = aws_apigatewayv2_api.http_api.execution_arn
3457
+ }
3458
+
3459
+ output "stage_id" {
3460
+ description = "ID of the API Gateway stage"
3461
+ value = aws_apigatewayv2_stage.api_stage.id
3462
+ }
3463
+
3464
+ output "stage_arn" {
3465
+ description = "ARN of the API Gateway stage"
3466
+ value = aws_apigatewayv2_stage.api_stage.arn
3467
+ }
3468
+
3469
+ output "stage_execution_arn" {
3470
+ description = "Execution ARN of the API Gateway stage"
3471
+ value = aws_apigatewayv2_stage.api_stage.execution_arn
3472
+ }
3473
+
3474
+ output "stage_invoke_url" {
3475
+ description = "Invoke URL of the API Gateway stage"
3476
+ value = aws_apigatewayv2_stage.api_stage.invoke_url
3477
+ }
3478
+
3479
+ output "api_log_group_name" {
3480
+ description = "Name of the API Gateway CloudWatch log group"
3481
+ value = aws_cloudwatch_log_group.api_logs.name
3482
+ }
3483
+
3484
+ output "api_log_group_arn" {
3485
+ description = "ARN of the API Gateway CloudWatch log group"
3486
+ value = aws_cloudwatch_log_group.api_logs.arn
3487
+ }",
3488
+ "test-api.tf": "terraform {
3489
+ required_version = ">= 1.0"
3490
+
3491
+ required_providers {
3492
+ aws = {
3493
+ source = "hashicorp/aws"
3494
+ version = "~> 6.0"
3495
+ }
3496
+ }
3497
+ }
3498
+
3499
+
3500
+ variable "env" {
3501
+ description = "Environment variables for the Lambda function"
3502
+ type = map(string)
3503
+ default = {}
3504
+ }
3505
+
3506
+ variable "additional_iam_policy_statements" {
3507
+ description = "Additional IAM policy statements for the Lambda function"
3508
+ type = list(object({
3509
+ Effect = string
3510
+ Action = list(string)
3511
+ Resource = list(string)
3512
+ }))
3513
+ default = []
3514
+ }
3515
+
3516
+ # CORS Configuration (passed to core module)
3517
+ variable "cors_allow_credentials" {
3518
+ description = "Whether to allow credentials in CORS requests"
3519
+ type = bool
3520
+ default = false
3521
+ }
3522
+
3523
+ variable "cors_allow_headers" {
3524
+ description = "List of allowed headers for CORS"
3525
+ type = list(string)
3526
+ default = ["authorization", "content-type", "x-amz-content-sha256", "x-amz-date", "x-amz-security-token"]
3527
+ }
3528
+
3529
+ variable "cors_allow_methods" {
3530
+ description = "List of allowed HTTP methods for CORS"
3531
+ type = list(string)
3532
+ default = ["*"]
3533
+ }
3534
+
3535
+ variable "cors_allow_origins" {
3536
+ description = "List of allowed origins for CORS"
3537
+ type = list(string)
3538
+ default = ["*"]
3539
+ }
3540
+
3541
+ variable "cors_expose_headers" {
3542
+ description = "List of headers to expose in CORS responses"
3543
+ type = list(string)
3544
+ default = []
3545
+ }
3546
+
3547
+ variable "cors_max_age" {
3548
+ description = "Maximum age for CORS preflight requests in seconds"
3549
+ type = number
3550
+ default = 0
3551
+ }
3552
+
3553
+ # Tags
3554
+ variable "tags" {
3555
+ description = "Tags to apply to all resources"
3556
+ type = map(string)
3557
+ default = {}
3558
+ }
3559
+
3560
+ # Get current AWS region and account ID
3561
+ data "aws_region" "current" {}
3562
+ data "aws_caller_identity" "current" {}
3563
+
3564
+ # Resources
3565
+
3566
+ # Create Lambda ZIP file from the bundle directory
3567
+ data "archive_file" "lambda_zip" {
3568
+ type = "zip"
3569
+ source_dir = "\${path.module}/../../../../../../../dist/apps/test-api/bundle"
3570
+ output_path = "\${path.module}/../../../../../../../dist/packages/common/terraform/apis/test-api/lambda.zip"
3571
+ }
3572
+
3573
+
3574
+ # Use the core HTTP API module
3575
+ module "http_api" {
3576
+ source = "../../../core/api/http-api"
3577
+
3578
+ api_name = "TestApi"
3579
+ api_description = "TestApi HTTP API"
3580
+ stage_name = "$default"
3581
+ stage_auto_deploy = true
3582
+
3583
+ # CORS Configuration
3584
+ cors_allow_credentials = var.cors_allow_credentials
3585
+ cors_allow_headers = var.cors_allow_headers
3586
+ cors_allow_methods = var.cors_allow_methods
3587
+ cors_allow_origins = var.cors_allow_origins
3588
+ cors_expose_headers = var.cors_expose_headers
3589
+ cors_max_age = var.cors_max_age
3590
+
3591
+ # Tags
3592
+ tags = var.tags
3593
+ }
3594
+
3595
+ # Lambda function
3596
+ # This configures a single "router" lambda to serve all requests
3597
+ resource "aws_lambda_function" "api_lambda" {
3598
+ #checkov:skip=CKV_AWS_117:Lambda function does not need to be in VPC for this use case
3599
+ #checkov:skip=CKV_AWS_116:Dead Letter Queue not required for this simple API use case
3600
+ #checkov:skip=CKV_AWS_272:Code signing not required for this use case
3601
+ #checkov:skip=CKV_AWS_115:Concurrent execution limit not required for this use case
3602
+ #checkov:skip=CKV_AWS_173:Lambda environment variables encrypted by managed key
3603
+ filename = data.archive_file.lambda_zip.output_path
3604
+ function_name = "TestApiHandler"
3605
+ role = aws_iam_role.lambda_execution_role.arn
3606
+ handler = "index.handler"
3607
+ runtime = "nodejs22.x"
3608
+ timeout = 30
3609
+ memory_size = 128
3610
+
3611
+ source_code_hash = data.archive_file.lambda_zip.output_base64sha256
3612
+
3613
+ # Enable X-Ray tracing
3614
+ tracing_config {
3615
+ mode = "Active"
3616
+ }
3617
+
3618
+ environment {
3619
+ variables = merge({
3620
+ AWS_CONNECTION_REUSE_ENABLED = "1"
3621
+ }, var.env)
3622
+ }
3623
+
3624
+ tags = var.tags
3625
+ }
3626
+
3627
+ # IAM role for Lambda execution
3628
+ resource "aws_iam_role" "lambda_execution_role" {
3629
+ name = "TestApiHandler-execution-role"
3630
+
3631
+ assume_role_policy = jsonencode({
3632
+ Version = "2012-10-17"
3633
+ Statement = [
3634
+ {
3635
+ Action = "sts:AssumeRole"
3636
+ Effect = "Allow"
3637
+ Principal = {
3638
+ Service = "lambda.amazonaws.com"
3639
+ }
3640
+ }
3641
+ ]
3642
+ })
3643
+
3644
+ tags = var.tags
3645
+ }
3646
+
3647
+ # Attach basic execution policy to Lambda role
3648
+ resource "aws_iam_role_policy_attachment" "lambda_basic_execution" {
3649
+ policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
3650
+ role = aws_iam_role.lambda_execution_role.name
3651
+ }
3652
+
3653
+ # Attach X-Ray tracing policy to Lambda role
3654
+ resource "aws_iam_role_policy_attachment" "lambda_xray_execution" {
3655
+ policy_arn = "arn:aws:iam::aws:policy/AWSXRayDaemonWriteAccess"
3656
+ role = aws_iam_role.lambda_execution_role.name
3657
+ }
3658
+
3659
+ # Additional IAM policies for Lambda (if provided)
3660
+ resource "aws_iam_role_policy" "lambda_additional_policies" {
3661
+ count = length(var.additional_iam_policy_statements) > 0 ? 1 : 0
3662
+ name = "TestApiHandler-additional-policies"
3663
+ role = aws_iam_role.lambda_execution_role.id
3664
+
3665
+ policy = jsonencode({
3666
+ Version = "2012-10-17"
3667
+ Statement = var.additional_iam_policy_statements
3668
+ })
3669
+ }
3670
+
3671
+ # CloudWatch Log Group for Lambda
3672
+ resource "aws_cloudwatch_log_group" "lambda_logs" {
3673
+ #checkov:skip=CKV_AWS_158:Using default CloudWatch log encryption
3674
+ #checkov:skip=CKV_AWS_338:Log retention set to forever
3675
+ #checkov:skip=CKV_AWS_66:Log retention set to forever
3676
+ name = "/aws/lambda/TestApiHandler"
3677
+ tags = var.tags
3678
+ }
3679
+
3680
+
3681
+ # Lambda integration for HTTP API
3682
+ resource "aws_apigatewayv2_integration" "lambda_integration" {
3683
+ api_id = module.http_api.api_id
3684
+ integration_type = "AWS_PROXY"
3685
+ integration_uri = aws_lambda_function.api_lambda.invoke_arn
3686
+
3687
+ payload_format_version = "2.0"
3688
+ timeout_milliseconds = 30000
3689
+
3690
+ depends_on = [aws_lambda_function.api_lambda]
3691
+ }
3692
+
3693
+ # Route for proxy integration (catches all requests)
3694
+ resource "aws_apigatewayv2_route" "proxy_routes" {
3695
+ # NB: OPTIONS is omitted here since API Gateway manages responding to preflight requests
3696
+ # when cors settings are configured
3697
+ for_each = toset(["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD"])
3698
+
3699
+ api_id = module.http_api.api_id
3700
+ route_key = "\${each.key} /{proxy+}"
3701
+ target = "integrations/\${aws_apigatewayv2_integration.lambda_integration.id}"
3702
+
3703
+ # Note: you may wish to suppress the checkov rule CKV_AWS_309 if you are absolutely sure you
3704
+ # need a public API without authentication
3705
+ authorization_type = "NONE"
3706
+
3707
+ depends_on = [aws_apigatewayv2_integration.lambda_integration]
3708
+ }
3709
+
3710
+ # Lambda permission for API Gateway to invoke the function
3711
+ resource "aws_lambda_permission" "api_gateway_invoke" {
3712
+ statement_id = "AllowExecutionFromAPIGateway"
3713
+ action = "lambda:InvokeFunction"
3714
+ function_name = aws_lambda_function.api_lambda.function_name
3715
+ principal = "apigateway.amazonaws.com"
3716
+ source_arn = "\${module.http_api.api_execution_arn}/*/*"
3717
+
3718
+ depends_on = [module.http_api, aws_lambda_function.api_lambda]
3719
+ }
3720
+
3721
+ # Outputs
3722
+
3723
+ # API Gateway Outputs (from core module)
3724
+ output "api_id" {
3725
+ description = "ID of the HTTP API Gateway"
3726
+ value = module.http_api.api_id
3727
+ }
3728
+
3729
+ output "api_arn" {
3730
+ description = "ARN of the HTTP API Gateway"
3731
+ value = module.http_api.api_arn
3732
+ }
3733
+
3734
+ output "api_endpoint" {
3735
+ description = "Base URL of the HTTP API Gateway"
3736
+ value = module.http_api.api_endpoint
3737
+ }
3738
+
3739
+ output "api_execution_arn" {
3740
+ description = "Execution ARN of the HTTP API Gateway"
3741
+ value = module.http_api.api_execution_arn
3742
+ }
3743
+
3744
+ output "stage_invoke_url" {
3745
+ description = "Invoke URL of the API Gateway stage"
3746
+ value = module.http_api.stage_invoke_url
3747
+ }
3748
+
3749
+ output "stage_arn" {
3750
+ description = "ARN of the API Gateway stage"
3751
+ value = module.http_api.stage_arn
3752
+ }
3753
+
3754
+ output "stage_execution_arn" {
3755
+ description = "Execution ARN of the API Gateway stage"
3756
+ value = module.http_api.stage_execution_arn
3757
+ }
3758
+
3759
+ # Lambda Function Outputs
3760
+ output "lambda_function_name" {
3761
+ description = "Name of the Lambda function"
3762
+ value = aws_lambda_function.api_lambda.function_name
3763
+ }
3764
+
3765
+ output "lambda_function_arn" {
3766
+ description = "ARN of the Lambda function"
3767
+ value = aws_lambda_function.api_lambda.arn
3768
+ }
3769
+
3770
+ output "lambda_invoke_arn" {
3771
+ description = "Invoke ARN of the Lambda function"
3772
+ value = aws_lambda_function.api_lambda.invoke_arn
3773
+ }
3774
+
3775
+ output "lambda_qualified_arn" {
3776
+ description = "Qualified ARN of the Lambda function"
3777
+ value = aws_lambda_function.api_lambda.qualified_arn
3778
+ }
3779
+
3780
+ output "lambda_version" {
3781
+ description = "Version of the Lambda function"
3782
+ value = aws_lambda_function.api_lambda.version
3783
+ }
3784
+
3785
+ output "lambda_source_code_hash" {
3786
+ description = "Base64-encoded SHA256 hash of the Lambda deployment package"
3787
+ value = aws_lambda_function.api_lambda.source_code_hash
3788
+ }
3789
+
3790
+ output "lambda_source_code_size" {
3791
+ description = "Size of the Lambda deployment package in bytes"
3792
+ value = aws_lambda_function.api_lambda.source_code_size
3793
+ }
3794
+
3795
+ # IAM Role Outputs
3796
+ output "lambda_execution_role_arn" {
3797
+ description = "ARN of the Lambda execution role"
3798
+ value = aws_iam_role.lambda_execution_role.arn
3799
+ }
3800
+
3801
+ output "lambda_execution_role_name" {
3802
+ description = "Name of the Lambda execution role"
3803
+ value = aws_iam_role.lambda_execution_role.name
3804
+ }
3805
+
3806
+ # Integration Outputs
3807
+ output "integration_id" {
3808
+ description = "ID of the Lambda integration"
3809
+ value = aws_apigatewayv2_integration.lambda_integration.id
3810
+ }
3811
+
3812
+ # CloudWatch Log Groups
3813
+ output "lambda_log_group_name" {
3814
+ description = "Name of the Lambda CloudWatch log group"
3815
+ value = aws_cloudwatch_log_group.lambda_logs.name
3816
+ }
3817
+
3818
+ output "lambda_log_group_arn" {
3819
+ description = "ARN of the Lambda CloudWatch log group"
3820
+ value = aws_cloudwatch_log_group.lambda_logs.arn
3821
+ }
3822
+
3823
+ output "api_log_group_name" {
3824
+ description = "Name of the API Gateway CloudWatch log group"
3825
+ value = module.http_api.api_log_group_name
3826
+ }
3827
+
3828
+ output "api_log_group_arn" {
3829
+ description = "ARN of the API Gateway CloudWatch log group"
3830
+ value = module.http_api.api_log_group_arn
3831
+ }",
3832
+ }
3833
+ `;
3834
+
3835
+ exports[`trpc backend generator > terraform iacProvider > should generate terraform files for REST API with Cognito auth and snapshot them > terraform-rest-cognito-files 1`] = `
3836
+ {
3837
+ "rest-api.tf": "# Core REST API Gateway module
3838
+ # This module creates the API Gateway REST API, deployment, stage, and logging resources
3839
+
3840
+ terraform {
3841
+ required_version = ">= 1.0"
3842
+
3843
+ required_providers {
3844
+ aws = {
3845
+ source = "hashicorp/aws"
3846
+ version = "~> 6.0"
3847
+ }
3848
+ }
3849
+ }
3850
+
3851
+ # Core REST API Gateway Variables
3852
+
3853
+ variable "api_name" {
3854
+ description = "Name of the REST API Gateway"
3855
+ type = string
3856
+ }
3857
+
3858
+ variable "api_description" {
3859
+ description = "Description of the REST API Gateway"
3860
+ type = string
3861
+ default = "REST API Gateway"
3862
+ }
3863
+
3864
+ variable "stage_name" {
3865
+ description = "Name of the API Gateway stage"
3866
+ type = string
3867
+ default = "prod"
3868
+ }
3869
+
3870
+ variable "stage_auto_deploy" {
3871
+ description = "Whether to automatically deploy the API stage"
3872
+ type = bool
3873
+ default = true
3874
+ }
3875
+
3876
+ # CORS Configuration
3877
+
3878
+ variable "cors_allow_headers" {
3879
+ description = "List of allowed headers for CORS"
3880
+ type = list(string)
3881
+ default = ["authorization", "content-type", "x-amz-content-sha256", "x-amz-date", "x-amz-security-token"]
3882
+ }
3883
+
3884
+ variable "cors_allow_methods" {
3885
+ description = "List of allowed HTTP methods for CORS"
3886
+ type = list(string)
3887
+ default = ["*"]
3888
+ }
3889
+
3890
+ variable "cors_allow_origins" {
3891
+ description = "List of allowed origins for CORS"
3892
+ type = list(string)
3893
+ default = ["*"]
3894
+ }
3895
+
3896
+ # Tags
3897
+
3898
+ variable "tags" {
3899
+ description = "Tags to apply to all resources"
3900
+ type = map(string)
3901
+ default = {}
3902
+ }
3903
+
3904
+ # Data sources
3905
+ data "aws_region" "current" {}
3906
+ data "aws_caller_identity" "current" {}
3907
+
3908
+ # Resources
3909
+
3910
+ # Note: CloudWatch logging removed due to account-level CloudWatch Logs role ARN requirement
3911
+
3912
+ # REST API Gateway
3913
+ resource "aws_api_gateway_rest_api" "rest_api" {
3914
+ name = var.api_name
3915
+ description = var.api_description
3916
+
3917
+ endpoint_configuration {
3918
+ types = ["REGIONAL"]
3919
+ }
3920
+
3921
+ lifecycle {
3922
+ create_before_destroy = true
3923
+ }
3924
+
3925
+ tags = var.tags
3926
+ }
3927
+
3928
+ # Note: Deployment and stage are created in the consuming module (e.g., foo-api.tf)
3929
+ # after all methods and integrations are defined
3930
+
3931
+ # Note: CloudWatch Log Group removed due to account-level CloudWatch Logs role ARN requirement
3932
+
3933
+ # Gateway Response for CORS (4XX errors)
3934
+ resource "aws_api_gateway_gateway_response" "cors_4xx" {
3935
+ rest_api_id = aws_api_gateway_rest_api.rest_api.id
3936
+ response_type = "DEFAULT_4XX"
3937
+
3938
+ response_parameters = {
3939
+ "gatewayresponse.header.Access-Control-Allow-Origin" = "'\${join(",", var.cors_allow_origins)}'"
3940
+ "gatewayresponse.header.Access-Control-Allow-Headers" = "'\${join(",", var.cors_allow_headers)}'"
3941
+ "gatewayresponse.header.Access-Control-Allow-Methods" = "'\${join(",", var.cors_allow_methods)}'"
3942
+ }
3943
+ }
3944
+
3945
+ # Gateway Response for CORS (5XX errors)
3946
+ resource "aws_api_gateway_gateway_response" "cors_5xx" {
3947
+ rest_api_id = aws_api_gateway_rest_api.rest_api.id
3948
+ response_type = "DEFAULT_5XX"
3949
+
3950
+ response_parameters = {
3951
+ "gatewayresponse.header.Access-Control-Allow-Origin" = "'\${join(",", var.cors_allow_origins)}'"
3952
+ "gatewayresponse.header.Access-Control-Allow-Headers" = "'\${join(",", var.cors_allow_headers)}'"
3953
+ "gatewayresponse.header.Access-Control-Allow-Methods" = "'\${join(",", var.cors_allow_methods)}'"
3954
+ }
3955
+ }
3956
+
3957
+ # Outputs
3958
+
3959
+ output "api_id" {
3960
+ description = "ID of the REST API Gateway"
3961
+ value = aws_api_gateway_rest_api.rest_api.id
3962
+ }
3963
+
3964
+ output "api_arn" {
3965
+ description = "ARN of the REST API Gateway"
3966
+ value = aws_api_gateway_rest_api.rest_api.arn
3967
+ }
3968
+
3969
+ output "api_endpoint" {
3970
+ description = "Base URL of the REST API Gateway"
3971
+ value = "https://\${aws_api_gateway_rest_api.rest_api.id}.execute-api.\${data.aws_region.current.id}.amazonaws.com"
3972
+ }
3973
+
3974
+ output "api_execution_arn" {
3975
+ description = "Execution ARN of the REST API Gateway"
3976
+ value = aws_api_gateway_rest_api.rest_api.execution_arn
3977
+ }
3978
+
3979
+ output "api_root_resource_id" {
3980
+ description = "Root resource ID of the REST API Gateway"
3981
+ value = aws_api_gateway_rest_api.rest_api.root_resource_id
3982
+ }
3983
+
3984
+ # Note: Stage and deployment outputs are provided by the consuming module
3985
+
3986
+ # Note: CloudWatch log group outputs removed due to account-level CloudWatch Logs role ARN requirement",
3987
+ "test-api.tf": "terraform {
3988
+ required_version = ">= 1.0"
3989
+
3990
+ required_providers {
3991
+ aws = {
3992
+ source = "hashicorp/aws"
3993
+ version = "~> 6.0"
3994
+ }
3995
+ }
3996
+ }
3997
+
3998
+ # Authentication Configuration
3999
+ variable "user_pool_id" {
4000
+ description = "Cognito User Pool ID for authentication"
4001
+ type = string
4002
+ }
4003
+
4004
+ variable "user_pool_client_ids" {
4005
+ description = "List of Cognito User Pool Client IDs"
4006
+ type = list(string)
4007
+ }
4008
+
4009
+ variable "env" {
4010
+ description = "Environment variables for the Lambda function"
4011
+ type = map(string)
4012
+ default = {}
4013
+ }
4014
+
4015
+ variable "additional_iam_policy_statements" {
4016
+ description = "Additional IAM policy statements for the Lambda function"
4017
+ type = list(object({
4018
+ Effect = string
4019
+ Action = list(string)
4020
+ Resource = list(string)
4021
+ }))
4022
+ default = []
4023
+ }
4024
+
4025
+ # CORS Configuration (passed to core module)
4026
+
4027
+ variable "cors_allow_headers" {
4028
+ description = "List of allowed headers for CORS"
4029
+ type = list(string)
4030
+ default = ["authorization", "content-type", "x-amz-content-sha256", "x-amz-date", "x-amz-security-token"]
4031
+ }
4032
+
4033
+ variable "cors_allow_methods" {
4034
+ description = "List of allowed HTTP methods for CORS"
4035
+ type = list(string)
4036
+ default = ["*"]
4037
+ }
4038
+
4039
+ variable "cors_allow_origins" {
4040
+ description = "List of allowed origins for CORS"
4041
+ type = list(string)
4042
+ default = ["*"]
4043
+ }
4044
+
4045
+ # Tags
4046
+ variable "tags" {
4047
+ description = "Tags to apply to all resources"
4048
+ type = map(string)
4049
+ default = {}
4050
+ }
4051
+
4052
+ # Get current AWS region and account ID
4053
+ data "aws_region" "current" {}
4054
+ data "aws_caller_identity" "current" {}
4055
+
4056
+ # Resources
4057
+
4058
+ # Create Lambda ZIP file from the FastAPI bundle directory
4059
+ data "archive_file" "lambda_zip" {
4060
+ type = "zip"
4061
+ source_dir = "\${path.module}/../../../../../../../dist/apps/test-api/bundle"
4062
+ output_path = "\${path.module}/../../../../../../../dist/packages/common/terraform/apis/test-api/lambda.zip"
4063
+ }
4064
+
4065
+ # Use the core REST API module
4066
+ module "rest_api" {
4067
+ source = "../../../core/api/rest-api"
4068
+
4069
+ api_name = "TestApi"
4070
+ api_description = "TestApi REST API"
4071
+ stage_name = "prod"
4072
+ stage_auto_deploy = true
4073
+
4074
+ # CORS Configuration
4075
+ cors_allow_headers = var.cors_allow_headers
4076
+ cors_allow_methods = var.cors_allow_methods
4077
+ cors_allow_origins = var.cors_allow_origins
4078
+
4079
+ # Tags
4080
+ tags = var.tags
4081
+ }
4082
+
4083
+ # Lambda function
4084
+ resource "aws_lambda_function" "api_lambda" {
4085
+ #checkov:skip=CKV_AWS_117:Lambda function does not need to be in VPC for this use case
4086
+ #checkov:skip=CKV_AWS_116:Dead Letter Queue not required for this simple API use case
4087
+ #checkov:skip=CKV_AWS_272:Code signing not required for this use case
4088
+ #checkov:skip=CKV_AWS_115:Concurrent execution limit not required for this use case
4089
+ #checkov:skip=CKV_AWS_173:Lambda environment variables encrypted by managed key
4090
+ filename = data.archive_file.lambda_zip.output_path
4091
+ function_name = "TestApiHandler"
4092
+ role = aws_iam_role.lambda_execution_role.arn
4093
+ handler = "index.handler"
4094
+ runtime = "nodejs22.x"
4095
+ timeout = 30
4096
+ memory_size = 128
4097
+
4098
+ source_code_hash = data.archive_file.lambda_zip.output_base64sha256
4099
+
4100
+ # Enable X-Ray tracing
4101
+ tracing_config {
4102
+ mode = "Active"
4103
+ }
4104
+
4105
+ environment {
4106
+ variables = merge({
4107
+ AWS_CONNECTION_REUSE_ENABLED = "1"
4108
+ }, var.env)
4109
+ }
4110
+
4111
+ tags = var.tags
4112
+ }
4113
+
4114
+ # IAM role for Lambda execution
4115
+ resource "aws_iam_role" "lambda_execution_role" {
4116
+ name = "TestApiHandler-execution-role"
4117
+
4118
+ assume_role_policy = jsonencode({
4119
+ Version = "2012-10-17"
4120
+ Statement = [
4121
+ {
4122
+ Action = "sts:AssumeRole"
4123
+ Effect = "Allow"
4124
+ Principal = {
4125
+ Service = "lambda.amazonaws.com"
4126
+ }
4127
+ }
4128
+ ]
4129
+ })
4130
+
4131
+ tags = var.tags
4132
+ }
4133
+
4134
+ # Attach basic execution policy to Lambda role
4135
+ resource "aws_iam_role_policy_attachment" "lambda_basic_execution" {
4136
+ policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
4137
+ role = aws_iam_role.lambda_execution_role.name
4138
+ }
4139
+
4140
+ # Attach X-Ray tracing policy to Lambda role
4141
+ resource "aws_iam_role_policy_attachment" "lambda_xray_execution" {
4142
+ policy_arn = "arn:aws:iam::aws:policy/AWSXRayDaemonWriteAccess"
4143
+ role = aws_iam_role.lambda_execution_role.name
4144
+ }
4145
+
4146
+ # Additional IAM policies for Lambda (if provided)
4147
+ resource "aws_iam_role_policy" "lambda_additional_policies" {
4148
+ count = length(var.additional_iam_policy_statements) > 0 ? 1 : 0
4149
+ name = "TestApiHandler-additional-policies"
4150
+ role = aws_iam_role.lambda_execution_role.id
4151
+
4152
+ policy = jsonencode({
4153
+ Version = "2012-10-17"
4154
+ Statement = var.additional_iam_policy_statements
4155
+ })
4156
+ }
4157
+
4158
+ # CloudWatch Log Group for Lambda
4159
+ resource "aws_cloudwatch_log_group" "lambda_logs" {
4160
+ #checkov:skip=CKV_AWS_158:Using default CloudWatch log encryption
4161
+ #checkov:skip=CKV_AWS_338:Log retention set to forever
4162
+ #checkov:skip=CKV_AWS_66:Log retention set to forever
4163
+ name = "/aws/lambda/TestApiHandler"
4164
+ tags = var.tags
4165
+ }
4166
+
4167
+ # Cognito User Pool Authorizer
4168
+ resource "aws_api_gateway_authorizer" "cognito_authorizer" {
4169
+ name = "TestApiAuthorizer"
4170
+ rest_api_id = module.rest_api.api_id
4171
+ type = "COGNITO_USER_POOLS"
4172
+ provider_arns = ["arn:aws:cognito-idp:\${data.aws_region.current.name}:\${data.aws_caller_identity.current.account_id}:userpool/\${var.user_pool_id}"]
4173
+ identity_source = "method.request.header.Authorization"
4174
+ }
4175
+
4176
+ # Create proxy resource (captures all paths)
4177
+ resource "aws_api_gateway_resource" "proxy_resource" {
4178
+ rest_api_id = module.rest_api.api_id
4179
+ parent_id = module.rest_api.api_root_resource_id
4180
+ path_part = "{proxy+}"
4181
+ }
4182
+
4183
+ # Lambda integration for REST API
4184
+ resource "aws_api_gateway_integration" "lambda_integration" {
4185
+ rest_api_id = module.rest_api.api_id
4186
+ resource_id = aws_api_gateway_resource.proxy_resource.id
4187
+ http_method = aws_api_gateway_method.proxy_method.http_method
4188
+
4189
+ integration_http_method = "POST"
4190
+ type = "AWS_PROXY"
4191
+ uri = aws_lambda_function.api_lambda.invoke_arn
4192
+
4193
+ depends_on = [aws_lambda_function.api_lambda]
4194
+ }
4195
+
4196
+ # Method for proxy integration
4197
+ resource "aws_api_gateway_method" "proxy_method" {
4198
+ #checkov:skip=CKV2_AWS_53:Request validation not required for proxy integration as Lambda handles validation
4199
+ rest_api_id = module.rest_api.api_id
4200
+ resource_id = aws_api_gateway_resource.proxy_resource.id
4201
+ http_method = "ANY"
4202
+
4203
+ authorization = "COGNITO_USER_POOLS"
4204
+ authorizer_id = aws_api_gateway_authorizer.cognito_authorizer.id
4205
+
4206
+ request_parameters = {
4207
+ "method.request.path.proxy" = true
4208
+ }
4209
+
4210
+ depends_on = [aws_api_gateway_authorizer.cognito_authorizer]
4211
+ }
4212
+
4213
+ # OPTIONS method for CORS preflight
4214
+ resource "aws_api_gateway_method" "options_method" {
4215
+ #checkov:skip=CKV2_AWS_70:OPTIONS method must be unauthenticated for CORS preflight requests
4216
+ #checkov:skip=CKV2_AWS_53:Request validation not required for OPTIONS CORS preflight method
4217
+ rest_api_id = module.rest_api.api_id
4218
+ resource_id = aws_api_gateway_resource.proxy_resource.id
4219
+ http_method = "OPTIONS"
4220
+ authorization = "NONE"
4221
+ }
4222
+
4223
+ # CORS integration for OPTIONS method
4224
+ resource "aws_api_gateway_integration" "options_integration" {
4225
+ rest_api_id = module.rest_api.api_id
4226
+ resource_id = aws_api_gateway_resource.proxy_resource.id
4227
+ http_method = aws_api_gateway_method.options_method.http_method
4228
+
4229
+ type = "MOCK"
4230
+ request_templates = {
4231
+ "application/json" = "{\\"statusCode\\": 204}"
4232
+ }
4233
+ }
4234
+
4235
+ # OPTIONS method response
4236
+ resource "aws_api_gateway_method_response" "options_response" {
4237
+ rest_api_id = module.rest_api.api_id
4238
+ resource_id = aws_api_gateway_resource.proxy_resource.id
4239
+ http_method = aws_api_gateway_method.options_method.http_method
4240
+ status_code = "204"
4241
+
4242
+ response_parameters = {
4243
+ "method.response.header.Access-Control-Allow-Headers" = true
4244
+ "method.response.header.Access-Control-Allow-Methods" = true
4245
+ "method.response.header.Access-Control-Allow-Origin" = true
4246
+ }
4247
+ }
4248
+
4249
+ # OPTIONS integration response
4250
+ resource "aws_api_gateway_integration_response" "options_integration_response" {
4251
+ rest_api_id = module.rest_api.api_id
4252
+ resource_id = aws_api_gateway_resource.proxy_resource.id
4253
+ http_method = aws_api_gateway_method.options_method.http_method
4254
+ status_code = aws_api_gateway_method_response.options_response.status_code
4255
+
4256
+ response_parameters = {
4257
+ "method.response.header.Access-Control-Allow-Headers" = "'\${join(",", var.cors_allow_headers)}'"
4258
+ "method.response.header.Access-Control-Allow-Methods" = "'\${join(",", var.cors_allow_methods)}'"
4259
+ "method.response.header.Access-Control-Allow-Origin" = "'\${join(",", var.cors_allow_origins)}'"
4260
+ }
4261
+ }
4262
+
4263
+ # API Gateway deployment
4264
+ resource "aws_api_gateway_deployment" "api_deployment" {
4265
+ rest_api_id = module.rest_api.api_id
4266
+
4267
+ triggers = {
4268
+ redeployment = sha1(jsonencode([
4269
+ aws_api_gateway_resource.proxy_resource.id,
4270
+ aws_api_gateway_method.proxy_method.id,
4271
+ aws_api_gateway_integration.lambda_integration.id,
4272
+ aws_api_gateway_method.options_method.id,
4273
+ aws_api_gateway_integration.options_integration.id,
4274
+ ]))
4275
+ }
4276
+
4277
+ lifecycle {
4278
+ create_before_destroy = true
4279
+ }
4280
+
4281
+ depends_on = [
4282
+ aws_api_gateway_method.proxy_method,
4283
+ aws_api_gateway_integration.lambda_integration,
4284
+ aws_api_gateway_method.options_method,
4285
+ aws_api_gateway_integration.options_integration,
4286
+ aws_api_gateway_method_response.options_response,
4287
+ aws_api_gateway_integration_response.options_integration_response,
4288
+ ]
4289
+ }
4290
+
4291
+ # API Gateway stage
4292
+ resource "aws_api_gateway_stage" "api_stage" {
4293
+ #checkov:skip=CKV_AWS_120:API Gateway caching not required for this use case
4294
+ #checkov:skip=CKV_AWS_76:API Gateway access logging disabled due to account-level CloudWatch Logs role ARN requirement
4295
+ #checkov:skip=CKV2_AWS_4:API Gateway logging level not applicable as access logging is disabled
4296
+ #checkov:skip=CKV2_AWS_51:Client certificate authentication not required for this use case
4297
+ deployment_id = aws_api_gateway_deployment.api_deployment.id
4298
+ rest_api_id = module.rest_api.api_id
4299
+ stage_name = "prod"
4300
+ xray_tracing_enabled = true
4301
+
4302
+ tags = var.tags
4303
+
4304
+ depends_on = [aws_api_gateway_deployment.api_deployment]
4305
+ }
4306
+
4307
+ # API Gateway Resource Policy
4308
+ resource "aws_api_gateway_rest_api_policy" "api_policy" {
4309
+ rest_api_id = module.rest_api.api_id
4310
+
4311
+ policy = jsonencode({
4312
+ Version = "2012-10-17"
4313
+ Statement = [
4314
+ {
4315
+ # Allow all callers to invoke the API in the resource policy, since auth is handled by Cognito
4316
+ Effect = "Allow"
4317
+ Principal = "*"
4318
+ Action = "execute-api:Invoke"
4319
+ Resource = "execute-api:/*"
4320
+ }
4321
+ ]
4322
+ })
4323
+ }
4324
+
4325
+ # Lambda permission for API Gateway to invoke the function
4326
+ resource "aws_lambda_permission" "api_gateway_invoke" {
4327
+ statement_id = "AllowExecutionFromAPIGateway"
4328
+ action = "lambda:InvokeFunction"
4329
+ function_name = aws_lambda_function.api_lambda.function_name
4330
+ principal = "apigateway.amazonaws.com"
4331
+ source_arn = "\${module.rest_api.api_execution_arn}/*/*"
4332
+
4333
+ depends_on = [module.rest_api, aws_lambda_function.api_lambda]
4334
+ }
4335
+
4336
+ # Outputs
4337
+
4338
+ # API Gateway Outputs (from core module)
4339
+ output "api_id" {
4340
+ description = "ID of the REST API Gateway"
4341
+ value = module.rest_api.api_id
4342
+ }
4343
+
4344
+ output "api_arn" {
4345
+ description = "ARN of the REST API Gateway"
4346
+ value = module.rest_api.api_arn
4347
+ }
4348
+
4349
+ output "api_endpoint" {
4350
+ description = "Base URL of the REST API Gateway"
4351
+ value = module.rest_api.api_endpoint
4352
+ }
4353
+
4354
+ output "api_execution_arn" {
4355
+ description = "Execution ARN of the REST API Gateway"
4356
+ value = module.rest_api.api_execution_arn
4357
+ }
4358
+
4359
+ output "stage_invoke_url" {
4360
+ description = "Invoke URL of the API Gateway stage"
4361
+ value = aws_api_gateway_stage.api_stage.invoke_url
4362
+ }
4363
+
4364
+ output "stage_arn" {
4365
+ description = "ARN of the API Gateway stage"
4366
+ value = aws_api_gateway_stage.api_stage.arn
4367
+ }
4368
+
4369
+ output "stage_execution_arn" {
4370
+ description = "Execution ARN of the API Gateway stage"
4371
+ value = aws_api_gateway_stage.api_stage.execution_arn
4372
+ }
4373
+
4374
+ output "deployment_id" {
4375
+ description = "ID of the API Gateway deployment"
4376
+ value = aws_api_gateway_deployment.api_deployment.id
4377
+ }
4378
+
4379
+ output "stage_id" {
4380
+ description = "ID of the API Gateway stage"
4381
+ value = aws_api_gateway_stage.api_stage.id
4382
+ }
4383
+
4384
+ # Lambda Function Outputs
4385
+ output "lambda_function_name" {
4386
+ description = "Name of the Lambda function"
4387
+ value = aws_lambda_function.api_lambda.function_name
4388
+ }
4389
+
4390
+ output "lambda_function_arn" {
4391
+ description = "ARN of the Lambda function"
4392
+ value = aws_lambda_function.api_lambda.arn
4393
+ }
4394
+
4395
+ output "lambda_invoke_arn" {
4396
+ description = "Invoke ARN of the Lambda function"
4397
+ value = aws_lambda_function.api_lambda.invoke_arn
4398
+ }
4399
+
4400
+ output "lambda_qualified_arn" {
4401
+ description = "Qualified ARN of the Lambda function"
4402
+ value = aws_lambda_function.api_lambda.qualified_arn
4403
+ }
4404
+
4405
+ output "lambda_version" {
4406
+ description = "Version of the Lambda function"
4407
+ value = aws_lambda_function.api_lambda.version
4408
+ }
4409
+
4410
+ output "lambda_source_code_hash" {
4411
+ description = "Base64-encoded SHA256 hash of the Lambda deployment package"
4412
+ value = aws_lambda_function.api_lambda.source_code_hash
4413
+ }
4414
+
4415
+ output "lambda_source_code_size" {
4416
+ description = "Size of the Lambda deployment package in bytes"
4417
+ value = aws_lambda_function.api_lambda.source_code_size
4418
+ }
4419
+
4420
+ # IAM Role Outputs
4421
+ output "lambda_execution_role_arn" {
4422
+ description = "ARN of the Lambda execution role"
4423
+ value = aws_iam_role.lambda_execution_role.arn
4424
+ }
4425
+
4426
+ output "lambda_execution_role_name" {
4427
+ description = "Name of the Lambda execution role"
4428
+ value = aws_iam_role.lambda_execution_role.name
4429
+ }
4430
+
4431
+ # Integration Outputs
4432
+ output "integration_id" {
4433
+ description = "ID of the Lambda integration"
4434
+ value = aws_api_gateway_integration.lambda_integration.id
4435
+ }
4436
+
4437
+ output "proxy_resource_id" {
4438
+ description = "ID of the proxy resource"
4439
+ value = aws_api_gateway_resource.proxy_resource.id
4440
+ }
4441
+
4442
+ output "proxy_method_id" {
4443
+ description = "ID of the proxy method"
4444
+ value = aws_api_gateway_method.proxy_method.id
4445
+ }
4446
+
4447
+ # CloudWatch Log Groups
4448
+ output "lambda_log_group_name" {
4449
+ description = "Name of the Lambda CloudWatch log group"
4450
+ value = aws_cloudwatch_log_group.lambda_logs.name
4451
+ }
4452
+
4453
+ output "lambda_log_group_arn" {
4454
+ description = "ARN of the Lambda CloudWatch log group"
4455
+ value = aws_cloudwatch_log_group.lambda_logs.arn
4456
+ }
4457
+ ",
4458
+ }
4459
+ `;
4460
+
4461
+ exports[`trpc backend generator > terraform iacProvider > should generate terraform files for REST API with IAM auth and snapshot them > terraform-rest-iam-files 1`] = `
4462
+ {
4463
+ "rest-api.tf": "# Core REST API Gateway module
4464
+ # This module creates the API Gateway REST API, deployment, stage, and logging resources
4465
+
4466
+ terraform {
4467
+ required_version = ">= 1.0"
4468
+
4469
+ required_providers {
4470
+ aws = {
4471
+ source = "hashicorp/aws"
4472
+ version = "~> 6.0"
4473
+ }
4474
+ }
4475
+ }
4476
+
4477
+ # Core REST API Gateway Variables
4478
+
4479
+ variable "api_name" {
4480
+ description = "Name of the REST API Gateway"
4481
+ type = string
4482
+ }
4483
+
4484
+ variable "api_description" {
4485
+ description = "Description of the REST API Gateway"
4486
+ type = string
4487
+ default = "REST API Gateway"
4488
+ }
4489
+
4490
+ variable "stage_name" {
4491
+ description = "Name of the API Gateway stage"
4492
+ type = string
4493
+ default = "prod"
4494
+ }
4495
+
4496
+ variable "stage_auto_deploy" {
4497
+ description = "Whether to automatically deploy the API stage"
4498
+ type = bool
4499
+ default = true
4500
+ }
4501
+
4502
+ # CORS Configuration
4503
+
4504
+ variable "cors_allow_headers" {
4505
+ description = "List of allowed headers for CORS"
4506
+ type = list(string)
4507
+ default = ["authorization", "content-type", "x-amz-content-sha256", "x-amz-date", "x-amz-security-token"]
4508
+ }
4509
+
4510
+ variable "cors_allow_methods" {
4511
+ description = "List of allowed HTTP methods for CORS"
4512
+ type = list(string)
4513
+ default = ["*"]
4514
+ }
4515
+
4516
+ variable "cors_allow_origins" {
4517
+ description = "List of allowed origins for CORS"
4518
+ type = list(string)
4519
+ default = ["*"]
4520
+ }
4521
+
4522
+ # Tags
4523
+
4524
+ variable "tags" {
4525
+ description = "Tags to apply to all resources"
4526
+ type = map(string)
4527
+ default = {}
4528
+ }
4529
+
4530
+ # Data sources
4531
+ data "aws_region" "current" {}
4532
+ data "aws_caller_identity" "current" {}
4533
+
4534
+ # Resources
4535
+
4536
+ # Note: CloudWatch logging removed due to account-level CloudWatch Logs role ARN requirement
4537
+
4538
+ # REST API Gateway
4539
+ resource "aws_api_gateway_rest_api" "rest_api" {
4540
+ name = var.api_name
4541
+ description = var.api_description
4542
+
4543
+ endpoint_configuration {
4544
+ types = ["REGIONAL"]
4545
+ }
4546
+
4547
+ lifecycle {
4548
+ create_before_destroy = true
4549
+ }
4550
+
4551
+ tags = var.tags
4552
+ }
4553
+
4554
+ # Note: Deployment and stage are created in the consuming module (e.g., foo-api.tf)
4555
+ # after all methods and integrations are defined
4556
+
4557
+ # Note: CloudWatch Log Group removed due to account-level CloudWatch Logs role ARN requirement
4558
+
4559
+ # Gateway Response for CORS (4XX errors)
4560
+ resource "aws_api_gateway_gateway_response" "cors_4xx" {
4561
+ rest_api_id = aws_api_gateway_rest_api.rest_api.id
4562
+ response_type = "DEFAULT_4XX"
4563
+
4564
+ response_parameters = {
4565
+ "gatewayresponse.header.Access-Control-Allow-Origin" = "'\${join(",", var.cors_allow_origins)}'"
4566
+ "gatewayresponse.header.Access-Control-Allow-Headers" = "'\${join(",", var.cors_allow_headers)}'"
4567
+ "gatewayresponse.header.Access-Control-Allow-Methods" = "'\${join(",", var.cors_allow_methods)}'"
4568
+ }
4569
+ }
4570
+
4571
+ # Gateway Response for CORS (5XX errors)
4572
+ resource "aws_api_gateway_gateway_response" "cors_5xx" {
4573
+ rest_api_id = aws_api_gateway_rest_api.rest_api.id
4574
+ response_type = "DEFAULT_5XX"
4575
+
4576
+ response_parameters = {
4577
+ "gatewayresponse.header.Access-Control-Allow-Origin" = "'\${join(",", var.cors_allow_origins)}'"
4578
+ "gatewayresponse.header.Access-Control-Allow-Headers" = "'\${join(",", var.cors_allow_headers)}'"
4579
+ "gatewayresponse.header.Access-Control-Allow-Methods" = "'\${join(",", var.cors_allow_methods)}'"
4580
+ }
4581
+ }
4582
+
4583
+ # Outputs
4584
+
4585
+ output "api_id" {
4586
+ description = "ID of the REST API Gateway"
4587
+ value = aws_api_gateway_rest_api.rest_api.id
4588
+ }
4589
+
4590
+ output "api_arn" {
4591
+ description = "ARN of the REST API Gateway"
4592
+ value = aws_api_gateway_rest_api.rest_api.arn
4593
+ }
4594
+
4595
+ output "api_endpoint" {
4596
+ description = "Base URL of the REST API Gateway"
4597
+ value = "https://\${aws_api_gateway_rest_api.rest_api.id}.execute-api.\${data.aws_region.current.id}.amazonaws.com"
4598
+ }
4599
+
4600
+ output "api_execution_arn" {
4601
+ description = "Execution ARN of the REST API Gateway"
4602
+ value = aws_api_gateway_rest_api.rest_api.execution_arn
4603
+ }
4604
+
4605
+ output "api_root_resource_id" {
4606
+ description = "Root resource ID of the REST API Gateway"
4607
+ value = aws_api_gateway_rest_api.rest_api.root_resource_id
4608
+ }
4609
+
4610
+ # Note: Stage and deployment outputs are provided by the consuming module
4611
+
4612
+ # Note: CloudWatch log group outputs removed due to account-level CloudWatch Logs role ARN requirement",
4613
+ "test-api.tf": "terraform {
4614
+ required_version = ">= 1.0"
4615
+
4616
+ required_providers {
4617
+ aws = {
4618
+ source = "hashicorp/aws"
4619
+ version = "~> 6.0"
4620
+ }
4621
+ }
4622
+ }
4623
+
4624
+
4625
+ variable "env" {
4626
+ description = "Environment variables for the Lambda function"
4627
+ type = map(string)
4628
+ default = {}
4629
+ }
4630
+
4631
+ variable "additional_iam_policy_statements" {
4632
+ description = "Additional IAM policy statements for the Lambda function"
4633
+ type = list(object({
4634
+ Effect = string
4635
+ Action = list(string)
4636
+ Resource = list(string)
4637
+ }))
4638
+ default = []
4639
+ }
4640
+
4641
+ # CORS Configuration (passed to core module)
4642
+
4643
+ variable "cors_allow_headers" {
4644
+ description = "List of allowed headers for CORS"
4645
+ type = list(string)
4646
+ default = ["authorization", "content-type", "x-amz-content-sha256", "x-amz-date", "x-amz-security-token"]
4647
+ }
4648
+
4649
+ variable "cors_allow_methods" {
4650
+ description = "List of allowed HTTP methods for CORS"
4651
+ type = list(string)
4652
+ default = ["*"]
4653
+ }
4654
+
4655
+ variable "cors_allow_origins" {
4656
+ description = "List of allowed origins for CORS"
4657
+ type = list(string)
4658
+ default = ["*"]
4659
+ }
4660
+
4661
+ # Tags
4662
+ variable "tags" {
4663
+ description = "Tags to apply to all resources"
4664
+ type = map(string)
4665
+ default = {}
4666
+ }
4667
+
4668
+ # Get current AWS region and account ID
4669
+ data "aws_region" "current" {}
4670
+ data "aws_caller_identity" "current" {}
4671
+
4672
+ # Resources
4673
+
4674
+ # Create Lambda ZIP file from the FastAPI bundle directory
4675
+ data "archive_file" "lambda_zip" {
4676
+ type = "zip"
4677
+ source_dir = "\${path.module}/../../../../../../../dist/apps/test-api/bundle"
4678
+ output_path = "\${path.module}/../../../../../../../dist/packages/common/terraform/apis/test-api/lambda.zip"
4679
+ }
4680
+
4681
+ # Use the core REST API module
4682
+ module "rest_api" {
4683
+ source = "../../../core/api/rest-api"
4684
+
4685
+ api_name = "TestApi"
4686
+ api_description = "TestApi REST API"
4687
+ stage_name = "prod"
4688
+ stage_auto_deploy = true
4689
+
4690
+ # CORS Configuration
4691
+ cors_allow_headers = var.cors_allow_headers
4692
+ cors_allow_methods = var.cors_allow_methods
4693
+ cors_allow_origins = var.cors_allow_origins
4694
+
4695
+ # Tags
4696
+ tags = var.tags
4697
+ }
4698
+
4699
+ # Lambda function
4700
+ resource "aws_lambda_function" "api_lambda" {
4701
+ #checkov:skip=CKV_AWS_117:Lambda function does not need to be in VPC for this use case
4702
+ #checkov:skip=CKV_AWS_116:Dead Letter Queue not required for this simple API use case
4703
+ #checkov:skip=CKV_AWS_272:Code signing not required for this use case
4704
+ #checkov:skip=CKV_AWS_115:Concurrent execution limit not required for this use case
4705
+ #checkov:skip=CKV_AWS_173:Lambda environment variables encrypted by managed key
4706
+ filename = data.archive_file.lambda_zip.output_path
4707
+ function_name = "TestApiHandler"
4708
+ role = aws_iam_role.lambda_execution_role.arn
4709
+ handler = "index.handler"
4710
+ runtime = "nodejs22.x"
4711
+ timeout = 30
4712
+ memory_size = 128
4713
+
4714
+ source_code_hash = data.archive_file.lambda_zip.output_base64sha256
4715
+
4716
+ # Enable X-Ray tracing
4717
+ tracing_config {
4718
+ mode = "Active"
4719
+ }
4720
+
4721
+ environment {
4722
+ variables = merge({
4723
+ AWS_CONNECTION_REUSE_ENABLED = "1"
4724
+ }, var.env)
4725
+ }
4726
+
4727
+ tags = var.tags
4728
+ }
4729
+
4730
+ # IAM role for Lambda execution
4731
+ resource "aws_iam_role" "lambda_execution_role" {
4732
+ name = "TestApiHandler-execution-role"
4733
+
4734
+ assume_role_policy = jsonencode({
4735
+ Version = "2012-10-17"
4736
+ Statement = [
4737
+ {
4738
+ Action = "sts:AssumeRole"
4739
+ Effect = "Allow"
4740
+ Principal = {
4741
+ Service = "lambda.amazonaws.com"
4742
+ }
4743
+ }
4744
+ ]
4745
+ })
4746
+
4747
+ tags = var.tags
4748
+ }
4749
+
4750
+ # Attach basic execution policy to Lambda role
4751
+ resource "aws_iam_role_policy_attachment" "lambda_basic_execution" {
4752
+ policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
4753
+ role = aws_iam_role.lambda_execution_role.name
4754
+ }
4755
+
4756
+ # Attach X-Ray tracing policy to Lambda role
4757
+ resource "aws_iam_role_policy_attachment" "lambda_xray_execution" {
4758
+ policy_arn = "arn:aws:iam::aws:policy/AWSXRayDaemonWriteAccess"
4759
+ role = aws_iam_role.lambda_execution_role.name
4760
+ }
4761
+
4762
+ # Additional IAM policies for Lambda (if provided)
4763
+ resource "aws_iam_role_policy" "lambda_additional_policies" {
4764
+ count = length(var.additional_iam_policy_statements) > 0 ? 1 : 0
4765
+ name = "TestApiHandler-additional-policies"
4766
+ role = aws_iam_role.lambda_execution_role.id
4767
+
4768
+ policy = jsonencode({
4769
+ Version = "2012-10-17"
4770
+ Statement = var.additional_iam_policy_statements
4771
+ })
4772
+ }
4773
+
4774
+ # CloudWatch Log Group for Lambda
4775
+ resource "aws_cloudwatch_log_group" "lambda_logs" {
4776
+ #checkov:skip=CKV_AWS_158:Using default CloudWatch log encryption
4777
+ #checkov:skip=CKV_AWS_338:Log retention set to forever
4778
+ #checkov:skip=CKV_AWS_66:Log retention set to forever
4779
+ name = "/aws/lambda/TestApiHandler"
4780
+ tags = var.tags
4781
+ }
4782
+
4783
+
4784
+ # Create proxy resource (captures all paths)
4785
+ resource "aws_api_gateway_resource" "proxy_resource" {
4786
+ rest_api_id = module.rest_api.api_id
4787
+ parent_id = module.rest_api.api_root_resource_id
4788
+ path_part = "{proxy+}"
4789
+ }
4790
+
4791
+ # Lambda integration for REST API
4792
+ resource "aws_api_gateway_integration" "lambda_integration" {
4793
+ rest_api_id = module.rest_api.api_id
4794
+ resource_id = aws_api_gateway_resource.proxy_resource.id
4795
+ http_method = aws_api_gateway_method.proxy_method.http_method
4796
+
4797
+ integration_http_method = "POST"
4798
+ type = "AWS_PROXY"
4799
+ uri = aws_lambda_function.api_lambda.invoke_arn
4800
+
4801
+ depends_on = [aws_lambda_function.api_lambda]
4802
+ }
4803
+
4804
+ # Method for proxy integration
4805
+ resource "aws_api_gateway_method" "proxy_method" {
4806
+ #checkov:skip=CKV2_AWS_53:Request validation not required for proxy integration as Lambda handles validation
4807
+ rest_api_id = module.rest_api.api_id
4808
+ resource_id = aws_api_gateway_resource.proxy_resource.id
4809
+ http_method = "ANY"
4810
+
4811
+ authorization = "AWS_IAM"
4812
+
4813
+ request_parameters = {
4814
+ "method.request.path.proxy" = true
4815
+ }
4816
+
4817
+ depends_on = []
4818
+ }
4819
+
4820
+ # OPTIONS method for CORS preflight
4821
+ resource "aws_api_gateway_method" "options_method" {
4822
+ #checkov:skip=CKV2_AWS_70:OPTIONS method must be unauthenticated for CORS preflight requests
4823
+ #checkov:skip=CKV2_AWS_53:Request validation not required for OPTIONS CORS preflight method
4824
+ rest_api_id = module.rest_api.api_id
4825
+ resource_id = aws_api_gateway_resource.proxy_resource.id
4826
+ http_method = "OPTIONS"
4827
+ authorization = "NONE"
4828
+ }
4829
+
4830
+ # CORS integration for OPTIONS method
4831
+ resource "aws_api_gateway_integration" "options_integration" {
4832
+ rest_api_id = module.rest_api.api_id
4833
+ resource_id = aws_api_gateway_resource.proxy_resource.id
4834
+ http_method = aws_api_gateway_method.options_method.http_method
4835
+
4836
+ type = "MOCK"
4837
+ request_templates = {
4838
+ "application/json" = "{\\"statusCode\\": 204}"
4839
+ }
4840
+ }
4841
+
4842
+ # OPTIONS method response
4843
+ resource "aws_api_gateway_method_response" "options_response" {
4844
+ rest_api_id = module.rest_api.api_id
4845
+ resource_id = aws_api_gateway_resource.proxy_resource.id
4846
+ http_method = aws_api_gateway_method.options_method.http_method
4847
+ status_code = "204"
4848
+
4849
+ response_parameters = {
4850
+ "method.response.header.Access-Control-Allow-Headers" = true
4851
+ "method.response.header.Access-Control-Allow-Methods" = true
4852
+ "method.response.header.Access-Control-Allow-Origin" = true
4853
+ }
4854
+ }
4855
+
4856
+ # OPTIONS integration response
4857
+ resource "aws_api_gateway_integration_response" "options_integration_response" {
4858
+ rest_api_id = module.rest_api.api_id
4859
+ resource_id = aws_api_gateway_resource.proxy_resource.id
4860
+ http_method = aws_api_gateway_method.options_method.http_method
4861
+ status_code = aws_api_gateway_method_response.options_response.status_code
4862
+
4863
+ response_parameters = {
4864
+ "method.response.header.Access-Control-Allow-Headers" = "'\${join(",", var.cors_allow_headers)}'"
4865
+ "method.response.header.Access-Control-Allow-Methods" = "'\${join(",", var.cors_allow_methods)}'"
4866
+ "method.response.header.Access-Control-Allow-Origin" = "'\${join(",", var.cors_allow_origins)}'"
4867
+ }
4868
+ }
4869
+
4870
+ # API Gateway deployment
4871
+ resource "aws_api_gateway_deployment" "api_deployment" {
4872
+ rest_api_id = module.rest_api.api_id
4873
+
4874
+ triggers = {
4875
+ redeployment = sha1(jsonencode([
4876
+ aws_api_gateway_resource.proxy_resource.id,
4877
+ aws_api_gateway_method.proxy_method.id,
4878
+ aws_api_gateway_integration.lambda_integration.id,
4879
+ aws_api_gateway_method.options_method.id,
4880
+ aws_api_gateway_integration.options_integration.id,
4881
+ ]))
4882
+ }
4883
+
4884
+ lifecycle {
4885
+ create_before_destroy = true
4886
+ }
4887
+
4888
+ depends_on = [
4889
+ aws_api_gateway_method.proxy_method,
4890
+ aws_api_gateway_integration.lambda_integration,
4891
+ aws_api_gateway_method.options_method,
4892
+ aws_api_gateway_integration.options_integration,
4893
+ aws_api_gateway_method_response.options_response,
4894
+ aws_api_gateway_integration_response.options_integration_response,
4895
+ ]
4896
+ }
4897
+
4898
+ # API Gateway stage
4899
+ resource "aws_api_gateway_stage" "api_stage" {
4900
+ #checkov:skip=CKV_AWS_120:API Gateway caching not required for this use case
4901
+ #checkov:skip=CKV_AWS_76:API Gateway access logging disabled due to account-level CloudWatch Logs role ARN requirement
4902
+ #checkov:skip=CKV2_AWS_4:API Gateway logging level not applicable as access logging is disabled
4903
+ #checkov:skip=CKV2_AWS_51:Client certificate authentication not required for this use case
4904
+ deployment_id = aws_api_gateway_deployment.api_deployment.id
4905
+ rest_api_id = module.rest_api.api_id
4906
+ stage_name = "prod"
4907
+ xray_tracing_enabled = true
4908
+
4909
+ tags = var.tags
4910
+
4911
+ depends_on = [aws_api_gateway_deployment.api_deployment]
4912
+ }
4913
+
4914
+ # API Gateway Resource Policy
4915
+ resource "aws_api_gateway_rest_api_policy" "api_policy" {
4916
+ rest_api_id = module.rest_api.api_id
4917
+
4918
+ policy = jsonencode({
4919
+ Version = "2012-10-17"
4920
+ Statement = [
4921
+ {
4922
+ # Grant any AWS credentials from the account to call the API
4923
+ # Machine to machine fine-grained access can be defined here using more specific principals
4924
+ # (eg roles or users) and resources (eg which api paths may be invoked by which principal) if required
4925
+ Effect = "Allow"
4926
+ Principal = {
4927
+ AWS = "arn:aws:iam::\${data.aws_caller_identity.current.account_id}:root"
4928
+ }
4929
+ Action = "execute-api:Invoke"
4930
+ Resource = "execute-api:/*"
4931
+ },
4932
+ {
4933
+ # Open up OPTIONS to allow browsers to make unauthenticated preflight requests
4934
+ Effect = "Allow"
4935
+ Principal = "*"
4936
+ Action = "execute-api:Invoke"
4937
+ Resource = "execute-api:/*/OPTIONS/*"
4938
+ }
4939
+ ]
4940
+ })
4941
+ }
4942
+
4943
+ # Lambda permission for API Gateway to invoke the function
4944
+ resource "aws_lambda_permission" "api_gateway_invoke" {
4945
+ statement_id = "AllowExecutionFromAPIGateway"
4946
+ action = "lambda:InvokeFunction"
4947
+ function_name = aws_lambda_function.api_lambda.function_name
4948
+ principal = "apigateway.amazonaws.com"
4949
+ source_arn = "\${module.rest_api.api_execution_arn}/*/*"
4950
+
4951
+ depends_on = [module.rest_api, aws_lambda_function.api_lambda]
4952
+ }
4953
+
4954
+ # Outputs
4955
+
4956
+ # API Gateway Outputs (from core module)
4957
+ output "api_id" {
4958
+ description = "ID of the REST API Gateway"
4959
+ value = module.rest_api.api_id
4960
+ }
4961
+
4962
+ output "api_arn" {
4963
+ description = "ARN of the REST API Gateway"
4964
+ value = module.rest_api.api_arn
4965
+ }
4966
+
4967
+ output "api_endpoint" {
4968
+ description = "Base URL of the REST API Gateway"
4969
+ value = module.rest_api.api_endpoint
4970
+ }
4971
+
4972
+ output "api_execution_arn" {
4973
+ description = "Execution ARN of the REST API Gateway"
4974
+ value = module.rest_api.api_execution_arn
4975
+ }
4976
+
4977
+ output "stage_invoke_url" {
4978
+ description = "Invoke URL of the API Gateway stage"
4979
+ value = aws_api_gateway_stage.api_stage.invoke_url
4980
+ }
4981
+
4982
+ output "stage_arn" {
4983
+ description = "ARN of the API Gateway stage"
4984
+ value = aws_api_gateway_stage.api_stage.arn
4985
+ }
4986
+
4987
+ output "stage_execution_arn" {
4988
+ description = "Execution ARN of the API Gateway stage"
4989
+ value = aws_api_gateway_stage.api_stage.execution_arn
4990
+ }
4991
+
4992
+ output "deployment_id" {
4993
+ description = "ID of the API Gateway deployment"
4994
+ value = aws_api_gateway_deployment.api_deployment.id
4995
+ }
4996
+
4997
+ output "stage_id" {
4998
+ description = "ID of the API Gateway stage"
4999
+ value = aws_api_gateway_stage.api_stage.id
5000
+ }
5001
+
5002
+ # Lambda Function Outputs
5003
+ output "lambda_function_name" {
5004
+ description = "Name of the Lambda function"
5005
+ value = aws_lambda_function.api_lambda.function_name
5006
+ }
5007
+
5008
+ output "lambda_function_arn" {
5009
+ description = "ARN of the Lambda function"
5010
+ value = aws_lambda_function.api_lambda.arn
5011
+ }
5012
+
5013
+ output "lambda_invoke_arn" {
5014
+ description = "Invoke ARN of the Lambda function"
5015
+ value = aws_lambda_function.api_lambda.invoke_arn
5016
+ }
5017
+
5018
+ output "lambda_qualified_arn" {
5019
+ description = "Qualified ARN of the Lambda function"
5020
+ value = aws_lambda_function.api_lambda.qualified_arn
5021
+ }
5022
+
5023
+ output "lambda_version" {
5024
+ description = "Version of the Lambda function"
5025
+ value = aws_lambda_function.api_lambda.version
5026
+ }
5027
+
5028
+ output "lambda_source_code_hash" {
5029
+ description = "Base64-encoded SHA256 hash of the Lambda deployment package"
5030
+ value = aws_lambda_function.api_lambda.source_code_hash
5031
+ }
5032
+
5033
+ output "lambda_source_code_size" {
5034
+ description = "Size of the Lambda deployment package in bytes"
5035
+ value = aws_lambda_function.api_lambda.source_code_size
5036
+ }
5037
+
5038
+ # IAM Role Outputs
5039
+ output "lambda_execution_role_arn" {
5040
+ description = "ARN of the Lambda execution role"
5041
+ value = aws_iam_role.lambda_execution_role.arn
5042
+ }
5043
+
5044
+ output "lambda_execution_role_name" {
5045
+ description = "Name of the Lambda execution role"
5046
+ value = aws_iam_role.lambda_execution_role.name
5047
+ }
5048
+
5049
+ # Integration Outputs
5050
+ output "integration_id" {
5051
+ description = "ID of the Lambda integration"
5052
+ value = aws_api_gateway_integration.lambda_integration.id
5053
+ }
5054
+
5055
+ output "proxy_resource_id" {
5056
+ description = "ID of the proxy resource"
5057
+ value = aws_api_gateway_resource.proxy_resource.id
5058
+ }
5059
+
5060
+ output "proxy_method_id" {
5061
+ description = "ID of the proxy method"
5062
+ value = aws_api_gateway_method.proxy_method.id
5063
+ }
5064
+
5065
+ # CloudWatch Log Groups
5066
+ output "lambda_log_group_name" {
5067
+ description = "Name of the Lambda CloudWatch log group"
5068
+ value = aws_cloudwatch_log_group.lambda_logs.name
5069
+ }
5070
+
5071
+ output "lambda_log_group_arn" {
5072
+ description = "ARN of the Lambda CloudWatch log group"
5073
+ value = aws_cloudwatch_log_group.lambda_logs.arn
5074
+ }
5075
+ ",
5076
+ }
5077
+ `;
5078
+
5079
+ exports[`trpc backend generator > terraform iacProvider > should generate terraform files for REST API with None auth and snapshot them > terraform-rest-none-files 1`] = `
5080
+ {
5081
+ "rest-api.tf": "# Core REST API Gateway module
5082
+ # This module creates the API Gateway REST API, deployment, stage, and logging resources
5083
+
5084
+ terraform {
5085
+ required_version = ">= 1.0"
5086
+
5087
+ required_providers {
5088
+ aws = {
5089
+ source = "hashicorp/aws"
5090
+ version = "~> 6.0"
5091
+ }
5092
+ }
5093
+ }
5094
+
5095
+ # Core REST API Gateway Variables
5096
+
5097
+ variable "api_name" {
5098
+ description = "Name of the REST API Gateway"
5099
+ type = string
5100
+ }
5101
+
5102
+ variable "api_description" {
5103
+ description = "Description of the REST API Gateway"
5104
+ type = string
5105
+ default = "REST API Gateway"
5106
+ }
5107
+
5108
+ variable "stage_name" {
5109
+ description = "Name of the API Gateway stage"
5110
+ type = string
5111
+ default = "prod"
5112
+ }
5113
+
5114
+ variable "stage_auto_deploy" {
5115
+ description = "Whether to automatically deploy the API stage"
5116
+ type = bool
5117
+ default = true
5118
+ }
5119
+
5120
+ # CORS Configuration
5121
+
5122
+ variable "cors_allow_headers" {
5123
+ description = "List of allowed headers for CORS"
5124
+ type = list(string)
5125
+ default = ["authorization", "content-type", "x-amz-content-sha256", "x-amz-date", "x-amz-security-token"]
5126
+ }
5127
+
5128
+ variable "cors_allow_methods" {
5129
+ description = "List of allowed HTTP methods for CORS"
5130
+ type = list(string)
5131
+ default = ["*"]
5132
+ }
5133
+
5134
+ variable "cors_allow_origins" {
5135
+ description = "List of allowed origins for CORS"
5136
+ type = list(string)
5137
+ default = ["*"]
5138
+ }
5139
+
5140
+ # Tags
5141
+
5142
+ variable "tags" {
5143
+ description = "Tags to apply to all resources"
5144
+ type = map(string)
5145
+ default = {}
5146
+ }
5147
+
5148
+ # Data sources
5149
+ data "aws_region" "current" {}
5150
+ data "aws_caller_identity" "current" {}
5151
+
5152
+ # Resources
5153
+
5154
+ # Note: CloudWatch logging removed due to account-level CloudWatch Logs role ARN requirement
5155
+
5156
+ # REST API Gateway
5157
+ resource "aws_api_gateway_rest_api" "rest_api" {
5158
+ name = var.api_name
5159
+ description = var.api_description
5160
+
5161
+ endpoint_configuration {
5162
+ types = ["REGIONAL"]
5163
+ }
5164
+
5165
+ lifecycle {
5166
+ create_before_destroy = true
5167
+ }
5168
+
5169
+ tags = var.tags
5170
+ }
5171
+
5172
+ # Note: Deployment and stage are created in the consuming module (e.g., foo-api.tf)
5173
+ # after all methods and integrations are defined
5174
+
5175
+ # Note: CloudWatch Log Group removed due to account-level CloudWatch Logs role ARN requirement
5176
+
5177
+ # Gateway Response for CORS (4XX errors)
5178
+ resource "aws_api_gateway_gateway_response" "cors_4xx" {
5179
+ rest_api_id = aws_api_gateway_rest_api.rest_api.id
5180
+ response_type = "DEFAULT_4XX"
5181
+
5182
+ response_parameters = {
5183
+ "gatewayresponse.header.Access-Control-Allow-Origin" = "'\${join(",", var.cors_allow_origins)}'"
5184
+ "gatewayresponse.header.Access-Control-Allow-Headers" = "'\${join(",", var.cors_allow_headers)}'"
5185
+ "gatewayresponse.header.Access-Control-Allow-Methods" = "'\${join(",", var.cors_allow_methods)}'"
5186
+ }
5187
+ }
5188
+
5189
+ # Gateway Response for CORS (5XX errors)
5190
+ resource "aws_api_gateway_gateway_response" "cors_5xx" {
5191
+ rest_api_id = aws_api_gateway_rest_api.rest_api.id
5192
+ response_type = "DEFAULT_5XX"
5193
+
5194
+ response_parameters = {
5195
+ "gatewayresponse.header.Access-Control-Allow-Origin" = "'\${join(",", var.cors_allow_origins)}'"
5196
+ "gatewayresponse.header.Access-Control-Allow-Headers" = "'\${join(",", var.cors_allow_headers)}'"
5197
+ "gatewayresponse.header.Access-Control-Allow-Methods" = "'\${join(",", var.cors_allow_methods)}'"
5198
+ }
5199
+ }
5200
+
5201
+ # Outputs
5202
+
5203
+ output "api_id" {
5204
+ description = "ID of the REST API Gateway"
5205
+ value = aws_api_gateway_rest_api.rest_api.id
5206
+ }
5207
+
5208
+ output "api_arn" {
5209
+ description = "ARN of the REST API Gateway"
5210
+ value = aws_api_gateway_rest_api.rest_api.arn
5211
+ }
5212
+
5213
+ output "api_endpoint" {
5214
+ description = "Base URL of the REST API Gateway"
5215
+ value = "https://\${aws_api_gateway_rest_api.rest_api.id}.execute-api.\${data.aws_region.current.id}.amazonaws.com"
5216
+ }
5217
+
5218
+ output "api_execution_arn" {
5219
+ description = "Execution ARN of the REST API Gateway"
5220
+ value = aws_api_gateway_rest_api.rest_api.execution_arn
5221
+ }
5222
+
5223
+ output "api_root_resource_id" {
5224
+ description = "Root resource ID of the REST API Gateway"
5225
+ value = aws_api_gateway_rest_api.rest_api.root_resource_id
5226
+ }
5227
+
5228
+ # Note: Stage and deployment outputs are provided by the consuming module
5229
+
5230
+ # Note: CloudWatch log group outputs removed due to account-level CloudWatch Logs role ARN requirement",
5231
+ "test-api.tf": "terraform {
5232
+ required_version = ">= 1.0"
5233
+
5234
+ required_providers {
5235
+ aws = {
5236
+ source = "hashicorp/aws"
5237
+ version = "~> 6.0"
5238
+ }
5239
+ }
5240
+ }
5241
+
5242
+
5243
+ variable "env" {
5244
+ description = "Environment variables for the Lambda function"
5245
+ type = map(string)
5246
+ default = {}
5247
+ }
5248
+
5249
+ variable "additional_iam_policy_statements" {
5250
+ description = "Additional IAM policy statements for the Lambda function"
5251
+ type = list(object({
5252
+ Effect = string
5253
+ Action = list(string)
5254
+ Resource = list(string)
5255
+ }))
5256
+ default = []
5257
+ }
5258
+
5259
+ # CORS Configuration (passed to core module)
5260
+
5261
+ variable "cors_allow_headers" {
5262
+ description = "List of allowed headers for CORS"
5263
+ type = list(string)
5264
+ default = ["authorization", "content-type", "x-amz-content-sha256", "x-amz-date", "x-amz-security-token"]
5265
+ }
5266
+
5267
+ variable "cors_allow_methods" {
5268
+ description = "List of allowed HTTP methods for CORS"
5269
+ type = list(string)
5270
+ default = ["*"]
5271
+ }
5272
+
5273
+ variable "cors_allow_origins" {
5274
+ description = "List of allowed origins for CORS"
5275
+ type = list(string)
5276
+ default = ["*"]
5277
+ }
5278
+
5279
+ # Tags
5280
+ variable "tags" {
5281
+ description = "Tags to apply to all resources"
5282
+ type = map(string)
5283
+ default = {}
5284
+ }
5285
+
5286
+ # Get current AWS region and account ID
5287
+ data "aws_region" "current" {}
5288
+ data "aws_caller_identity" "current" {}
5289
+
5290
+ # Resources
5291
+
5292
+ # Create Lambda ZIP file from the FastAPI bundle directory
5293
+ data "archive_file" "lambda_zip" {
5294
+ type = "zip"
5295
+ source_dir = "\${path.module}/../../../../../../../dist/apps/test-api/bundle"
5296
+ output_path = "\${path.module}/../../../../../../../dist/packages/common/terraform/apis/test-api/lambda.zip"
5297
+ }
5298
+
5299
+ # Use the core REST API module
5300
+ module "rest_api" {
5301
+ source = "../../../core/api/rest-api"
5302
+
5303
+ api_name = "TestApi"
5304
+ api_description = "TestApi REST API"
5305
+ stage_name = "prod"
5306
+ stage_auto_deploy = true
5307
+
5308
+ # CORS Configuration
5309
+ cors_allow_headers = var.cors_allow_headers
5310
+ cors_allow_methods = var.cors_allow_methods
5311
+ cors_allow_origins = var.cors_allow_origins
5312
+
5313
+ # Tags
5314
+ tags = var.tags
5315
+ }
5316
+
5317
+ # Lambda function
5318
+ resource "aws_lambda_function" "api_lambda" {
5319
+ #checkov:skip=CKV_AWS_117:Lambda function does not need to be in VPC for this use case
5320
+ #checkov:skip=CKV_AWS_116:Dead Letter Queue not required for this simple API use case
5321
+ #checkov:skip=CKV_AWS_272:Code signing not required for this use case
5322
+ #checkov:skip=CKV_AWS_115:Concurrent execution limit not required for this use case
5323
+ #checkov:skip=CKV_AWS_173:Lambda environment variables encrypted by managed key
5324
+ filename = data.archive_file.lambda_zip.output_path
5325
+ function_name = "TestApiHandler"
5326
+ role = aws_iam_role.lambda_execution_role.arn
5327
+ handler = "index.handler"
5328
+ runtime = "nodejs22.x"
5329
+ timeout = 30
5330
+ memory_size = 128
5331
+
5332
+ source_code_hash = data.archive_file.lambda_zip.output_base64sha256
5333
+
5334
+ # Enable X-Ray tracing
5335
+ tracing_config {
5336
+ mode = "Active"
5337
+ }
5338
+
5339
+ environment {
5340
+ variables = merge({
5341
+ AWS_CONNECTION_REUSE_ENABLED = "1"
5342
+ }, var.env)
5343
+ }
5344
+
5345
+ tags = var.tags
5346
+ }
5347
+
5348
+ # IAM role for Lambda execution
5349
+ resource "aws_iam_role" "lambda_execution_role" {
5350
+ name = "TestApiHandler-execution-role"
5351
+
5352
+ assume_role_policy = jsonencode({
5353
+ Version = "2012-10-17"
5354
+ Statement = [
5355
+ {
5356
+ Action = "sts:AssumeRole"
5357
+ Effect = "Allow"
5358
+ Principal = {
5359
+ Service = "lambda.amazonaws.com"
5360
+ }
5361
+ }
5362
+ ]
5363
+ })
5364
+
5365
+ tags = var.tags
5366
+ }
5367
+
5368
+ # Attach basic execution policy to Lambda role
5369
+ resource "aws_iam_role_policy_attachment" "lambda_basic_execution" {
5370
+ policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
5371
+ role = aws_iam_role.lambda_execution_role.name
5372
+ }
5373
+
5374
+ # Attach X-Ray tracing policy to Lambda role
5375
+ resource "aws_iam_role_policy_attachment" "lambda_xray_execution" {
5376
+ policy_arn = "arn:aws:iam::aws:policy/AWSXRayDaemonWriteAccess"
5377
+ role = aws_iam_role.lambda_execution_role.name
5378
+ }
5379
+
5380
+ # Additional IAM policies for Lambda (if provided)
5381
+ resource "aws_iam_role_policy" "lambda_additional_policies" {
5382
+ count = length(var.additional_iam_policy_statements) > 0 ? 1 : 0
5383
+ name = "TestApiHandler-additional-policies"
5384
+ role = aws_iam_role.lambda_execution_role.id
5385
+
5386
+ policy = jsonencode({
5387
+ Version = "2012-10-17"
5388
+ Statement = var.additional_iam_policy_statements
5389
+ })
5390
+ }
5391
+
5392
+ # CloudWatch Log Group for Lambda
5393
+ resource "aws_cloudwatch_log_group" "lambda_logs" {
5394
+ #checkov:skip=CKV_AWS_158:Using default CloudWatch log encryption
5395
+ #checkov:skip=CKV_AWS_338:Log retention set to forever
5396
+ #checkov:skip=CKV_AWS_66:Log retention set to forever
5397
+ name = "/aws/lambda/TestApiHandler"
5398
+ tags = var.tags
5399
+ }
5400
+
5401
+
5402
+ # Create proxy resource (captures all paths)
5403
+ resource "aws_api_gateway_resource" "proxy_resource" {
5404
+ rest_api_id = module.rest_api.api_id
5405
+ parent_id = module.rest_api.api_root_resource_id
5406
+ path_part = "{proxy+}"
5407
+ }
5408
+
5409
+ # Lambda integration for REST API
5410
+ resource "aws_api_gateway_integration" "lambda_integration" {
5411
+ rest_api_id = module.rest_api.api_id
5412
+ resource_id = aws_api_gateway_resource.proxy_resource.id
5413
+ http_method = aws_api_gateway_method.proxy_method.http_method
5414
+
5415
+ integration_http_method = "POST"
5416
+ type = "AWS_PROXY"
5417
+ uri = aws_lambda_function.api_lambda.invoke_arn
5418
+
5419
+ depends_on = [aws_lambda_function.api_lambda]
5420
+ }
5421
+
5422
+ # Method for proxy integration
5423
+ resource "aws_api_gateway_method" "proxy_method" {
5424
+ #checkov:skip=CKV2_AWS_53:Request validation not required for proxy integration as Lambda handles validation
5425
+ rest_api_id = module.rest_api.api_id
5426
+ resource_id = aws_api_gateway_resource.proxy_resource.id
5427
+ http_method = "ANY"
5428
+
5429
+ # Note: you may wish to suppress the checkov rule CKV_AWS_59 if you are absolutely sure you
5430
+ # need a public API without authentication
5431
+ authorization = "NONE"
5432
+
5433
+ request_parameters = {
5434
+ "method.request.path.proxy" = true
5435
+ }
5436
+
5437
+ depends_on = []
5438
+ }
5439
+
5440
+ # OPTIONS method for CORS preflight
5441
+ resource "aws_api_gateway_method" "options_method" {
5442
+ #checkov:skip=CKV2_AWS_70:OPTIONS method must be unauthenticated for CORS preflight requests
5443
+ #checkov:skip=CKV2_AWS_53:Request validation not required for OPTIONS CORS preflight method
5444
+ rest_api_id = module.rest_api.api_id
5445
+ resource_id = aws_api_gateway_resource.proxy_resource.id
5446
+ http_method = "OPTIONS"
5447
+ authorization = "NONE"
5448
+ }
5449
+
5450
+ # CORS integration for OPTIONS method
5451
+ resource "aws_api_gateway_integration" "options_integration" {
5452
+ rest_api_id = module.rest_api.api_id
5453
+ resource_id = aws_api_gateway_resource.proxy_resource.id
5454
+ http_method = aws_api_gateway_method.options_method.http_method
5455
+
5456
+ type = "MOCK"
5457
+ request_templates = {
5458
+ "application/json" = "{\\"statusCode\\": 204}"
5459
+ }
5460
+ }
5461
+
5462
+ # OPTIONS method response
5463
+ resource "aws_api_gateway_method_response" "options_response" {
5464
+ rest_api_id = module.rest_api.api_id
5465
+ resource_id = aws_api_gateway_resource.proxy_resource.id
5466
+ http_method = aws_api_gateway_method.options_method.http_method
5467
+ status_code = "204"
5468
+
5469
+ response_parameters = {
5470
+ "method.response.header.Access-Control-Allow-Headers" = true
5471
+ "method.response.header.Access-Control-Allow-Methods" = true
5472
+ "method.response.header.Access-Control-Allow-Origin" = true
5473
+ }
5474
+ }
5475
+
5476
+ # OPTIONS integration response
5477
+ resource "aws_api_gateway_integration_response" "options_integration_response" {
5478
+ rest_api_id = module.rest_api.api_id
5479
+ resource_id = aws_api_gateway_resource.proxy_resource.id
5480
+ http_method = aws_api_gateway_method.options_method.http_method
5481
+ status_code = aws_api_gateway_method_response.options_response.status_code
5482
+
5483
+ response_parameters = {
5484
+ "method.response.header.Access-Control-Allow-Headers" = "'\${join(",", var.cors_allow_headers)}'"
5485
+ "method.response.header.Access-Control-Allow-Methods" = "'\${join(",", var.cors_allow_methods)}'"
5486
+ "method.response.header.Access-Control-Allow-Origin" = "'\${join(",", var.cors_allow_origins)}'"
5487
+ }
5488
+ }
5489
+
5490
+ # API Gateway deployment
5491
+ resource "aws_api_gateway_deployment" "api_deployment" {
5492
+ rest_api_id = module.rest_api.api_id
5493
+
5494
+ triggers = {
5495
+ redeployment = sha1(jsonencode([
5496
+ aws_api_gateway_resource.proxy_resource.id,
5497
+ aws_api_gateway_method.proxy_method.id,
5498
+ aws_api_gateway_integration.lambda_integration.id,
5499
+ aws_api_gateway_method.options_method.id,
5500
+ aws_api_gateway_integration.options_integration.id,
5501
+ ]))
5502
+ }
5503
+
5504
+ lifecycle {
5505
+ create_before_destroy = true
5506
+ }
5507
+
5508
+ depends_on = [
5509
+ aws_api_gateway_method.proxy_method,
5510
+ aws_api_gateway_integration.lambda_integration,
5511
+ aws_api_gateway_method.options_method,
5512
+ aws_api_gateway_integration.options_integration,
5513
+ aws_api_gateway_method_response.options_response,
5514
+ aws_api_gateway_integration_response.options_integration_response,
5515
+ ]
5516
+ }
5517
+
5518
+ # API Gateway stage
5519
+ resource "aws_api_gateway_stage" "api_stage" {
5520
+ #checkov:skip=CKV_AWS_120:API Gateway caching not required for this use case
5521
+ #checkov:skip=CKV_AWS_76:API Gateway access logging disabled due to account-level CloudWatch Logs role ARN requirement
5522
+ #checkov:skip=CKV2_AWS_4:API Gateway logging level not applicable as access logging is disabled
5523
+ #checkov:skip=CKV2_AWS_51:Client certificate authentication not required for this use case
5524
+ deployment_id = aws_api_gateway_deployment.api_deployment.id
5525
+ rest_api_id = module.rest_api.api_id
5526
+ stage_name = "prod"
5527
+ xray_tracing_enabled = true
5528
+
5529
+ tags = var.tags
5530
+
5531
+ depends_on = [aws_api_gateway_deployment.api_deployment]
5532
+ }
5533
+
5534
+ # API Gateway Resource Policy
5535
+ resource "aws_api_gateway_rest_api_policy" "api_policy" {
5536
+ rest_api_id = module.rest_api.api_id
5537
+
5538
+ policy = jsonencode({
5539
+ Version = "2012-10-17"
5540
+ Statement = [
5541
+ {
5542
+ # Allow all callers to invoke the API in the resource policy
5543
+ Effect = "Allow"
5544
+ Principal = "*"
5545
+ Action = "execute-api:Invoke"
5546
+ Resource = "execute-api:/*"
5547
+ }
5548
+ ]
5549
+ })
5550
+ }
5551
+
5552
+ # Lambda permission for API Gateway to invoke the function
5553
+ resource "aws_lambda_permission" "api_gateway_invoke" {
5554
+ statement_id = "AllowExecutionFromAPIGateway"
5555
+ action = "lambda:InvokeFunction"
5556
+ function_name = aws_lambda_function.api_lambda.function_name
5557
+ principal = "apigateway.amazonaws.com"
5558
+ source_arn = "\${module.rest_api.api_execution_arn}/*/*"
5559
+
5560
+ depends_on = [module.rest_api, aws_lambda_function.api_lambda]
5561
+ }
5562
+
5563
+ # Outputs
5564
+
5565
+ # API Gateway Outputs (from core module)
5566
+ output "api_id" {
5567
+ description = "ID of the REST API Gateway"
5568
+ value = module.rest_api.api_id
5569
+ }
5570
+
5571
+ output "api_arn" {
5572
+ description = "ARN of the REST API Gateway"
5573
+ value = module.rest_api.api_arn
5574
+ }
5575
+
5576
+ output "api_endpoint" {
5577
+ description = "Base URL of the REST API Gateway"
5578
+ value = module.rest_api.api_endpoint
5579
+ }
5580
+
5581
+ output "api_execution_arn" {
5582
+ description = "Execution ARN of the REST API Gateway"
5583
+ value = module.rest_api.api_execution_arn
5584
+ }
5585
+
5586
+ output "stage_invoke_url" {
5587
+ description = "Invoke URL of the API Gateway stage"
5588
+ value = aws_api_gateway_stage.api_stage.invoke_url
5589
+ }
5590
+
5591
+ output "stage_arn" {
5592
+ description = "ARN of the API Gateway stage"
5593
+ value = aws_api_gateway_stage.api_stage.arn
5594
+ }
5595
+
5596
+ output "stage_execution_arn" {
5597
+ description = "Execution ARN of the API Gateway stage"
5598
+ value = aws_api_gateway_stage.api_stage.execution_arn
5599
+ }
5600
+
5601
+ output "deployment_id" {
5602
+ description = "ID of the API Gateway deployment"
5603
+ value = aws_api_gateway_deployment.api_deployment.id
5604
+ }
5605
+
5606
+ output "stage_id" {
5607
+ description = "ID of the API Gateway stage"
5608
+ value = aws_api_gateway_stage.api_stage.id
5609
+ }
5610
+
5611
+ # Lambda Function Outputs
5612
+ output "lambda_function_name" {
5613
+ description = "Name of the Lambda function"
5614
+ value = aws_lambda_function.api_lambda.function_name
5615
+ }
5616
+
5617
+ output "lambda_function_arn" {
5618
+ description = "ARN of the Lambda function"
5619
+ value = aws_lambda_function.api_lambda.arn
5620
+ }
5621
+
5622
+ output "lambda_invoke_arn" {
5623
+ description = "Invoke ARN of the Lambda function"
5624
+ value = aws_lambda_function.api_lambda.invoke_arn
5625
+ }
5626
+
5627
+ output "lambda_qualified_arn" {
5628
+ description = "Qualified ARN of the Lambda function"
5629
+ value = aws_lambda_function.api_lambda.qualified_arn
5630
+ }
5631
+
5632
+ output "lambda_version" {
5633
+ description = "Version of the Lambda function"
5634
+ value = aws_lambda_function.api_lambda.version
5635
+ }
5636
+
5637
+ output "lambda_source_code_hash" {
5638
+ description = "Base64-encoded SHA256 hash of the Lambda deployment package"
5639
+ value = aws_lambda_function.api_lambda.source_code_hash
5640
+ }
5641
+
5642
+ output "lambda_source_code_size" {
5643
+ description = "Size of the Lambda deployment package in bytes"
5644
+ value = aws_lambda_function.api_lambda.source_code_size
5645
+ }
5646
+
5647
+ # IAM Role Outputs
5648
+ output "lambda_execution_role_arn" {
5649
+ description = "ARN of the Lambda execution role"
5650
+ value = aws_iam_role.lambda_execution_role.arn
5651
+ }
5652
+
5653
+ output "lambda_execution_role_name" {
5654
+ description = "Name of the Lambda execution role"
5655
+ value = aws_iam_role.lambda_execution_role.name
5656
+ }
5657
+
5658
+ # Integration Outputs
5659
+ output "integration_id" {
5660
+ description = "ID of the Lambda integration"
5661
+ value = aws_api_gateway_integration.lambda_integration.id
5662
+ }
5663
+
5664
+ output "proxy_resource_id" {
5665
+ description = "ID of the proxy resource"
5666
+ value = aws_api_gateway_resource.proxy_resource.id
5667
+ }
5668
+
5669
+ output "proxy_method_id" {
5670
+ description = "ID of the proxy method"
5671
+ value = aws_api_gateway_method.proxy_method.id
5672
+ }
5673
+
5674
+ # CloudWatch Log Groups
5675
+ output "lambda_log_group_name" {
5676
+ description = "Name of the Lambda CloudWatch log group"
5677
+ value = aws_cloudwatch_log_group.lambda_logs.name
5678
+ }
5679
+
5680
+ output "lambda_log_group_arn" {
5681
+ description = "ARN of the Lambda CloudWatch log group"
5682
+ value = aws_cloudwatch_log_group.lambda_logs.arn
5683
+ }
5684
+ ",
5685
+ }
5686
+ `;