@aws/nx-plugin 1.0.0-rc.9 → 1.0.0-rc.90
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.
- package/LICENSE-THIRD-PARTY +13999 -17963
- package/README.md +30 -110
- package/executors.json +5 -0
- package/generators.json +170 -10
- package/migrations.json +364 -0
- package/package.json +40 -21
- package/src/agentcore-gateway/__snapshots__/generator.spec.ts.snap +344 -0
- package/src/agentcore-gateway/agent-connection/generator.d.ts +19 -0
- package/src/agentcore-gateway/agent-connection/generator.js +95 -0
- package/src/agentcore-gateway/agent-connection/generator.js.map +1 -0
- package/src/agentcore-gateway/agent-connection/schema.d.js +6 -0
- package/src/agentcore-gateway/agent-connection/schema.d.js.map +1 -0
- package/src/agentcore-gateway/agent-connection/schema.d.ts +13 -0
- package/src/agentcore-gateway/agent-connection/schema.json +31 -0
- package/src/agentcore-gateway/attach-upstream.d.ts +49 -0
- package/src/agentcore-gateway/attach-upstream.js +59 -0
- package/src/agentcore-gateway/attach-upstream.js.map +1 -0
- package/src/agentcore-gateway/files/cedar/policies/README.md +61 -0
- package/src/agentcore-gateway/files/cedar/policies/permit-all.cedar +26 -0
- package/src/agentcore-gateway/files/project/http/local-dev.ts.template +77 -0
- package/src/agentcore-gateway/files/project/mcp/local-dev.ts.template +134 -0
- package/src/agentcore-gateway/gateway-connection/generator.d.ts +21 -0
- package/src/agentcore-gateway/gateway-connection/generator.js +103 -0
- package/src/agentcore-gateway/gateway-connection/generator.js.map +1 -0
- package/src/agentcore-gateway/gateway-connection/schema.d.js +6 -0
- package/src/agentcore-gateway/gateway-connection/schema.d.js.map +1 -0
- package/src/agentcore-gateway/gateway-connection/schema.d.ts +13 -0
- package/src/agentcore-gateway/gateway-connection/schema.json +31 -0
- package/src/agentcore-gateway/generator.d.ts +90 -0
- package/src/agentcore-gateway/generator.js +202 -0
- package/src/agentcore-gateway/generator.js.map +1 -0
- package/src/agentcore-gateway/mcp-connection/generator.d.ts +19 -0
- package/src/agentcore-gateway/mcp-connection/generator.js +61 -0
- package/src/agentcore-gateway/mcp-connection/generator.js.map +1 -0
- package/src/agentcore-gateway/mcp-connection/schema.d.js +6 -0
- package/src/agentcore-gateway/mcp-connection/schema.d.js.map +1 -0
- package/src/agentcore-gateway/mcp-connection/schema.d.ts +13 -0
- package/src/agentcore-gateway/mcp-connection/schema.json +31 -0
- package/src/agentcore-gateway/react-connection/__snapshots__/generator.spec.ts.snap +68 -0
- package/src/agentcore-gateway/react-connection/generator.d.ts +19 -0
- package/src/agentcore-gateway/react-connection/generator.js +119 -0
- package/src/agentcore-gateway/react-connection/generator.js.map +1 -0
- package/src/agentcore-gateway/react-connection/schema.d.js +6 -0
- package/src/agentcore-gateway/react-connection/schema.d.js.map +1 -0
- package/src/agentcore-gateway/react-connection/schema.d.ts +13 -0
- package/src/agentcore-gateway/react-connection/schema.json +31 -0
- package/src/agentcore-gateway/schema.d.js +6 -0
- package/src/agentcore-gateway/schema.d.js.map +1 -0
- package/src/agentcore-gateway/schema.d.ts +17 -0
- package/src/agentcore-gateway/schema.json +72 -0
- package/src/agentcore-harness/__snapshots__/generator.spec.ts.snap +237 -0
- package/src/agentcore-harness/files/project/README.md.template +82 -0
- package/src/agentcore-harness/files/project/scripts/chat.ts.template +99 -0
- package/src/agentcore-harness/files/project/src/PROMPT.md.template +16 -0
- package/src/agentcore-harness/generator.d.ts +62 -0
- package/src/agentcore-harness/generator.js +158 -0
- package/src/agentcore-harness/generator.js.map +1 -0
- package/src/agentcore-harness/schema.d.js +8 -0
- package/src/agentcore-harness/schema.d.js.map +1 -0
- package/src/agentcore-harness/schema.d.ts +17 -0
- package/src/agentcore-harness/schema.json +53 -0
- package/src/connection/agent-local-dev.d.ts +49 -0
- package/src/connection/agent-local-dev.js +84 -0
- package/src/connection/agent-local-dev.js.map +1 -0
- package/src/connection/agent-runtime-config.js +9 -14
- package/src/connection/agent-runtime-config.js.map +1 -1
- package/src/connection/gateway-runtime-config.d.ts +19 -0
- package/src/connection/gateway-runtime-config.js +47 -0
- package/src/connection/gateway-runtime-config.js.map +1 -0
- package/src/connection/generator.d.ts +4 -11
- package/src/connection/generator.js +172 -194
- package/src/connection/generator.js.map +1 -1
- package/src/connection/{serve-local.d.ts → local-dev.d.ts} +3 -3
- package/src/connection/local-dev.js +37 -0
- package/src/connection/local-dev.js.map +1 -0
- package/src/connection/scaffold-catalog.d.ts +267 -0
- package/src/connection/scaffold-catalog.js +347 -0
- package/src/connection/scaffold-catalog.js.map +1 -0
- package/src/connection/schema-resolver.d.ts +5 -0
- package/src/connection/schema-resolver.js +27 -0
- package/src/connection/schema-resolver.js.map +1 -0
- package/src/connection/schema.d.js +6 -0
- package/src/connection/schema.d.js.map +1 -0
- package/src/connection/schema.d.ts +1 -0
- package/src/connection/schema.json +5 -0
- package/src/connection/supported-connections.d.ts +116 -0
- package/src/connection/supported-connections.js +163 -0
- package/src/connection/supported-connections.js.map +1 -0
- package/src/index.d.ts +1 -1
- package/src/index.js +2 -5
- package/src/index.js.map +1 -1
- package/src/infra/app/__snapshots__/generator.spec.ts.snap +172 -87
- package/src/infra/app/files/app/README.md.template +22 -4
- package/src/infra/app/files/app/src/main.ts.template +5 -1
- package/src/infra/app/files/app/src/stages/application-stage.ts.template +1 -1
- package/src/infra/app/generator.d.ts +44 -1
- package/src/infra/app/generator.js +209 -128
- package/src/infra/app/generator.js.map +1 -1
- package/src/infra/app/schema.d.js +6 -0
- package/src/infra/app/schema.d.js.map +1 -0
- package/src/infra/app/schema.d.ts +1 -1
- package/src/infra/app/schema.json +5 -0
- package/src/init/generator.d.ts +31 -0
- package/src/init/generator.js +46 -0
- package/src/init/generator.js.map +1 -0
- package/src/init/schema.d.js +6 -0
- package/src/init/schema.d.js.map +1 -0
- package/src/init/schema.d.ts +16 -0
- package/src/init/schema.json +35 -0
- package/src/internal/test-matrix/generator.d.ts +29 -0
- package/src/internal/test-matrix/generator.js +729 -0
- package/src/internal/test-matrix/generator.js.map +1 -0
- package/src/internal/test-matrix/schema.d.js +6 -0
- package/src/internal/test-matrix/schema.d.js.map +1 -0
- package/src/internal/test-matrix/schema.d.ts +12 -0
- package/src/internal/test-matrix/schema.json +21 -0
- package/src/license/config-types.d.ts +2 -2
- package/src/license/config-types.js +5 -3
- package/src/license/config-types.js.map +1 -1
- package/src/license/config.d.ts +12 -3
- package/src/license/config.js +295 -242
- package/src/license/config.js.map +1 -1
- package/src/license/dependency-check/check.d.ts +2 -2
- package/src/license/dependency-check/check.js +51 -46
- package/src/license/dependency-check/check.js.map +1 -1
- package/src/license/dependency-check/collectors/collector.js +41 -71
- package/src/license/dependency-check/collectors/collector.js.map +1 -1
- package/src/license/dependency-check/collectors/npm-collector.js +34 -41
- package/src/license/dependency-check/collectors/npm-collector.js.map +1 -1
- package/src/license/dependency-check/collectors/python-collector.js +61 -62
- package/src/license/dependency-check/collectors/python-collector.js.map +1 -1
- package/src/license/dependency-check/evaluator.d.ts +1 -1
- package/src/license/dependency-check/evaluator.js +91 -74
- package/src/license/dependency-check/evaluator.js.map +1 -1
- package/src/license/dependency-check/executor.js +30 -22
- package/src/license/dependency-check/executor.js.map +1 -1
- package/src/license/dependency-check/pre-approved.d.ts +1 -1
- package/src/license/dependency-check/pre-approved.js +949 -336
- package/src/license/dependency-check/pre-approved.js.map +1 -1
- package/src/license/dependency-check/types.d.ts +1 -1
- package/src/license/dependency-check/types.js +2 -3
- package/src/license/dependency-check/types.js.map +1 -1
- package/src/license/generator.d.ts +1 -1
- package/src/license/generator.js +60 -77
- package/src/license/generator.js.map +1 -1
- package/src/license/index.d.ts +4 -4
- package/src/license/index.js +3 -9
- package/src/license/index.js.map +1 -1
- package/src/license/known-exceptions.d.ts +2 -3
- package/src/license/known-exceptions.js +12 -28
- package/src/license/known-exceptions.js.map +1 -1
- package/src/license/schema.d.js +6 -0
- package/src/license/schema.d.js.map +1 -0
- package/src/license/schema.d.ts +2 -0
- package/src/license/schema.json +5 -0
- package/src/license/sync/generator.js +94 -119
- package/src/license/sync/generator.js.map +1 -1
- package/src/license/sync/project-file-sync.d.ts +1 -1
- package/src/license/sync/project-file-sync.js +28 -35
- package/src/license/sync/project-file-sync.js.map +1 -1
- package/src/mcp-server/dev-server.d.ts +1 -0
- package/src/mcp-server/dev-server.js +18 -0
- package/src/mcp-server/dev-server.js.map +1 -0
- package/src/mcp-server/generator-info.d.ts +8 -3
- package/src/mcp-server/generator-info.js +155 -167
- package/src/mcp-server/generator-info.js.map +1 -1
- package/src/mcp-server/guide-pipeline.d.ts +1 -1
- package/src/mcp-server/guide-pipeline.js +199 -206
- package/src/mcp-server/guide-pipeline.js.map +1 -1
- package/src/mcp-server/guide-render.js +10 -25
- package/src/mcp-server/guide-render.js.map +1 -1
- package/src/mcp-server/index.js +6 -10
- package/src/mcp-server/index.js.map +1 -1
- package/src/mcp-server/mdx-ast.js +39 -57
- package/src/mcp-server/mdx-ast.js.map +1 -1
- package/src/mcp-server/option-filter.js +33 -47
- package/src/mcp-server/option-filter.js.map +1 -1
- package/src/mcp-server/schema-registry.d.ts +9 -3
- package/src/mcp-server/schema-registry.js +41 -38
- package/src/mcp-server/schema-registry.js.map +1 -1
- package/src/mcp-server/schema.d.ts +1 -1
- package/src/mcp-server/schema.js +9 -7
- package/src/mcp-server/schema.js.map +1 -1
- package/src/mcp-server/server.js +24 -24
- package/src/mcp-server/server.js.map +1 -1
- package/src/mcp-server/tools/add-to-existing-project.d.ts +12 -0
- package/src/mcp-server/tools/add-to-existing-project.js +36 -0
- package/src/mcp-server/tools/add-to-existing-project.js.map +1 -0
- package/src/mcp-server/tools/create-workspace-command.js +23 -24
- package/src/mcp-server/tools/create-workspace-command.js.map +1 -1
- package/src/mcp-server/tools/general-guidance.d.ts +2 -2
- package/src/mcp-server/tools/general-guidance.js +55 -32
- package/src/mcp-server/tools/general-guidance.js.map +1 -1
- package/src/mcp-server/tools/generator-guide.d.ts +1 -1
- package/src/mcp-server/tools/generator-guide.js +29 -37
- package/src/mcp-server/tools/generator-guide.js.map +1 -1
- package/src/mcp-server/tools/list-generators.d.ts +1 -1
- package/src/mcp-server/tools/list-generators.js +19 -25
- package/src/mcp-server/tools/list-generators.js.map +1 -1
- package/src/mcp-server/tools/upgrade-workspace.d.ts +11 -0
- package/src/mcp-server/tools/upgrade-workspace.js +32 -0
- package/src/mcp-server/tools/upgrade-workspace.js.map +1 -0
- package/src/migrations/latest/add-assemble-target/metadata.json +3 -0
- package/src/migrations/latest/add-assemble-target/migration.d.ts +6 -0
- package/src/migrations/latest/add-assemble-target/migration.js +241 -0
- package/src/migrations/latest/add-assemble-target/migration.js.map +1 -0
- package/src/migrations/latest/add-destroy-sandbox-target/metadata.json +3 -0
- package/src/migrations/latest/add-destroy-sandbox-target/migration.d.ts +6 -0
- package/src/migrations/latest/add-destroy-sandbox-target/migration.js +150 -0
- package/src/migrations/latest/add-destroy-sandbox-target/migration.js.map +1 -0
- package/src/migrations/latest/declare-cacheable-target-inputs/metadata.json +3 -0
- package/src/migrations/latest/declare-cacheable-target-inputs/migration.d.ts +6 -0
- package/src/migrations/latest/declare-cacheable-target-inputs/migration.js +94 -0
- package/src/migrations/latest/declare-cacheable-target-inputs/migration.js.map +1 -0
- package/src/migrations/latest/dev-target-depends-on-pull-image/metadata.json +3 -0
- package/src/migrations/latest/dev-target-depends-on-pull-image/migration.d.ts +6 -0
- package/src/migrations/latest/dev-target-depends-on-pull-image/migration.js +67 -0
- package/src/migrations/latest/dev-target-depends-on-pull-image/migration.js.map +1 -0
- package/src/migrations/latest/docker-target-cache-soundness/metadata.json +3 -0
- package/src/migrations/latest/docker-target-cache-soundness/migration.d.ts +6 -0
- package/src/migrations/latest/docker-target-cache-soundness/migration.js +95 -0
- package/src/migrations/latest/docker-target-cache-soundness/migration.js.map +1 -0
- package/src/migrations/latest/nx-parallel-default/metadata.json +3 -0
- package/src/migrations/latest/nx-parallel-default/migration.d.ts +14 -0
- package/src/migrations/latest/nx-parallel-default/migration.js +29 -0
- package/src/migrations/latest/nx-parallel-default/migration.js.map +1 -0
- package/src/migrations/latest/open-api-codegen-executor/metadata.json +3 -0
- package/src/migrations/latest/open-api-codegen-executor/migration.d.ts +6 -0
- package/src/migrations/latest/open-api-codegen-executor/migration.js +100 -0
- package/src/migrations/latest/open-api-codegen-executor/migration.js.map +1 -0
- package/src/migrations/latest/python-test-input-scoping/metadata.json +3 -0
- package/src/migrations/latest/python-test-input-scoping/migration.d.ts +6 -0
- package/src/migrations/latest/python-test-input-scoping/migration.js +142 -0
- package/src/migrations/latest/python-test-input-scoping/migration.js.map +1 -0
- package/src/migrations/latest/python-version-drop-exact-patch/metadata.json +3 -0
- package/src/migrations/latest/python-version-drop-exact-patch/migration.d.ts +6 -0
- package/src/migrations/latest/python-version-drop-exact-patch/migration.js +43 -0
- package/src/migrations/latest/python-version-drop-exact-patch/migration.js.map +1 -0
- package/src/migrations/latest/react-website-nx-react-express-override/metadata.json +3 -0
- package/src/migrations/latest/react-website-nx-react-express-override/migration.d.ts +31 -0
- package/src/migrations/latest/react-website-nx-react-express-override/migration.js +74 -0
- package/src/migrations/latest/react-website-nx-react-express-override/migration.js.map +1 -0
- package/src/migrations/latest/terraform-fmt-check/metadata.json +3 -0
- package/src/migrations/latest/terraform-fmt-check/migration.d.ts +6 -0
- package/src/migrations/latest/terraform-fmt-check/migration.js +165 -0
- package/src/migrations/latest/terraform-fmt-check/migration.js.map +1 -0
- package/src/migrations/latest/terraform-provider-plugin-cache/metadata.json +3 -0
- package/src/migrations/latest/terraform-provider-plugin-cache/migration.d.ts +6 -0
- package/src/migrations/latest/terraform-provider-plugin-cache/migration.js +164 -0
- package/src/migrations/latest/terraform-provider-plugin-cache/migration.js.map +1 -0
- package/src/migrations/latest/terraform-rdb-proxy-iam-connect-grant/__snapshots__/migration.spec.ts.snap +23 -0
- package/src/migrations/latest/terraform-rdb-proxy-iam-connect-grant/metadata.json +3 -0
- package/src/migrations/latest/terraform-rdb-proxy-iam-connect-grant/migration.d.ts +6 -0
- package/src/migrations/latest/terraform-rdb-proxy-iam-connect-grant/migration.js +88 -0
- package/src/migrations/latest/terraform-rdb-proxy-iam-connect-grant/migration.js.map +1 -0
- package/src/migrations/latest/vitest-coverage-output-dir/metadata.json +3 -0
- package/src/migrations/latest/vitest-coverage-output-dir/migration.d.ts +6 -0
- package/src/migrations/latest/vitest-coverage-output-dir/migration.js +177 -0
- package/src/migrations/latest/vitest-coverage-output-dir/migration.js.map +1 -0
- package/src/migrations/v1.0.0-rc.50/0001-modernize-function-props-cast/metadata.json +3 -0
- package/src/migrations/v1.0.0-rc.50/0001-modernize-function-props-cast/migration.d.ts +6 -0
- package/src/migrations/v1.0.0-rc.50/0001-modernize-function-props-cast/migration.js +65 -0
- package/src/migrations/v1.0.0-rc.50/0001-modernize-function-props-cast/migration.js.map +1 -0
- package/src/migrations/v1.0.0-rc.50/0002-restrict-cors-to-custom-domains/metadata.json +3 -0
- package/src/migrations/v1.0.0-rc.50/0002-restrict-cors-to-custom-domains/migration.d.ts +6 -0
- package/src/migrations/v1.0.0-rc.50/0002-restrict-cors-to-custom-domains/migration.js +108 -0
- package/src/migrations/v1.0.0-rc.50/0002-restrict-cors-to-custom-domains/migration.js.map +1 -0
- package/src/migrations/v1.0.0-rc.50/0003-terraform-bootstrap-adopt-existing-bucket/metadata.json +3 -0
- package/src/migrations/v1.0.0-rc.50/0003-terraform-bootstrap-adopt-existing-bucket/migration.d.ts +6 -0
- package/src/migrations/v1.0.0-rc.50/0003-terraform-bootstrap-adopt-existing-bucket/migration.js +128 -0
- package/src/migrations/v1.0.0-rc.50/0003-terraform-bootstrap-adopt-existing-bucket/migration.js.map +1 -0
- package/src/migrations/v1.0.0-rc.52/0001-user-identity-waf-allow-localhost-callback/metadata.json +3 -0
- package/src/migrations/v1.0.0-rc.52/0001-user-identity-waf-allow-localhost-callback/migration.d.ts +6 -0
- package/src/migrations/v1.0.0-rc.52/0001-user-identity-waf-allow-localhost-callback/migration.js +215 -0
- package/src/migrations/v1.0.0-rc.52/0001-user-identity-waf-allow-localhost-callback/migration.js.map +1 -0
- package/src/migrations/v1.0.0-rc.54/0001-order-access-log-delivery-after-bucket-policy/metadata.json +3 -0
- package/src/migrations/v1.0.0-rc.54/0001-order-access-log-delivery-after-bucket-policy/migration.d.ts +6 -0
- package/src/migrations/v1.0.0-rc.54/0001-order-access-log-delivery-after-bucket-policy/migration.js +93 -0
- package/src/migrations/v1.0.0-rc.54/0001-order-access-log-delivery-after-bucket-policy/migration.js.map +1 -0
- package/src/migrations/v1.0.0-rc.55/0001-backfill-generator-metadata/metadata.json +3 -0
- package/src/migrations/v1.0.0-rc.55/0001-backfill-generator-metadata/migration.d.ts +96 -0
- package/src/migrations/v1.0.0-rc.55/0001-backfill-generator-metadata/migration.js +670 -0
- package/src/migrations/v1.0.0-rc.55/0001-backfill-generator-metadata/migration.js.map +1 -0
- package/src/migrations/v1.0.0-rc.56/0001-dynamodb-local-remove-optimize-flag/metadata.json +3 -0
- package/src/migrations/v1.0.0-rc.56/0001-dynamodb-local-remove-optimize-flag/migration.d.ts +6 -0
- package/src/migrations/v1.0.0-rc.56/0001-dynamodb-local-remove-optimize-flag/migration.js +89 -0
- package/src/migrations/v1.0.0-rc.56/0001-dynamodb-local-remove-optimize-flag/migration.js.map +1 -0
- package/src/migrations/v1.0.0-rc.57/0001-ts-agent-session-management-support/metadata.json +3 -0
- package/src/migrations/v1.0.0-rc.57/0001-ts-agent-session-management-support/migration.d.ts +6 -0
- package/src/migrations/v1.0.0-rc.57/0001-ts-agent-session-management-support/migration.js +449 -0
- package/src/migrations/v1.0.0-rc.57/0001-ts-agent-session-management-support/migration.js.map +1 -0
- package/src/migrations/v1.0.0-rc.58/0001-smithy-ssdk-bundle-pins/metadata.json +3 -0
- package/src/migrations/v1.0.0-rc.58/0001-smithy-ssdk-bundle-pins/migration.d.ts +6 -0
- package/src/migrations/v1.0.0-rc.58/0001-smithy-ssdk-bundle-pins/migration.js +78 -0
- package/src/migrations/v1.0.0-rc.58/0001-smithy-ssdk-bundle-pins/migration.js.map +1 -0
- package/src/{smithy/project/files/build.Dockerfile.template → migrations/v1.0.0-rc.58/0001-smithy-ssdk-bundle-pins/rc57-service.Dockerfile.fixture} +1 -4
- package/src/migrations/v1.0.0-rc.59/0001-gateway-agent-targets/__snapshots__/migration.spec.ts.snap +223 -0
- package/src/migrations/v1.0.0-rc.59/0001-gateway-agent-targets/metadata.json +3 -0
- package/src/migrations/v1.0.0-rc.59/0001-gateway-agent-targets/migration.d.ts +6 -0
- package/src/migrations/v1.0.0-rc.59/0001-gateway-agent-targets/migration.js +217 -0
- package/src/migrations/v1.0.0-rc.59/0001-gateway-agent-targets/migration.js.map +1 -0
- package/src/migrations/v1.0.0-rc.60/0001-gateway-cognito-passthrough/__snapshots__/migration.spec.ts.snap +149 -0
- package/src/migrations/v1.0.0-rc.60/0001-gateway-cognito-passthrough/metadata.json +3 -0
- package/src/migrations/v1.0.0-rc.60/0001-gateway-cognito-passthrough/migration.d.ts +6 -0
- package/src/migrations/v1.0.0-rc.60/0001-gateway-cognito-passthrough/migration.js +195 -0
- package/src/migrations/v1.0.0-rc.60/0001-gateway-cognito-passthrough/migration.js.map +1 -0
- package/src/migrations/v1.0.0-rc.60/0002-waf-log-group-removal/__snapshots__/migration.spec.ts.snap +57 -0
- package/src/migrations/v1.0.0-rc.60/0002-waf-log-group-removal/metadata.json +3 -0
- package/src/migrations/v1.0.0-rc.60/0002-waf-log-group-removal/migration.d.ts +6 -0
- package/src/migrations/v1.0.0-rc.60/0002-waf-log-group-removal/migration.js +77 -0
- package/src/migrations/v1.0.0-rc.60/0002-waf-log-group-removal/migration.js.map +1 -0
- package/src/migrations/v1.0.0-rc.60/0003-strip-pip-from-python-images/__snapshots__/migration.spec.ts.snap +48 -0
- package/src/migrations/v1.0.0-rc.60/0003-strip-pip-from-python-images/metadata.json +3 -0
- package/src/migrations/v1.0.0-rc.60/0003-strip-pip-from-python-images/migration.d.ts +6 -0
- package/src/migrations/v1.0.0-rc.60/0003-strip-pip-from-python-images/migration.js +91 -0
- package/src/migrations/v1.0.0-rc.60/0003-strip-pip-from-python-images/migration.js.map +1 -0
- package/src/migrations/v1.0.0-rc.61/0001-py-agent-lifespan-construction/metadata.json +3 -0
- package/src/migrations/v1.0.0-rc.61/0001-py-agent-lifespan-construction/migration.d.ts +6 -0
- package/src/migrations/v1.0.0-rc.61/0001-py-agent-lifespan-construction/migration.js +412 -0
- package/src/migrations/v1.0.0-rc.61/0001-py-agent-lifespan-construction/migration.js.map +1 -0
- package/src/migrations/v1.0.0-rc.62/0001-rename-load-runtime-config-target/metadata.json +3 -0
- package/src/migrations/v1.0.0-rc.62/0001-rename-load-runtime-config-target/migration.d.ts +6 -0
- package/src/migrations/v1.0.0-rc.62/0001-rename-load-runtime-config-target/migration.js +33 -0
- package/src/migrations/v1.0.0-rc.62/0001-rename-load-runtime-config-target/migration.js.map +1 -0
- package/src/migrations/v1.0.0-rc.63/0001-add-deploy-sandbox-target/metadata.json +3 -0
- package/src/migrations/v1.0.0-rc.63/0001-add-deploy-sandbox-target/migration.d.ts +6 -0
- package/src/migrations/v1.0.0-rc.63/0001-add-deploy-sandbox-target/migration.js +83 -0
- package/src/migrations/v1.0.0-rc.63/0001-add-deploy-sandbox-target/migration.js.map +1 -0
- package/src/migrations/v1.0.0-rc.64/0001-smithy-build-without-docker/legacy-service.Dockerfile.fixture +95 -0
- package/src/migrations/v1.0.0-rc.64/0001-smithy-build-without-docker/metadata.json +3 -0
- package/src/migrations/v1.0.0-rc.64/0001-smithy-build-without-docker/migration.d.ts +6 -0
- package/src/migrations/v1.0.0-rc.64/0001-smithy-build-without-docker/migration.js +154 -0
- package/src/migrations/v1.0.0-rc.64/0001-smithy-build-without-docker/migration.js.map +1 -0
- package/src/migrations/v1.0.0-rc.65/0001-vite-config-import-meta-dirname/metadata.json +3 -0
- package/src/migrations/v1.0.0-rc.65/0001-vite-config-import-meta-dirname/migration.d.ts +6 -0
- package/src/migrations/v1.0.0-rc.65/0001-vite-config-import-meta-dirname/migration.js +71 -0
- package/src/migrations/v1.0.0-rc.65/0001-vite-config-import-meta-dirname/migration.js.map +1 -0
- package/src/migrations/v1.0.0-rc.65/0002-rolldown-code-splitting/metadata.json +3 -0
- package/src/migrations/v1.0.0-rc.65/0002-rolldown-code-splitting/migration.d.ts +6 -0
- package/src/migrations/v1.0.0-rc.65/0002-rolldown-code-splitting/migration.js +57 -0
- package/src/migrations/v1.0.0-rc.65/0002-rolldown-code-splitting/migration.js.map +1 -0
- package/src/migrations/v1.0.0-rc.67/0001-smithy-server-package-rename/metadata.json +3 -0
- package/src/migrations/v1.0.0-rc.67/0001-smithy-server-package-rename/migration.d.ts +6 -0
- package/src/migrations/v1.0.0-rc.67/0001-smithy-server-package-rename/migration.js +123 -0
- package/src/migrations/v1.0.0-rc.67/0001-smithy-server-package-rename/migration.js.map +1 -0
- package/src/migrations/v1.0.0-rc.68/0001-translate-script-whole-file-writes/files/build-system-prompt.ts.fixture +23 -0
- package/src/migrations/v1.0.0-rc.68/0001-translate-script-whole-file-writes/files/build-user-prompt.ts.fixture +96 -0
- package/src/migrations/v1.0.0-rc.68/0001-translate-script-whole-file-writes/files/config-path.ts.fixture +1 -0
- package/src/migrations/v1.0.0-rc.68/0001-translate-script-whole-file-writes/files/file-to-translate.ts.fixture +10 -0
- package/src/migrations/v1.0.0-rc.68/0001-translate-script-whole-file-writes/files/get-files-to-translate.ts.fixture +96 -0
- package/src/migrations/v1.0.0-rc.68/0001-translate-script-whole-file-writes/files/header.ts.fixture +15 -0
- package/src/migrations/v1.0.0-rc.68/0001-translate-script-whole-file-writes/files/log.ts.fixture +18 -0
- package/src/migrations/v1.0.0-rc.68/0001-translate-script-whole-file-writes/files/main-call.ts.fixture +6 -0
- package/src/migrations/v1.0.0-rc.68/0001-translate-script-whole-file-writes/files/main.ts.fixture +79 -0
- package/src/migrations/v1.0.0-rc.68/0001-translate-script-whole-file-writes/files/project-root.ts.fixture +1 -0
- package/src/migrations/v1.0.0-rc.68/0001-translate-script-whole-file-writes/files/run-with-concurrency.ts.fixture +57 -0
- package/src/migrations/v1.0.0-rc.68/0001-translate-script-whole-file-writes/files/scripts-dir.ts.fixture +1 -0
- package/src/migrations/v1.0.0-rc.68/0001-translate-script-whole-file-writes/files/translate-file-for-language.ts.fixture +61 -0
- package/src/migrations/v1.0.0-rc.68/0001-translate-script-whole-file-writes/grit/already-migrated.grit +1 -0
- package/src/migrations/v1.0.0-rc.68/0001-translate-script-whole-file-writes/grit/build-system-prompt.grit +6 -0
- package/src/migrations/v1.0.0-rc.68/0001-translate-script-whole-file-writes/grit/build-user-prompt.grit +6 -0
- package/src/migrations/v1.0.0-rc.68/0001-translate-script-whole-file-writes/grit/config-path.grit +1 -0
- package/src/migrations/v1.0.0-rc.68/0001-translate-script-whole-file-writes/grit/file-to-translate.grit +11 -0
- package/src/migrations/v1.0.0-rc.68/0001-translate-script-whole-file-writes/grit/get-files-to-translate.grit +7 -0
- package/src/migrations/v1.0.0-rc.68/0001-translate-script-whole-file-writes/grit/log.grit +3 -0
- package/src/migrations/v1.0.0-rc.68/0001-translate-script-whole-file-writes/grit/main-call.grit +1 -0
- package/src/migrations/v1.0.0-rc.68/0001-translate-script-whole-file-writes/grit/main.grit +8 -0
- package/src/migrations/v1.0.0-rc.68/0001-translate-script-whole-file-writes/grit/project-root.grit +1 -0
- package/src/migrations/v1.0.0-rc.68/0001-translate-script-whole-file-writes/grit/run-with-concurrency.grit +6 -0
- package/src/migrations/v1.0.0-rc.68/0001-translate-script-whole-file-writes/grit/translate-file-for-language.grit +6 -0
- package/src/migrations/v1.0.0-rc.68/0001-translate-script-whole-file-writes/metadata.json +3 -0
- package/src/migrations/v1.0.0-rc.68/0001-translate-script-whole-file-writes/migration.d.ts +2 -0
- package/src/migrations/v1.0.0-rc.68/0001-translate-script-whole-file-writes/migration.js +103 -0
- package/src/migrations/v1.0.0-rc.68/0001-translate-script-whole-file-writes/migration.js.map +1 -0
- package/src/migrations/v1.0.0-rc.68/0001-translate-script-whole-file-writes/test-fixtures/released-script-first.ts.fixture +430 -0
- package/src/migrations/v1.0.0-rc.68/0001-translate-script-whole-file-writes/test-fixtures/released-script.ts.fixture +431 -0
- package/src/migrations/v1.0.0-rc.70/0001-py-agent-a2a-lifespan-construction/metadata.json +3 -0
- package/src/migrations/v1.0.0-rc.70/0001-py-agent-a2a-lifespan-construction/migration.d.ts +6 -0
- package/src/migrations/v1.0.0-rc.70/0001-py-agent-a2a-lifespan-construction/migration.js +246 -0
- package/src/migrations/v1.0.0-rc.70/0001-py-agent-a2a-lifespan-construction/migration.js.map +1 -0
- package/src/migrations/v1.0.0-rc.71/0001-py-agent-a2a-httpx-client-per-call/metadata.json +3 -0
- package/src/migrations/v1.0.0-rc.71/0001-py-agent-a2a-httpx-client-per-call/migration.d.ts +6 -0
- package/src/migrations/v1.0.0-rc.71/0001-py-agent-a2a-httpx-client-per-call/migration.js +329 -0
- package/src/migrations/v1.0.0-rc.71/0001-py-agent-a2a-httpx-client-per-call/migration.js.map +1 -0
- package/src/migrations/v1.0.0-rc.72/0001-py-agent-session-management-support/metadata.json +3 -0
- package/src/migrations/v1.0.0-rc.72/0001-py-agent-session-management-support/migration.d.ts +2 -0
- package/src/migrations/v1.0.0-rc.72/0001-py-agent-session-management-support/migration.js +308 -0
- package/src/migrations/v1.0.0-rc.72/0001-py-agent-session-management-support/migration.js.map +1 -0
- package/src/migrations/v1.0.0-rc.73/0001-remove-mcp-inspector-license-exceptions/metadata.json +3 -0
- package/{sdk/utils/ast.d.ts → src/migrations/v1.0.0-rc.73/0001-remove-mcp-inspector-license-exceptions/migration.d.ts} +2 -2
- package/src/migrations/v1.0.0-rc.73/0001-remove-mcp-inspector-license-exceptions/migration.js +38 -0
- package/src/migrations/v1.0.0-rc.73/0001-remove-mcp-inspector-license-exceptions/migration.js.map +1 -0
- package/src/migrations/v1.0.0-rc.73/0002-apt-security-updates-in-container-images/__snapshots__/migration.spec.ts.snap +90 -0
- package/src/migrations/v1.0.0-rc.73/0002-apt-security-updates-in-container-images/metadata.json +3 -0
- package/src/migrations/v1.0.0-rc.73/0002-apt-security-updates-in-container-images/migration.d.ts +6 -0
- package/src/migrations/v1.0.0-rc.73/0002-apt-security-updates-in-container-images/migration.js +90 -0
- package/src/migrations/v1.0.0-rc.73/0002-apt-security-updates-in-container-images/migration.js.map +1 -0
- package/src/migrations/v1.0.0-rc.74/0001-py-agent-session-id-middleware-extraction/metadata.json +3 -0
- package/src/migrations/v1.0.0-rc.74/0001-py-agent-session-id-middleware-extraction/migration.d.ts +2 -0
- package/src/migrations/v1.0.0-rc.74/0001-py-agent-session-id-middleware-extraction/migration.js +118 -0
- package/src/migrations/v1.0.0-rc.74/0001-py-agent-session-id-middleware-extraction/migration.js.map +1 -0
- package/src/migrations/v1.0.0-rc.75/0001-ts-agent-session-id-middleware-extraction/metadata.json +3 -0
- package/src/migrations/v1.0.0-rc.75/0001-ts-agent-session-id-middleware-extraction/migration.d.ts +2 -0
- package/src/migrations/v1.0.0-rc.75/0001-ts-agent-session-id-middleware-extraction/migration.js +136 -0
- package/src/migrations/v1.0.0-rc.75/0001-ts-agent-session-id-middleware-extraction/migration.js.map +1 -0
- package/src/migrations/v1.0.0-rc.77/0001-dynamodb-configurable-encryption/__snapshots__/migration.spec.ts.snap +429 -0
- package/src/migrations/v1.0.0-rc.77/0001-dynamodb-configurable-encryption/metadata.json +3 -0
- package/src/migrations/v1.0.0-rc.77/0001-dynamodb-configurable-encryption/migration.d.ts +6 -0
- package/src/migrations/v1.0.0-rc.77/0001-dynamodb-configurable-encryption/migration.js +325 -0
- package/src/migrations/v1.0.0-rc.77/0001-dynamodb-configurable-encryption/migration.js.map +1 -0
- package/src/migrations/v1.0.0-rc.77/0002-user-identity-configurable-mfa/metadata.json +3 -0
- package/src/migrations/v1.0.0-rc.77/0002-user-identity-configurable-mfa/migration.d.ts +6 -0
- package/src/migrations/v1.0.0-rc.77/0002-user-identity-configurable-mfa/migration.js +362 -0
- package/src/migrations/v1.0.0-rc.77/0002-user-identity-configurable-mfa/migration.js.map +1 -0
- package/src/migrations/v1.0.0-rc.78/0001-static-website-configurable-waf-encryption/metadata.json +3 -0
- package/src/migrations/v1.0.0-rc.78/0001-static-website-configurable-waf-encryption/migration.d.ts +6 -0
- package/src/migrations/v1.0.0-rc.78/0001-static-website-configurable-waf-encryption/migration.js +418 -0
- package/src/migrations/v1.0.0-rc.78/0001-static-website-configurable-waf-encryption/migration.js.map +1 -0
- package/src/migrations/v1.0.0-rc.79/0001-py-agent-ag-ui-hooks/metadata.json +3 -0
- package/src/migrations/v1.0.0-rc.79/0001-py-agent-ag-ui-hooks/migration.d.ts +6 -0
- package/src/migrations/v1.0.0-rc.79/0001-py-agent-ag-ui-hooks/migration.js +113 -0
- package/src/migrations/v1.0.0-rc.79/0001-py-agent-ag-ui-hooks/migration.js.map +1 -0
- package/src/migrations/v1.0.0-rc.82/0001-terraform-load-runtime-config-src-path/metadata.json +3 -0
- package/src/migrations/v1.0.0-rc.82/0001-terraform-load-runtime-config-src-path/migration.d.ts +6 -0
- package/src/migrations/v1.0.0-rc.82/0001-terraform-load-runtime-config-src-path/migration.js +48 -0
- package/src/migrations/v1.0.0-rc.82/0001-terraform-load-runtime-config-src-path/migration.js.map +1 -0
- package/src/migrations/v1.0.0-rc.82/0002-runtime-config-namespace-defaults/metadata.json +3 -0
- package/src/migrations/v1.0.0-rc.82/0002-runtime-config-namespace-defaults/migration.d.ts +6 -0
- package/src/migrations/v1.0.0-rc.82/0002-runtime-config-namespace-defaults/migration.js +131 -0
- package/src/migrations/v1.0.0-rc.82/0002-runtime-config-namespace-defaults/migration.js.map +1 -0
- package/src/migrations/v1.0.0-rc.83/0001-dynamodb-terraform-app-module-outputs/metadata.json +3 -0
- package/src/migrations/v1.0.0-rc.83/0001-dynamodb-terraform-app-module-outputs/migration.d.ts +6 -0
- package/src/migrations/v1.0.0-rc.83/0001-dynamodb-terraform-app-module-outputs/migration.js +69 -0
- package/src/migrations/v1.0.0-rc.83/0001-dynamodb-terraform-app-module-outputs/migration.js.map +1 -0
- package/src/migrations/v1.0.0-rc.83/0002-terraform-data-resource-destroy-protection/__snapshots__/migration.spec.ts.snap +75 -0
- package/src/migrations/v1.0.0-rc.83/0002-terraform-data-resource-destroy-protection/metadata.json +3 -0
- package/src/migrations/v1.0.0-rc.83/0002-terraform-data-resource-destroy-protection/migration.d.ts +6 -0
- package/src/migrations/v1.0.0-rc.83/0002-terraform-data-resource-destroy-protection/migration.js +78 -0
- package/src/migrations/v1.0.0-rc.83/0002-terraform-data-resource-destroy-protection/migration.js.map +1 -0
- package/src/migrations/v1.0.0-rc.83/0003-terraform-gateway-cedar-render-root-ejs/metadata.json +3 -0
- package/src/migrations/v1.0.0-rc.83/0003-terraform-gateway-cedar-render-root-ejs/migration.d.ts +6 -0
- package/src/migrations/v1.0.0-rc.83/0003-terraform-gateway-cedar-render-root-ejs/migration.js +38 -0
- package/src/migrations/v1.0.0-rc.83/0003-terraform-gateway-cedar-render-root-ejs/migration.js.map +1 -0
- package/src/migrations/v1.0.0-rc.84/0001-rdb-terraform-aurora-app-module-defaults/__snapshots__/migration.spec.ts.snap +54 -0
- package/src/migrations/v1.0.0-rc.84/0001-rdb-terraform-aurora-app-module-defaults/metadata.json +3 -0
- package/src/migrations/v1.0.0-rc.84/0001-rdb-terraform-aurora-app-module-defaults/migration.d.ts +6 -0
- package/src/migrations/v1.0.0-rc.84/0001-rdb-terraform-aurora-app-module-defaults/migration.js +86 -0
- package/src/migrations/v1.0.0-rc.84/0001-rdb-terraform-aurora-app-module-defaults/migration.js.map +1 -0
- package/src/migrations/v1.0.0-rc.84/0002-agentcore-harness-no-tools-by-default/__snapshots__/migration.spec.ts.snap +79 -0
- package/src/migrations/v1.0.0-rc.84/0002-agentcore-harness-no-tools-by-default/metadata.json +3 -0
- package/src/migrations/v1.0.0-rc.84/0002-agentcore-harness-no-tools-by-default/migration.d.ts +6 -0
- package/src/migrations/v1.0.0-rc.84/0002-agentcore-harness-no-tools-by-default/migration.js +87 -0
- package/src/migrations/v1.0.0-rc.84/0002-agentcore-harness-no-tools-by-default/migration.js.map +1 -0
- package/src/migrations/v1.0.0-rc.84/0003-terraform-declare-used-providers/metadata.json +3 -0
- package/src/migrations/v1.0.0-rc.84/0003-terraform-declare-used-providers/migration.d.ts +6 -0
- package/src/migrations/v1.0.0-rc.84/0003-terraform-declare-used-providers/migration.js +147 -0
- package/src/migrations/v1.0.0-rc.84/0003-terraform-declare-used-providers/migration.js.map +1 -0
- package/src/migrations/v1.0.0-rc.84/0004-waf-log-group-cmk-encryption/__snapshots__/migration.spec.ts.snap +286 -0
- package/src/migrations/v1.0.0-rc.84/0004-waf-log-group-cmk-encryption/metadata.json +3 -0
- package/src/migrations/v1.0.0-rc.84/0004-waf-log-group-cmk-encryption/migration.d.ts +6 -0
- package/src/migrations/v1.0.0-rc.84/0004-waf-log-group-cmk-encryption/migration.js +238 -0
- package/src/migrations/v1.0.0-rc.84/0004-waf-log-group-cmk-encryption/migration.js.map +1 -0
- package/src/migrations/v1.0.0-rc.84/0005-terraform-harness-vpc-role-and-memory-grant/__snapshots__/migration.spec.ts.snap +521 -0
- package/src/migrations/v1.0.0-rc.84/0005-terraform-harness-vpc-role-and-memory-grant/metadata.json +3 -0
- package/src/migrations/v1.0.0-rc.84/0005-terraform-harness-vpc-role-and-memory-grant/migration.d.ts +6 -0
- package/src/migrations/v1.0.0-rc.84/0005-terraform-harness-vpc-role-and-memory-grant/migration.js +504 -0
- package/src/migrations/v1.0.0-rc.84/0005-terraform-harness-vpc-role-and-memory-grant/migration.js.map +1 -0
- package/src/migrations/v1.0.0-rc.85/0001-terraform-project-checkov-target-and-bootstrap-destroy/metadata.json +3 -0
- package/src/migrations/v1.0.0-rc.85/0001-terraform-project-checkov-target-and-bootstrap-destroy/migration.d.ts +6 -0
- package/src/migrations/v1.0.0-rc.85/0001-terraform-project-checkov-target-and-bootstrap-destroy/migration.js +146 -0
- package/src/migrations/v1.0.0-rc.85/0001-terraform-project-checkov-target-and-bootstrap-destroy/migration.js.map +1 -0
- package/src/open-api/codegen/executor-schema.d.js +6 -0
- package/src/open-api/codegen/executor-schema.d.js.map +1 -0
- package/src/open-api/codegen/executor-schema.d.ts +18 -0
- package/src/open-api/codegen/executor-schema.json +33 -0
- package/src/open-api/codegen/executor.d.ts +18 -0
- package/src/open-api/codegen/executor.js +56 -0
- package/src/open-api/codegen/executor.js.map +1 -0
- package/src/open-api/json-metadata/generator.d.ts +24 -0
- package/src/open-api/json-metadata/generator.js +37 -0
- package/src/open-api/json-metadata/generator.js.map +1 -0
- package/src/open-api/json-metadata/schema.d.js +6 -0
- package/src/open-api/json-metadata/schema.d.js.map +1 -0
- package/src/open-api/json-metadata/schema.d.ts +9 -0
- package/src/open-api/json-metadata/schema.json +20 -0
- package/src/open-api/ts-client/__snapshots__/generator.additional-properties.spec.ts.snap +147 -33
- package/src/open-api/ts-client/__snapshots__/generator.arrays.spec.ts.snap +308 -75
- package/src/open-api/ts-client/__snapshots__/generator.complex-types.spec.ts.snap +298 -74
- package/src/open-api/ts-client/__snapshots__/generator.composite-types.spec.ts.snap +748 -103
- package/src/open-api/ts-client/__snapshots__/generator.content-type.spec.ts.snap +230 -37
- package/src/open-api/ts-client/__snapshots__/generator.duplicate-types.spec.ts.snap +249 -52
- package/src/open-api/ts-client/__snapshots__/generator.edge-cases.spec.ts.snap +5535 -0
- package/src/open-api/ts-client/__snapshots__/generator.fast-api-gaps.spec.ts.snap +736 -0
- package/src/open-api/ts-client/__snapshots__/generator.fast-api.spec.ts.snap +305 -71
- package/src/open-api/ts-client/__snapshots__/generator.multipart.spec.ts.snap +298 -0
- package/src/open-api/ts-client/__snapshots__/generator.primitive-types.spec.ts.snap +353 -82
- package/src/open-api/ts-client/__snapshots__/generator.request.spec.ts.snap +176 -55
- package/src/open-api/ts-client/__snapshots__/generator.reserved-keywords.spec.ts.snap +100 -24
- package/src/open-api/ts-client/__snapshots__/generator.response.spec.ts.snap +147 -33
- package/src/open-api/ts-client/__snapshots__/generator.spec-compliance.spec.ts.snap +1883 -0
- package/src/open-api/ts-client/__snapshots__/generator.streaming.spec.ts.snap +392 -88
- package/src/open-api/ts-client/__snapshots__/generator.tags.spec.ts.snap +200 -48
- package/src/open-api/ts-client/files/client.gen.ts.template +358 -24
- package/src/open-api/ts-client/files/types.gen.ts.template +6 -4
- package/src/open-api/ts-client/generator.d.ts +1 -1
- package/src/open-api/ts-client/generator.js +41 -26
- package/src/open-api/ts-client/generator.js.map +1 -1
- package/src/open-api/ts-client/schema.d.js +6 -0
- package/src/open-api/ts-client/schema.d.js.map +1 -0
- package/src/open-api/ts-hooks/files/options-proxy.gen.ts.template +7 -2
- package/src/open-api/ts-hooks/generator.d.ts +1 -1
- package/src/open-api/ts-hooks/generator.js +17 -21
- package/src/open-api/ts-hooks/generator.js.map +1 -1
- package/src/open-api/ts-hooks/generator.spec.tsx +76 -6
- package/src/open-api/ts-hooks/schema.d.js +6 -0
- package/src/open-api/ts-hooks/schema.d.js.map +1 -0
- package/src/open-api/ts-metadata/generator.d.ts +1 -1
- package/src/open-api/ts-metadata/generator.js +12 -20
- package/src/open-api/ts-metadata/generator.js.map +1 -1
- package/src/open-api/ts-metadata/schema.d.js +6 -0
- package/src/open-api/ts-metadata/schema.d.js.map +1 -0
- package/src/open-api/utils/codegen-data/languages.d.ts +1 -7
- package/src/open-api/utils/codegen-data/languages.js +59 -66
- package/src/open-api/utils/codegen-data/languages.js.map +1 -1
- package/src/open-api/utils/codegen-data/types.d.ts +255 -10
- package/src/open-api/utils/codegen-data/types.js +54 -30
- package/src/open-api/utils/codegen-data/types.js.map +1 -1
- package/src/open-api/utils/codegen-data.d.ts +4 -4
- package/src/open-api/utils/codegen-data.js +494 -674
- package/src/open-api/utils/codegen-data.js.map +1 -1
- package/src/open-api/utils/normalise.d.ts +1 -1
- package/src/open-api/utils/normalise.js +437 -246
- package/src/open-api/utils/normalise.js.map +1 -1
- package/src/open-api/utils/parse.d.ts +1 -1
- package/src/open-api/utils/parse.js +8 -14
- package/src/open-api/utils/parse.js.map +1 -1
- package/src/open-api/utils/parser.d.ts +55 -0
- package/src/open-api/utils/parser.js +787 -0
- package/src/open-api/utils/parser.js.map +1 -0
- package/src/open-api/utils/refs.d.ts +1 -1
- package/src/open-api/utils/refs.js +12 -22
- package/src/open-api/utils/refs.js.map +1 -1
- package/src/open-api/utils/types.d.ts +18 -0
- package/src/open-api/utils/types.js +5 -2
- package/src/open-api/utils/types.js.map +1 -1
- package/src/preset/__snapshots__/generator.spec.ts.snap +104 -21
- package/src/preset/generator.d.ts +15 -2
- package/src/preset/generator.js +76 -151
- package/src/preset/generator.js.map +1 -1
- package/src/preset/schema.d.js +6 -0
- package/src/preset/schema.d.js.map +1 -0
- package/src/preset/schema.d.ts +6 -3
- package/src/preset/schema.json +16 -5
- package/src/py/agent/__snapshots__/generator.constructs.spec.ts.snap +931 -0
- package/src/py/agent/__snapshots__/generator.core.spec.ts.snap +186 -0
- package/src/py/agent/__snapshots__/generator.frameworks.spec.ts.snap +771 -0
- package/src/py/agent/__snapshots__/generator.protocols.spec.ts.snap +1322 -0
- package/src/py/agent/a2a-connection/__snapshots__/generator.spec.ts.snap +231 -0
- package/src/py/agent/a2a-connection/files/agent-connection/app/__targetAgentSnakeCase___client_strands.py.template +29 -0
- package/src/py/agent/a2a-connection/files/langchain/agent-connection/app/__targetAgentSnakeCase___client_langchain.py.template +29 -0
- package/src/py/agent/a2a-connection/generator.d.ts +25 -1
- package/src/py/agent/a2a-connection/generator.js +146 -95
- package/src/py/agent/a2a-connection/generator.js.map +1 -1
- package/src/py/agent/a2a-connection/schema.d.js +8 -0
- package/src/py/agent/a2a-connection/schema.d.js.map +1 -0
- package/src/py/agent/a2a-connection/schema.d.ts +2 -1
- package/src/py/agent/a2a-connection/schema.json +5 -0
- package/src/py/agent/files/deploy/Dockerfile.template +15 -1
- package/src/py/agent/files/langchain/a2a/main.py.template +83 -0
- package/src/py/agent/files/langchain/ag-ui/main.py.template +76 -0
- package/src/py/agent/files/langchain/common/agent.py.template +30 -0
- package/src/py/agent/files/langchain/common/middleware/__init__.py.template +0 -0
- package/src/py/agent/files/langchain/common/middleware/session_id_middleware.py.template +17 -0
- package/src/py/agent/files/langchain/common/session.py.template +61 -0
- package/src/py/agent/files/{http → langchain/http}/init.py.template +17 -25
- package/src/py/agent/files/langchain/http/main.py.template +69 -0
- package/src/py/agent/files/strands/a2a/main.py.template +61 -0
- package/src/py/agent/files/strands/ag-ui/main.py.template +86 -0
- package/src/py/agent/files/strands/common/__init__.py.template +0 -0
- package/src/py/agent/files/{common → strands/common}/agent.py.template +13 -2
- package/src/py/agent/files/strands/common/middleware/__init__.py.template +0 -0
- package/src/py/agent/files/strands/common/middleware/session_id_middleware.py.template +17 -0
- package/src/py/agent/files/strands/common/session.py.template +36 -0
- package/src/py/agent/files/strands/http/init.py.template +97 -0
- package/src/py/agent/files/{http → strands/http}/main.py.template +5 -29
- package/src/py/agent/gateway-connection/__snapshots__/generator.spec.ts.snap +184 -0
- package/src/py/agent/gateway-connection/files/agent-connection/app/__gatewaySnakeCase___client_strands.py.template +35 -0
- package/src/py/agent/gateway-connection/files/langchain/agent-connection/app/__gatewaySnakeCase___client_langchain.py.template +34 -0
- package/src/py/agent/gateway-connection/generator.d.ts +33 -0
- package/src/py/agent/gateway-connection/generator.js +153 -0
- package/src/py/agent/gateway-connection/generator.js.map +1 -0
- package/src/py/agent/gateway-connection/schema.d.js +6 -0
- package/src/py/agent/gateway-connection/schema.d.js.map +1 -0
- package/src/py/agent/gateway-connection/schema.d.ts +13 -0
- package/src/py/agent/gateway-connection/schema.json +31 -0
- package/src/py/agent/generator.d.ts +165 -2
- package/src/py/agent/generator.js +445 -199
- package/src/py/agent/generator.js.map +1 -1
- package/src/py/agent/mcp-connection/__snapshots__/generator.spec.ts.snap +155 -92
- package/src/py/agent/mcp-connection/files/agent-connection/app/__mcpServerSnakeCase___client_strands.py.template +31 -0
- package/src/py/agent/mcp-connection/files/langchain/agent-connection/app/__mcpServerSnakeCase___client_langchain.py.template +31 -0
- package/src/py/agent/mcp-connection/generator.d.ts +24 -1
- package/src/py/agent/mcp-connection/generator.js +103 -130
- package/src/py/agent/mcp-connection/generator.js.map +1 -1
- package/src/py/agent/mcp-connection/schema.d.js +8 -0
- package/src/py/agent/mcp-connection/schema.d.js.map +1 -0
- package/src/py/agent/mcp-connection/schema.d.ts +2 -1
- package/src/py/agent/mcp-connection/schema.json +5 -0
- package/src/py/agent/react-connection/__snapshots__/generator.spec.ts.snap +17 -19
- package/src/py/agent/react-connection/generator.d.ts +152 -3
- package/src/py/agent/react-connection/generator.js +114 -65
- package/src/py/agent/react-connection/generator.js.map +1 -1
- package/src/py/agent/react-connection/{serve-local.d.ts → local-dev.d.ts} +5 -5
- package/src/py/agent/react-connection/local-dev.js +36 -0
- package/src/py/agent/react-connection/local-dev.js.map +1 -0
- package/src/py/agent/react-connection/schema.d.js +8 -0
- package/src/py/agent/react-connection/schema.d.js.map +1 -0
- package/src/py/agent/react-connection/schema.d.ts +2 -1
- package/src/py/agent/react-connection/schema.json +5 -0
- package/src/py/agent/schema.d.js +6 -0
- package/src/py/agent/schema.d.js.map +1 -0
- package/src/py/agent/schema.d.ts +6 -2
- package/src/py/agent/schema.json +15 -1
- package/src/py/api/generator.d.ts +1 -1
- package/src/py/api/generator.js +12 -11
- package/src/py/api/generator.js.map +1 -1
- package/src/py/api/schema.d.js +6 -0
- package/src/py/api/schema.d.js.map +1 -0
- package/src/py/api/schema.d.ts +2 -1
- package/src/py/api/schema.json +5 -0
- package/src/py/dynamodb/__snapshots__/generator.spec.ts.snap +1592 -0
- package/src/py/dynamodb/agent-connection/__snapshots__/generator.spec.ts.snap +63 -0
- package/src/py/dynamodb/agent-connection/generator.d.ts +10 -0
- package/src/py/dynamodb/agent-connection/generator.js +45 -0
- package/src/py/dynamodb/agent-connection/generator.js.map +1 -0
- package/src/py/dynamodb/agent-connection/schema.d.js +8 -0
- package/src/py/dynamodb/agent-connection/schema.d.js.map +1 -0
- package/src/py/dynamodb/agent-connection/schema.d.ts +15 -0
- package/src/py/dynamodb/agent-connection/schema.json +27 -0
- package/src/py/dynamodb/fast-api-connection/__snapshots__/generator.spec.ts.snap +32 -0
- package/src/py/dynamodb/fast-api-connection/generator.d.ts +10 -0
- package/src/py/dynamodb/fast-api-connection/generator.js +39 -0
- package/src/py/dynamodb/fast-api-connection/generator.js.map +1 -0
- package/src/py/dynamodb/fast-api-connection/schema.d.js +8 -0
- package/src/py/dynamodb/fast-api-connection/schema.d.js.map +1 -0
- package/src/py/dynamodb/fast-api-connection/schema.d.ts +13 -0
- package/src/py/dynamodb/fast-api-connection/schema.json +23 -0
- package/src/py/dynamodb/files/__name__/__init__.py.template +6 -0
- package/src/py/dynamodb/files/__name__/client.py.template +39 -0
- package/src/py/dynamodb/files/__name__/entities/__init__.py.template +4 -0
- package/src/py/dynamodb/files/__name__/entities/base.py.template +63 -0
- package/src/py/dynamodb/files/__name__/entities/example.py.template +64 -0
- package/src/py/dynamodb/files/config.json.template +24 -0
- package/src/py/dynamodb/generator.d.ts +39 -0
- package/src/py/dynamodb/generator.js +130 -0
- package/src/py/dynamodb/generator.js.map +1 -0
- package/src/py/dynamodb/mcp-server-connection/__snapshots__/generator.spec.ts.snap +63 -0
- package/src/py/dynamodb/mcp-server-connection/generator.d.ts +10 -0
- package/src/py/dynamodb/mcp-server-connection/generator.js +45 -0
- package/src/py/dynamodb/mcp-server-connection/generator.js.map +1 -0
- package/src/py/dynamodb/mcp-server-connection/schema.d.js +8 -0
- package/src/py/dynamodb/mcp-server-connection/schema.d.js.map +1 -0
- package/src/py/dynamodb/mcp-server-connection/schema.d.ts +15 -0
- package/src/py/dynamodb/mcp-server-connection/schema.json +27 -0
- package/src/py/dynamodb/schema.d.js +6 -0
- package/src/py/dynamodb/schema.d.js.map +1 -0
- package/src/py/dynamodb/schema.d.ts +16 -0
- package/src/py/dynamodb/schema.json +76 -0
- package/src/py/fast-api/__snapshots__/generator.spec.ts.snap +240 -4693
- package/src/py/fast-api/__snapshots__/generator.terraform.spec.ts.snap +6661 -0
- package/src/py/fast-api/files/app/__name__/init.py.template +5 -22
- package/src/py/fast-api/files/app/__name__/main.py.template +4 -1
- package/src/py/fast-api/generator.d.ts +73 -1
- package/src/py/fast-api/generator.js +126 -92
- package/src/py/fast-api/generator.js.map +1 -1
- package/src/py/fast-api/react/__snapshots__/generator.spec.ts.snap +4 -3
- package/src/py/fast-api/react/generator.d.ts +17 -2
- package/src/py/fast-api/react/generator.js +38 -26
- package/src/py/fast-api/react/generator.js.map +1 -1
- package/src/py/fast-api/react/open-api.js +44 -33
- package/src/py/fast-api/react/open-api.js.map +1 -1
- package/src/py/fast-api/react/schema.d.js +6 -0
- package/src/py/fast-api/react/schema.d.js.map +1 -0
- package/src/py/fast-api/react/schema.d.ts +1 -0
- package/src/py/fast-api/react/schema.json +5 -0
- package/src/py/fast-api/schema.d.js +6 -0
- package/src/py/fast-api/schema.d.js.map +1 -0
- package/src/py/fast-api/schema.d.ts +2 -1
- package/src/py/fast-api/schema.json +6 -0
- package/src/py/lambda-function/__snapshots__/generator.spec.ts.snap +12 -4
- package/src/py/lambda-function/files/handler/__lambdaFunctionSnakeCase__.py.template +1 -1
- package/src/py/lambda-function/generator.d.ts +28 -1
- package/src/py/lambda-function/generator.js +88 -61
- package/src/py/lambda-function/generator.js.map +1 -1
- package/src/py/lambda-function/schema.d.js +6 -0
- package/src/py/lambda-function/schema.d.js.map +1 -0
- package/src/py/lambda-function/schema.d.ts +3 -2
- package/src/py/lambda-function/schema.json +6 -1
- package/src/py/mcp-server/__snapshots__/generator.spec.ts.snap +225 -21
- package/src/py/mcp-server/files/deploy/Dockerfile.template +15 -1
- package/src/py/mcp-server/generator.d.ts +69 -1
- package/src/py/mcp-server/generator.js +211 -137
- package/src/py/mcp-server/generator.js.map +1 -1
- package/src/py/mcp-server/schema.d.js +6 -0
- package/src/py/mcp-server/schema.d.js.map +1 -0
- package/src/py/mcp-server/schema.d.ts +2 -1
- package/src/py/mcp-server/schema.json +6 -0
- package/src/py/project/generator.d.ts +37 -2
- package/src/py/project/generator.js +246 -90
- package/src/py/project/generator.js.map +1 -1
- package/src/py/project/schema.d.js +6 -0
- package/src/py/project/schema.d.js.map +1 -0
- package/src/py/project/schema.d.ts +1 -0
- package/src/py/project/schema.json +6 -0
- package/src/py/rdb/__snapshots__/generator.spec.ts.snap +2113 -0
- package/src/py/rdb/agent-connection/__snapshots__/generator.spec.ts.snap +123 -0
- package/src/py/rdb/agent-connection/generator.d.ts +10 -0
- package/src/py/rdb/agent-connection/generator.js +52 -0
- package/src/py/rdb/agent-connection/generator.js.map +1 -0
- package/src/py/rdb/agent-connection/schema.d.js +8 -0
- package/src/py/rdb/agent-connection/schema.d.js.map +1 -0
- package/src/py/rdb/agent-connection/schema.d.ts +15 -0
- package/src/py/rdb/agent-connection/schema.json +27 -0
- package/src/py/rdb/fast-api-connection/__snapshots__/generator.spec.ts.snap +51 -0
- package/src/py/rdb/fast-api-connection/files/__apiModuleName__/dependencies/__rdbNameSnake__.py.template +14 -0
- package/src/py/rdb/fast-api-connection/generator.d.ts +10 -0
- package/src/py/rdb/fast-api-connection/generator.js +56 -0
- package/src/py/rdb/fast-api-connection/generator.js.map +1 -0
- package/src/py/rdb/fast-api-connection/schema.d.js +8 -0
- package/src/py/rdb/fast-api-connection/schema.d.js.map +1 -0
- package/src/py/rdb/fast-api-connection/schema.d.ts +13 -0
- package/src/py/rdb/fast-api-connection/schema.json +23 -0
- package/src/py/rdb/files/Dockerfile.create-db-user.template +14 -0
- package/src/py/rdb/files/Dockerfile.migration.template +14 -0
- package/src/py/rdb/files/__name__/connection.py.template +55 -0
- package/src/py/rdb/files/__name__/create_db_user_handler.py.template +97 -0
- package/src/py/rdb/files/__name__/migration_handler.py.template +36 -0
- package/src/py/rdb/files/__name__/models/__init__.py.template +3 -0
- package/src/py/rdb/files/__name__/models/example.py.template +8 -0
- package/src/py/rdb/files/__name__/utils.py.template +120 -0
- package/src/py/rdb/files/alembic.ini.template +38 -0
- package/src/py/rdb/files/migrations/env.py.template +80 -0
- package/src/py/rdb/files/migrations/script.py.mako.template +28 -0
- package/src/py/rdb/generator.d.ts +103 -0
- package/src/py/rdb/generator.js +368 -0
- package/src/py/rdb/generator.js.map +1 -0
- package/src/py/rdb/mcp-server-connection/__snapshots__/generator.spec.ts.snap +119 -0
- package/src/py/rdb/mcp-server-connection/generator.d.ts +10 -0
- package/src/py/rdb/mcp-server-connection/generator.js +52 -0
- package/src/py/rdb/mcp-server-connection/generator.js.map +1 -0
- package/src/py/rdb/mcp-server-connection/schema.d.js +8 -0
- package/src/py/rdb/mcp-server-connection/schema.d.js.map +1 -0
- package/src/py/rdb/mcp-server-connection/schema.d.ts +15 -0
- package/src/py/rdb/mcp-server-connection/schema.json +27 -0
- package/src/py/rdb/schema.d.js +6 -0
- package/src/py/rdb/schema.d.js.map +1 -0
- package/src/py/rdb/schema.d.ts +16 -0
- package/src/py/rdb/schema.json +78 -0
- package/src/py/rdb/utils.d.ts +6 -0
- package/src/py/rdb/utils.js +16 -0
- package/src/py/rdb/utils.js.map +1 -0
- package/src/sdk/agentcore-gateway.d.ts +6 -0
- package/src/sdk/agentcore-gateway.js +7 -0
- package/src/sdk/agentcore-gateway.js.map +1 -0
- package/src/sdk/agentcore-harness.d.ts +6 -0
- package/src/sdk/agentcore-harness.js +7 -0
- package/src/sdk/agentcore-harness.js.map +1 -0
- package/src/sdk/connection.d.ts +6 -0
- package/src/sdk/connection.js +6 -0
- package/src/sdk/connection.js.map +1 -0
- package/src/sdk/license.d.ts +8 -0
- package/src/sdk/license.js +7 -0
- package/src/sdk/license.js.map +1 -0
- package/src/sdk/open-api.d.ts +12 -0
- package/src/sdk/open-api.js +9 -0
- package/src/sdk/open-api.js.map +1 -0
- package/src/sdk/py.d.ts +18 -0
- package/src/sdk/py.js +12 -0
- package/src/sdk/py.js.map +1 -0
- package/src/sdk/smithy.d.ts +6 -0
- package/src/sdk/smithy.js +7 -0
- package/src/sdk/smithy.js.map +1 -0
- package/src/sdk/terraform.d.ts +6 -0
- package/src/sdk/terraform.js +7 -0
- package/src/sdk/terraform.js.map +1 -0
- package/src/sdk/ts.d.ts +39 -0
- package/src/sdk/ts.js +41 -0
- package/src/sdk/ts.js.map +1 -0
- package/{sdk/utils/format.d.ts → src/sdk/utils/ast.d.ts} +1 -1
- package/src/sdk/utils/ast.js +6 -0
- package/src/sdk/utils/ast.js.map +1 -0
- package/src/sdk/utils/format.d.ts +5 -0
- package/src/sdk/utils/format.js +6 -0
- package/src/sdk/utils/format.js.map +1 -0
- package/{sdk → src/sdk}/utils/test.d.ts +1 -1
- package/src/sdk/utils/test.js +6 -0
- package/src/sdk/utils/test.js.map +1 -0
- package/src/smithy/project/__snapshots__/generator.spec.ts.snap +244 -226
- package/src/smithy/project/files/{smithy-build.json.template → service/smithy-build.json.template} +5 -5
- package/src/smithy/project/files/{src → service/src}/operations/echo.smithy.template +1 -0
- package/src/smithy/project/files/shapes/smithy-build.json.template +7 -0
- package/src/smithy/project/files/shapes/src/main.smithy.template +11 -0
- package/src/smithy/project/files/ssdk-bundle/ssdk.rolldown.config.mjs.template +52 -0
- package/src/smithy/project/generator.d.ts +91 -1
- package/src/smithy/project/generator.js +220 -45
- package/src/smithy/project/generator.js.map +1 -1
- package/src/smithy/project/schema.d.js +6 -0
- package/src/smithy/project/schema.d.js.map +1 -0
- package/src/smithy/project/schema.d.ts +2 -0
- package/src/smithy/project/schema.json +28 -1
- package/src/smithy/react-connection/__snapshots__/generator.spec.ts.snap +1 -1
- package/src/smithy/react-connection/generator.d.ts +16 -1
- package/src/smithy/react-connection/generator.js +54 -48
- package/src/smithy/react-connection/generator.js.map +1 -1
- package/src/smithy/react-connection/schema.d.js +6 -0
- package/src/smithy/react-connection/schema.d.js.map +1 -0
- package/src/smithy/react-connection/schema.d.ts +1 -0
- package/src/smithy/react-connection/schema.json +5 -0
- package/src/smithy/ts/api/__snapshots__/generator.spec.ts.snap +2618 -550
- package/src/smithy/ts/api/files/handler.ts.template +3 -3
- package/src/smithy/ts/api/files/local-server.ts.template +3 -3
- package/src/smithy/ts/api/files/operations/echo.ts.template +2 -2
- package/src/smithy/ts/api/files/service.ts.template +3 -3
- package/src/smithy/ts/api/generator.d.ts +89 -1
- package/src/smithy/ts/api/generator.js +185 -119
- package/src/smithy/ts/api/generator.js.map +1 -1
- package/src/smithy/ts/api/schema.d.js +6 -0
- package/src/smithy/ts/api/schema.d.js.map +1 -0
- package/src/smithy/ts/api/schema.d.ts +2 -1
- package/src/smithy/ts/api/schema.json +6 -0
- package/src/terraform/project/files/application/bootstrap/providers.tf.template +11 -0
- package/src/terraform/project/files/application/scripts/bootstrap-destroy.ts.template +111 -0
- package/src/terraform/project/files/application/scripts/bootstrap.ts.template +40 -1
- package/src/terraform/project/files/application/scripts/env.ts.template +11 -0
- package/src/terraform/project/files/application/scripts/init.ts.template +2 -1
- package/src/terraform/project/files/application/src/main.tf.template +6 -1
- package/src/terraform/project/files/application/src/providers.tf.template +9 -3
- package/src/terraform/project/files/checkov/checkov.yml.template +8 -0
- package/src/terraform/project/files/library/src/main.tf.template +9 -0
- package/src/terraform/project/generator.d.ts +62 -2
- package/src/terraform/project/generator.js +340 -117
- package/src/terraform/project/generator.js.map +1 -1
- package/src/terraform/project/schema.d.js +9 -0
- package/src/terraform/project/schema.d.js.map +1 -0
- package/src/terraform/project/schema.d.ts +1 -0
- package/src/terraform/project/schema.json +5 -0
- package/src/trpc/backend/__snapshots__/generator.spec.ts.snap +2957 -725
- package/src/trpc/backend/files/src/client/index.ts.template +1 -1
- package/src/trpc/backend/files/src/handler.ts.template +1 -1
- package/src/trpc/backend/files/src/index.ts.template +5 -5
- package/src/trpc/backend/files/src/init.ts.template +1 -1
- package/src/trpc/backend/files/src/local-server.ts.template +1 -1
- package/src/trpc/backend/files/src/middleware/index.ts.template +7 -7
- package/src/trpc/backend/files/src/procedures/echo.ts.template +3 -3
- package/src/trpc/backend/files/src/router.ts.template +2 -2
- package/src/trpc/backend/files/src/schema/echo.ts.template +2 -2
- package/src/trpc/backend/files/src/schema/index.ts.template +1 -1
- package/src/trpc/backend/files-operations/scripts/generate-operations.ts.template +40 -0
- package/src/trpc/backend/generator.d.ts +91 -2
- package/src/trpc/backend/generator.js +186 -100
- package/src/trpc/backend/generator.js.map +1 -1
- package/src/trpc/backend/schema.d.js +6 -0
- package/src/trpc/backend/schema.d.js.map +1 -0
- package/src/trpc/backend/schema.d.ts +2 -1
- package/src/trpc/backend/schema.json +6 -0
- package/src/trpc/react/__snapshots__/generator.spec.ts.snap +4 -4
- package/src/trpc/react/files/src/components/__apiNameClassName__ClientProvider.tsx.template +3 -3
- package/src/trpc/react/generator.d.ts +39 -2
- package/src/trpc/react/generator.js +105 -63
- package/src/trpc/react/generator.js.map +1 -1
- package/src/trpc/react/schema.d.js +6 -0
- package/src/trpc/react/schema.d.js.map +1 -0
- package/src/trpc/react/schema.d.ts +1 -0
- package/src/trpc/react/schema.json +5 -0
- package/src/ts/agent/__snapshots__/generator.spec.ts.snap +1490 -31
- package/src/ts/agent/a2a-connection/__snapshots__/generator.spec.ts.snap +258 -0
- package/src/ts/agent/a2a-connection/files/agent-connection/app/__targetAgentKebabCase__-client-strands.ts.template +23 -0
- package/src/ts/agent/a2a-connection/generator.d.ts +47 -1
- package/src/ts/agent/a2a-connection/generator.js +112 -63
- package/src/ts/agent/a2a-connection/generator.js.map +1 -1
- package/src/ts/agent/a2a-connection/schema.d.js +8 -0
- package/src/ts/agent/a2a-connection/schema.d.js.map +1 -0
- package/src/ts/agent/a2a-connection/schema.d.ts +2 -1
- package/src/ts/agent/a2a-connection/schema.json +5 -0
- package/src/ts/agent/files/a2a/index.ts.template +5 -12
- package/src/ts/agent/files/ag-ui/index.ts.template +29 -14
- package/src/ts/agent/files/common/agent.ts.template +11 -2
- package/src/ts/agent/files/common/session.ts.template +43 -0
- package/src/ts/agent/files/common-express/middleware/session-id-middleware.ts.template +16 -0
- package/src/ts/agent/files/deploy/Dockerfile.template +20 -2
- package/src/ts/agent/files/http/client.ts.template +2 -2
- package/src/ts/agent/files/http/index.ts.template +2 -2
- package/src/ts/agent/files/http/router.ts.template +5 -5
- package/src/ts/agent/gateway-connection/__snapshots__/generator.spec.ts.snap +222 -0
- package/src/ts/agent/gateway-connection/files/agent-connection/app/__gatewayKebabCase__-client-strands.ts.template +30 -0
- package/src/ts/agent/gateway-connection/generator.d.ts +47 -0
- package/src/ts/agent/gateway-connection/generator.js +144 -0
- package/src/ts/agent/gateway-connection/generator.js.map +1 -0
- package/src/ts/agent/gateway-connection/schema.d.js +6 -0
- package/src/ts/agent/gateway-connection/schema.d.js.map +1 -0
- package/src/ts/agent/gateway-connection/schema.d.ts +13 -0
- package/src/ts/agent/gateway-connection/schema.json +31 -0
- package/src/ts/agent/generator.d.ts +206 -1
- package/src/ts/agent/generator.js +342 -159
- package/src/ts/agent/generator.js.map +1 -1
- package/src/ts/agent/mcp-connection/__snapshots__/generator.spec.ts.snap +194 -114
- package/src/ts/agent/mcp-connection/files/agent-connection/app/__mcpServerKebabCase__-client-strands.ts.template +23 -0
- package/src/ts/agent/mcp-connection/generator.d.ts +38 -1
- package/src/ts/agent/mcp-connection/generator.js +88 -65
- package/src/ts/agent/mcp-connection/generator.js.map +1 -1
- package/src/ts/agent/mcp-connection/schema.d.js +8 -0
- package/src/ts/agent/mcp-connection/schema.d.js.map +1 -0
- package/src/ts/agent/mcp-connection/schema.d.ts +2 -1
- package/src/ts/agent/mcp-connection/schema.json +5 -0
- package/src/ts/agent/react-connection/__snapshots__/generator.spec.ts.snap +8 -4
- package/src/ts/agent/react-connection/files/src/components/__agentNameClassName__AgentClientProvider.tsx.template +2 -1
- package/src/ts/agent/react-connection/generator.d.ts +204 -3
- package/src/ts/agent/react-connection/generator.js +158 -99
- package/src/ts/agent/react-connection/generator.js.map +1 -1
- package/src/ts/agent/react-connection/local-dev.d.ts +13 -0
- package/src/ts/agent/react-connection/local-dev.js +17 -0
- package/src/ts/agent/react-connection/local-dev.js.map +1 -0
- package/src/ts/agent/react-connection/schema.d.js +8 -0
- package/src/ts/agent/react-connection/schema.d.js.map +1 -0
- package/src/ts/agent/react-connection/schema.d.ts +2 -1
- package/src/ts/agent/react-connection/schema.json +5 -0
- package/src/ts/agent/schema.d.js +6 -0
- package/src/ts/agent/schema.d.js.map +1 -0
- package/src/ts/agent/schema.d.ts +5 -1
- package/src/ts/agent/schema.json +14 -0
- package/src/ts/api/generator.d.ts +1 -1
- package/src/ts/api/generator.js +16 -16
- package/src/ts/api/generator.js.map +1 -1
- package/src/ts/api/schema.d.js +6 -0
- package/src/ts/api/schema.d.js.map +1 -0
- package/src/ts/api/schema.d.ts +2 -1
- package/src/ts/api/schema.json +5 -0
- package/src/ts/astro-docs/__snapshots__/generator.spec.ts.snap +22 -8
- package/src/ts/astro-docs/files/base/src/content/docs/en/index.mdx.template +2 -2
- package/src/ts/astro-docs/files/base/src/content.config.ts.template +4 -4
- package/src/ts/astro-docs/files/translation/scripts/translate.ts.template +272 -150
- package/src/ts/astro-docs/generator.d.ts +41 -1
- package/src/ts/astro-docs/generator.js +133 -59
- package/src/ts/astro-docs/generator.js.map +1 -1
- package/src/ts/astro-docs/schema.d.js +6 -0
- package/src/ts/astro-docs/schema.d.js.map +1 -0
- package/src/ts/astro-docs/schema.d.ts +2 -2
- package/src/ts/astro-docs/schema.json +3 -3
- package/src/ts/dcr-proxy/__snapshots__/generator.spec.ts.snap +986 -0
- package/src/ts/dcr-proxy/generator.d.ts +34 -0
- package/src/ts/dcr-proxy/generator.js +115 -0
- package/src/ts/dcr-proxy/generator.js.map +1 -0
- package/src/ts/dcr-proxy/schema.d.js +6 -0
- package/src/ts/dcr-proxy/schema.d.js.map +1 -0
- package/src/ts/dcr-proxy/schema.d.ts +13 -0
- package/src/ts/dcr-proxy/schema.json +44 -0
- package/src/ts/docs/generator.d.ts +1 -1
- package/src/ts/docs/generator.js +10 -10
- package/src/ts/docs/generator.js.map +1 -1
- package/src/ts/docs/schema.d.js +6 -0
- package/src/ts/docs/schema.d.js.map +1 -0
- package/src/ts/docs/schema.d.ts +1 -4
- package/src/ts/docs/schema.json +3 -3
- package/src/ts/dynamodb/__snapshots__/generator.spec.ts.snap +481 -527
- package/src/ts/dynamodb/agent-connection/__snapshots__/generator.spec.ts.snap +23 -5
- package/src/ts/dynamodb/agent-connection/generator.d.ts +1 -1
- package/src/ts/dynamodb/agent-connection/generator.js +27 -23
- package/src/ts/dynamodb/agent-connection/generator.js.map +1 -1
- package/src/ts/dynamodb/agent-connection/schema.d.js +8 -0
- package/src/ts/dynamodb/agent-connection/schema.d.js.map +1 -0
- package/src/ts/dynamodb/agent-connection/schema.d.ts +2 -1
- package/src/ts/dynamodb/agent-connection/schema.json +5 -0
- package/src/ts/dynamodb/files/config.json.template +24 -0
- package/src/ts/dynamodb/files/src/client.ts.template +30 -11
- package/src/ts/dynamodb/files/src/entities/example.ts.template +1 -1
- package/src/ts/dynamodb/files/src/entities/index.ts.template +1 -1
- package/src/ts/dynamodb/files/src/index.ts.template +2 -11
- package/src/ts/dynamodb/generator.d.ts +42 -1
- package/src/ts/dynamodb/generator.js +110 -64
- package/src/ts/dynamodb/generator.js.map +1 -1
- package/src/ts/dynamodb/mcp-server-connection/__snapshots__/generator.spec.ts.snap +23 -5
- package/src/ts/dynamodb/mcp-server-connection/generator.d.ts +1 -1
- package/src/ts/dynamodb/mcp-server-connection/generator.js +27 -23
- package/src/ts/dynamodb/mcp-server-connection/generator.js.map +1 -1
- package/src/ts/dynamodb/mcp-server-connection/schema.d.js +8 -0
- package/src/ts/dynamodb/mcp-server-connection/schema.d.js.map +1 -0
- package/src/ts/dynamodb/mcp-server-connection/schema.d.ts +2 -1
- package/src/ts/dynamodb/mcp-server-connection/schema.json +5 -0
- package/src/ts/dynamodb/schema.d.js +6 -0
- package/src/ts/dynamodb/schema.d.js.map +1 -0
- package/src/ts/dynamodb/schema.d.ts +3 -1
- package/src/ts/dynamodb/schema.json +26 -2
- package/src/ts/dynamodb/smithy-connection/__snapshots__/generator.spec.ts.snap +12 -3
- package/src/ts/dynamodb/smithy-connection/generator.d.ts +1 -1
- package/src/ts/dynamodb/smithy-connection/generator.js +22 -22
- package/src/ts/dynamodb/smithy-connection/generator.js.map +1 -1
- package/src/ts/dynamodb/smithy-connection/schema.d.js +8 -0
- package/src/ts/dynamodb/smithy-connection/schema.d.js.map +1 -0
- package/src/ts/dynamodb/smithy-connection/schema.d.ts +1 -0
- package/src/ts/dynamodb/smithy-connection/schema.json +5 -0
- package/src/ts/dynamodb/trpc-connection/__snapshots__/generator.spec.ts.snap +12 -3
- package/src/ts/dynamodb/trpc-connection/generator.d.ts +1 -1
- package/src/ts/dynamodb/trpc-connection/generator.js +22 -22
- package/src/ts/dynamodb/trpc-connection/generator.js.map +1 -1
- package/src/ts/dynamodb/trpc-connection/schema.d.js +8 -0
- package/src/ts/dynamodb/trpc-connection/schema.d.js.map +1 -0
- package/src/ts/dynamodb/trpc-connection/schema.d.ts +1 -0
- package/src/ts/dynamodb/trpc-connection/schema.json +5 -0
- package/src/ts/lambda-function/__snapshots__/generator.spec.ts.snap +19 -9
- package/src/ts/lambda-function/files/handler/__lambdaFunctionKebabCase__.ts.template +2 -1
- package/src/ts/lambda-function/generator.d.ts +39 -1
- package/src/ts/lambda-function/generator.js +98 -65
- package/src/ts/lambda-function/generator.js.map +1 -1
- package/src/ts/lambda-function/io.js +83 -52
- package/src/ts/lambda-function/io.js.map +1 -1
- package/src/ts/lambda-function/schema.d.js +6 -0
- package/src/ts/lambda-function/schema.d.js.map +1 -0
- package/src/ts/lambda-function/schema.d.ts +2 -1
- package/src/ts/lambda-function/schema.json +5 -0
- package/src/ts/lib/__snapshots__/generator.spec.ts.snap +83 -36
- package/src/ts/lib/__snapshots__/vitest.spec.ts.snap +2 -2
- package/src/ts/lib/biome.d.ts +1 -1
- package/src/ts/lib/biome.js +71 -38
- package/src/ts/lib/biome.js.map +1 -1
- package/src/ts/lib/generator.d.ts +24 -1
- package/src/ts/lib/generator.js +128 -94
- package/src/ts/lib/generator.js.map +1 -1
- package/src/ts/lib/grit/vitest-pass-with-no-tests.grit +1 -4
- package/src/ts/lib/schema.d.js +6 -0
- package/src/ts/lib/schema.d.js.map +1 -0
- package/src/ts/lib/schema.d.ts +1 -1
- package/src/ts/lib/schema.json +5 -0
- package/src/ts/lib/ts-project-utils.d.ts +4 -2
- package/src/ts/lib/ts-project-utils.js +85 -74
- package/src/ts/lib/ts-project-utils.js.map +1 -1
- package/src/ts/lib/types.d.ts +6 -0
- package/src/ts/lib/types.js +5 -2
- package/src/ts/lib/types.js.map +1 -1
- package/src/ts/lib/vitest.d.ts +22 -2
- package/src/ts/lib/vitest.js +83 -26
- package/src/ts/lib/vitest.js.map +1 -1
- package/src/ts/mcp-server/__snapshots__/generator.spec.ts.snap +225 -44
- package/src/ts/mcp-server/files/Dockerfile.template +20 -2
- package/src/ts/mcp-server/generator.d.ts +111 -1
- package/src/ts/mcp-server/generator.js +234 -168
- package/src/ts/mcp-server/generator.js.map +1 -1
- package/src/ts/mcp-server/schema.d.js +6 -0
- package/src/ts/mcp-server/schema.d.js.map +1 -0
- package/src/ts/mcp-server/schema.d.ts +2 -1
- package/src/ts/mcp-server/schema.json +6 -0
- package/src/ts/nx-generator/__snapshots__/generator.spec.ts.snap +28 -13
- package/src/ts/nx-generator/files/common/schema.d.ts.template +1 -0
- package/src/ts/nx-generator/files/common/schema.json.template +5 -0
- package/src/ts/nx-generator/files/local/generator.spec.ts.template +1 -1
- package/src/ts/nx-generator/files/local/generator.ts.template +3 -3
- package/src/ts/nx-generator/files/nx-plugin-for-aws/generator/generator.ts.template +6 -7
- package/src/ts/nx-generator/generator.d.ts +3 -0
- package/src/ts/nx-generator/generator.js +122 -75
- package/src/ts/nx-generator/generator.js.map +1 -1
- package/src/ts/nx-generator/schema.d.js +6 -0
- package/src/ts/nx-generator/schema.d.js.map +1 -0
- package/src/ts/nx-generator/schema.d.ts +1 -0
- package/src/ts/nx-generator/schema.json +5 -0
- package/src/ts/nx-migration/files/migration.spec.ts.template +26 -0
- package/src/ts/nx-migration/files/migration.ts.template +65 -0
- package/src/ts/nx-migration/files/prompt.md.template +46 -0
- package/src/ts/nx-migration/generator.d.ts +27 -0
- package/src/ts/nx-migration/generator.js +147 -0
- package/src/ts/nx-migration/generator.js.map +1 -0
- package/src/ts/nx-migration/schema.d.js +6 -0
- package/src/ts/nx-migration/schema.d.js.map +1 -0
- package/src/ts/nx-migration/schema.d.ts +13 -0
- package/src/ts/nx-migration/schema.json +63 -0
- package/src/ts/nx-plugin/__snapshots__/generator.spec.ts.snap +36 -25
- package/src/ts/nx-plugin/files/mcp-server/resources/GENERAL_GUIDANCE.md.template +5 -6
- package/src/ts/nx-plugin/files/mcp-server/server.ts.template +5 -5
- package/src/ts/nx-plugin/files/mcp-server/tools/create-workspace-command.ts.template +2 -2
- package/src/ts/nx-plugin/files/mcp-server/tools/general-guidance.ts.template +1 -1
- package/src/ts/nx-plugin/files/mcp-server/tools/generator-guide.ts.template +2 -2
- package/src/ts/nx-plugin/files/mcp-server/tools/list-generators.ts.template +2 -2
- package/src/ts/nx-plugin/files/mcp-server/utils.ts.template +4 -4
- package/src/ts/nx-plugin/generator.d.ts +4 -1
- package/src/ts/nx-plugin/generator.js +64 -48
- package/src/ts/nx-plugin/generator.js.map +1 -1
- package/src/ts/nx-plugin/schema.d.js +9 -0
- package/src/ts/nx-plugin/schema.d.js.map +1 -0
- package/src/ts/nx-plugin/schema.json +5 -0
- package/src/ts/nx-plugin/utils.d.ts +27 -2
- package/src/ts/nx-plugin/utils.js +66 -57
- package/src/ts/nx-plugin/utils.js.map +1 -1
- package/src/ts/rdb/__snapshots__/generator.spec.ts.snap +711 -877
- package/src/ts/rdb/agent-connection/__snapshots__/generator.spec.ts.snap +16 -6
- package/src/ts/rdb/agent-connection/generator.d.ts +1 -1
- package/src/ts/rdb/agent-connection/generator.js +44 -39
- package/src/ts/rdb/agent-connection/generator.js.map +1 -1
- package/src/ts/rdb/agent-connection/schema.d.js +8 -0
- package/src/ts/rdb/agent-connection/schema.d.js.map +1 -0
- package/src/ts/rdb/agent-connection/schema.d.ts +2 -1
- package/src/ts/rdb/agent-connection/schema.json +5 -0
- package/src/ts/rdb/files/Dockerfile.template +19 -1
- package/src/ts/rdb/files/prisma.config.ts.template +6 -5
- package/src/ts/rdb/files/src/create-db-user-handler.ts.template +9 -11
- package/src/ts/rdb/files/src/migration-handler.ts.template +5 -30
- package/src/ts/rdb/files/src/prisma.ts.template +33 -25
- package/src/ts/rdb/files/src/utils.ts.template +31 -1
- package/src/ts/rdb/generator.d.ts +118 -5
- package/src/ts/rdb/generator.js +272 -127
- package/src/ts/rdb/generator.js.map +1 -1
- package/src/ts/rdb/mcp-server-connection/__snapshots__/generator.spec.ts.snap +16 -6
- package/src/ts/rdb/mcp-server-connection/generator.d.ts +1 -1
- package/src/ts/rdb/mcp-server-connection/generator.js +42 -37
- package/src/ts/rdb/mcp-server-connection/generator.js.map +1 -1
- package/src/ts/rdb/mcp-server-connection/schema.d.js +8 -0
- package/src/ts/rdb/mcp-server-connection/schema.d.js.map +1 -0
- package/src/ts/rdb/mcp-server-connection/schema.d.ts +2 -1
- package/src/ts/rdb/mcp-server-connection/schema.json +5 -0
- package/src/ts/rdb/schema.d.js +6 -0
- package/src/ts/rdb/schema.d.js.map +1 -0
- package/src/ts/rdb/schema.d.ts +2 -1
- package/src/ts/rdb/schema.json +7 -1
- package/src/ts/rdb/smithy-connection/__snapshots__/generator.spec.ts.snap +18 -9
- package/src/ts/rdb/smithy-connection/generator.d.ts +1 -1
- package/src/ts/rdb/smithy-connection/generator.js +48 -43
- package/src/ts/rdb/smithy-connection/generator.js.map +1 -1
- package/src/ts/rdb/smithy-connection/schema.d.js +8 -0
- package/src/ts/rdb/smithy-connection/schema.d.js.map +1 -0
- package/src/ts/rdb/smithy-connection/schema.d.ts +1 -0
- package/src/ts/rdb/smithy-connection/schema.json +5 -0
- package/src/ts/rdb/trpc-connection/__snapshots__/generator.spec.ts.snap +12 -3
- package/src/ts/rdb/trpc-connection/generator.d.ts +1 -1
- package/src/ts/rdb/trpc-connection/generator.js +37 -31
- package/src/ts/rdb/trpc-connection/generator.js.map +1 -1
- package/src/ts/rdb/trpc-connection/schema.d.js +8 -0
- package/src/ts/rdb/trpc-connection/schema.d.js.map +1 -0
- package/src/ts/rdb/trpc-connection/schema.d.ts +1 -0
- package/src/ts/rdb/trpc-connection/schema.json +5 -0
- package/src/ts/rdb/utils.js +9 -11
- package/src/ts/rdb/utils.js.map +1 -1
- package/src/ts/react-website/agui/files/common/src/hooks/useAgui__agentNameClassName__.tsx.template +17 -16
- package/src/ts/react-website/agui/generator.d.ts +97 -0
- package/src/ts/react-website/agui/generator.js +114 -67
- package/src/ts/react-website/agui/generator.js.map +1 -1
- package/src/ts/react-website/app/__snapshots__/generator.spec.ts.snap +1705 -717
- package/src/ts/react-website/app/files/app/common/README.md.template +1 -1
- package/src/ts/react-website/app/generator.d.ts +146 -3
- package/src/ts/react-website/app/generator.js +363 -209
- package/src/ts/react-website/app/generator.js.map +1 -1
- package/src/ts/react-website/app/schema.d.js +6 -0
- package/src/ts/react-website/app/schema.d.js.map +1 -0
- package/src/ts/react-website/app/schema.d.ts +3 -3
- package/src/ts/react-website/app/schema.json +12 -6
- package/src/ts/react-website/cognito-auth/__snapshots__/generator.spec.ts.snap +225 -31
- package/src/ts/react-website/cognito-auth/__snapshots__/generator.terraform.spec.ts.snap +78 -12
- package/src/ts/react-website/cognito-auth/files/app/components/CognitoAuth/index.tsx.template +2 -2
- package/src/ts/react-website/cognito-auth/generator.d.ts +26 -2
- package/src/ts/react-website/cognito-auth/generator.js +79 -61
- package/src/ts/react-website/cognito-auth/generator.js.map +1 -1
- package/src/ts/react-website/cognito-auth/schema.d.js +6 -0
- package/src/ts/react-website/cognito-auth/schema.d.js.map +1 -0
- package/src/ts/react-website/cognito-auth/schema.d.ts +2 -1
- package/src/ts/react-website/cognito-auth/schema.json +5 -0
- package/src/ts/react-website/cognito-auth/utils.js +34 -32
- package/src/ts/react-website/cognito-auth/utils.js.map +1 -1
- package/src/ts/react-website/runtime-config/__snapshots__/generator.spec.ts.snap +2 -2
- package/src/ts/react-website/runtime-config/files/app/components/RuntimeConfig/index.tsx.template +2 -2
- package/src/ts/react-website/runtime-config/generator.d.ts +1 -1
- package/src/ts/react-website/runtime-config/generator.js +29 -31
- package/src/ts/react-website/runtime-config/generator.js.map +1 -1
- package/src/ts/react-website/runtime-config/schema.d.js +6 -0
- package/src/ts/react-website/runtime-config/schema.d.js.map +1 -0
- package/src/ts/react-website/runtime-config/schema.d.ts +1 -0
- package/src/ts/react-website/runtime-config/schema.json +5 -0
- package/src/ts/sync/generator.d.ts +1 -1
- package/src/ts/sync/generator.js +154 -60
- package/src/ts/sync/generator.js.map +1 -1
- package/src/ts/website/app/generator.d.ts +1 -1
- package/src/ts/website/app/generator.js +10 -10
- package/src/ts/website/app/generator.js.map +1 -1
- package/src/ts/website/app/schema.d.js +6 -0
- package/src/ts/website/app/schema.d.js.map +1 -0
- package/src/ts/website/app/schema.d.ts +3 -3
- package/src/ts/website/app/schema.json +11 -6
- package/src/ts/website/auth/generator.d.ts +2 -2
- package/src/ts/website/auth/generator.js +11 -10
- package/src/ts/website/auth/generator.js.map +1 -1
- package/src/ts/website/auth/schema.d.js +6 -0
- package/src/ts/website/auth/schema.d.js.map +1 -0
- package/src/ts/website/auth/schema.d.ts +2 -1
- package/src/ts/website/auth/schema.json +5 -0
- package/src/utils/__snapshots__/shared-constructs.spec.ts.snap +21 -0
- package/src/utils/add-dependencies.d.ts +38 -0
- package/src/utils/add-dependencies.js +83 -0
- package/src/utils/add-dependencies.js.map +1 -0
- package/src/utils/agent-chat/agent-chat.d.ts +31 -0
- package/src/utils/agent-chat/agent-chat.js +31 -0
- package/src/utils/agent-chat/agent-chat.js.map +1 -0
- package/src/utils/agent-chat/files/a2a/chat.ts.template +33 -0
- package/src/utils/agent-chat/files/ag-ui/chat.ts.template +17 -0
- package/src/utils/agent-chat/files/common/agentcore.ts.template +81 -0
- package/src/utils/agent-chat/files/http-py/chat.ts.template +43 -0
- package/src/utils/agent-chat/files/http-ts/chat.ts.template +54 -0
- package/src/utils/agent-connection/agent-connection.d.ts +149 -26
- package/src/utils/agent-connection/agent-connection.js +510 -108
- package/src/utils/agent-connection/agent-connection.js.map +1 -1
- package/src/utils/agent-connection/files/core-a2a/agentcore-a2a-client-config.ts.template +93 -0
- package/src/utils/agent-connection/files/core-auth/agentcore-endpoints.ts.template +37 -0
- package/src/utils/agent-connection/files/core-auth/agentcore-fetch.ts.template +54 -0
- package/src/utils/agent-connection/files/core-gateway/agentcore-gateway-mcp-transport.ts.template +41 -0
- package/src/utils/agent-connection/files/core-mcp/agentcore-mcp-transport.ts.template +70 -0
- package/src/utils/agent-connection/files/core-runtime-config/runtime-config.ts.template +35 -33
- package/src/utils/agent-connection/files/core-shared/agentcore-transport.ts.template +39 -0
- package/src/utils/agent-connection/files/core-strands/a2a/agentcore-a2a-client-strands.ts.template +61 -0
- package/src/utils/agent-connection/files/{core-runtime-config/model-errors.ts.template → core-strands/base/model-errors-strands.ts.template} +26 -15
- package/src/utils/agent-connection/files/core-strands/base/tool-errors-strands.ts.template +29 -0
- package/src/utils/agent-connection/files/{core-runtime-config/with-session-id.ts.template → core-strands/base/with-session-id-strands.ts.template} +1 -1
- package/src/utils/agent-connection/files/core-strands/gateway/agentcore-gateway-mcp-client-strands.ts.template +26 -0
- package/src/utils/agent-connection/files/core-strands/mcp/agentcore-mcp-client-strands.ts.template +27 -0
- package/src/utils/agent-connection/files/py-core-a2a/agentcore_a2a_client_config.py.template +43 -0
- package/src/utils/agent-connection/files/py-core-auth/agentcore_endpoints.py.template +47 -0
- package/src/utils/agent-connection/files/py-core-auth/auth/session.py.template +51 -0
- package/src/utils/agent-connection/files/py-core-gateway/agentcore_gateway_mcp_transport.py.template +28 -0
- package/src/utils/agent-connection/files/py-core-langchain/a2a/agentcore_a2a_client_langchain.py.template +105 -0
- package/src/utils/agent-connection/files/py-core-langchain/gateway/agentcore_gateway_mcp_client_langchain.py.template +57 -0
- package/src/utils/agent-connection/files/py-core-langchain/mcp/agentcore_mcp_client_langchain.py.template +64 -0
- package/src/utils/agent-connection/files/py-core-langchain/s3/s3_checkpoint_saver_langchain.py.template +360 -0
- package/src/utils/agent-connection/files/py-core-mcp/agentcore_mcp_transport.py.template +34 -0
- package/src/utils/agent-connection/files/py-core-runtime-config/runtime_config.py.template +4 -18
- package/src/utils/agent-connection/files/py-core-runtime-config/session_context.py.template +2 -2
- package/src/utils/agent-connection/files/py-core-shared/agentcore_transport.py.template +40 -0
- package/src/utils/agent-connection/files/py-core-strands/a2a/agentcore_a2a_client_strands.py.template +111 -0
- package/src/utils/agent-connection/files/py-core-strands/base/tool_errors_strands.py.template +24 -0
- package/src/utils/agent-connection/files/{py-core-runtime-config/with_session_id.py.template → py-core-strands/base/with_session_id_strands.py.template} +2 -2
- package/src/utils/agent-connection/files/py-core-strands/gateway/agentcore_gateway_mcp_client_strands.py.template +22 -0
- package/src/utils/agent-connection/files/py-core-strands/mcp/agentcore_mcp_client_strands.py.template +30 -0
- package/src/utils/agent-core-constructs/agent-core-constructs.d.ts +88 -2
- package/src/utils/agent-core-constructs/agent-core-constructs.js +227 -30
- package/src/utils/agent-core-constructs/agent-core-constructs.js.map +1 -1
- package/src/utils/agent-core-constructs/files/cdk/app/agent-core/__nameKebabCase__/__nameKebabCase__.ts.template +273 -9
- package/src/utils/agent-core-constructs/files/cdk/app/agentcore-gateway/__nameKebabCase__/__nameKebabCase__.ts.template +87 -0
- package/src/utils/agent-core-constructs/files/cdk/app/agentcore-harness/__nameKebabCase__/__nameKebabCase__.ts.template +404 -0
- package/src/utils/agent-core-constructs/files/cdk/core/agentcore-gateway/agentcore-gateway.ts.template +624 -0
- package/src/utils/agent-core-constructs/files/cdk/core/agentcore-gateway/readiness-probe/index.js.template +55 -0
- package/src/utils/agent-core-constructs/files/terraform/app/agent-core/__nameKebabCase__/__nameKebabCase__.tf.template +288 -1
- package/src/utils/agent-core-constructs/files/terraform/app/agentcore-gateway/__nameKebabCase__/__nameKebabCase__.tf.template +576 -0
- package/src/utils/agent-core-constructs/files/terraform/app/agentcore-gateway/__nameKebabCase__/render-cedar.cjs.template +13 -0
- package/src/utils/agent-core-constructs/files/terraform/app/agentcore-harness/__nameKebabCase__/__nameKebabCase__.tf.template +516 -0
- package/src/utils/agent-core-constructs/files/terraform/core/agent-core/runtime.tf.template +163 -13
- package/src/utils/agent-core-constructs/files/terraform/core/agentcore-gateway/gateway.tf.template +14 -0
- package/src/utils/api-constructs/api-constructs.d.ts +31 -3
- package/src/utils/api-constructs/api-constructs.js +96 -32
- package/src/utils/api-constructs/api-constructs.js.map +1 -1
- package/src/utils/api-constructs/files/cdk/app/apis/http/__apiNameKebabCase__.ts.template +24 -19
- package/src/utils/api-constructs/files/cdk/app/apis/rest/__apiNameKebabCase__.ts.template +28 -20
- package/src/utils/api-constructs/files/cdk/core/api/http/http-api.ts.template +26 -9
- package/src/utils/api-constructs/files/cdk/core/api/rest/api-gateway-account/index.js.template +70 -0
- package/src/utils/api-constructs/files/cdk/core/api/rest/api-gateway-account.ts.template +82 -0
- package/src/utils/api-constructs/files/cdk/core/api/rest/rest-api.ts.template +56 -17
- package/src/utils/api-constructs/files/cdk/core/api/trpc/trpc-utils.ts.template +1 -1
- package/src/utils/api-constructs/files/cdk/core/api/utils/utils.ts.template +61 -7
- package/src/utils/api-constructs/files/terraform/app/apis/http/__apiNameKebabCase__/__apiNameKebabCase__.tf.template +356 -19
- package/src/utils/api-constructs/files/terraform/app/apis/rest/__apiNameKebabCase__/__apiNameKebabCase__.tf.template +635 -14
- package/src/utils/api-constructs/files/terraform/core/api/http/http-api/http-api.tf.template +1 -1
- package/src/utils/api-constructs/files/terraform/core/api/rest/api-gateway-account/api-gateway-account.tf.template +83 -0
- package/src/utils/api-constructs/files/terraform/core/api/rest/rest-api/rest-api.tf.template +65 -18
- package/src/utils/api-constructs/open-api-metadata.d.ts +21 -4
- package/src/utils/api-constructs/open-api-metadata.js +74 -39
- package/src/utils/api-constructs/open-api-metadata.js.map +1 -1
- package/src/utils/api-constructs/trpc-operations-metadata.d.ts +21 -0
- package/src/utils/api-constructs/trpc-operations-metadata.js +61 -0
- package/src/utils/api-constructs/trpc-operations-metadata.js.map +1 -0
- package/src/utils/ast/website.js +17 -19
- package/src/utils/ast/website.js.map +1 -1
- package/src/utils/ast.d.ts +47 -0
- package/src/utils/ast.js +185 -96
- package/src/utils/ast.js.map +1 -1
- package/src/utils/base-tsconfig.d.ts +30 -0
- package/src/utils/base-tsconfig.js +32 -0
- package/src/utils/base-tsconfig.js.map +1 -0
- package/src/utils/bundle/bundle.d.ts +6 -1
- package/src/utils/bundle/bundle.js +70 -48
- package/src/utils/bundle/bundle.js.map +1 -1
- package/src/utils/commands.d.ts +14 -3
- package/src/utils/commands.js +83 -28
- package/src/utils/commands.js.map +1 -1
- package/src/utils/config/index.d.ts +22 -6
- package/src/utils/config/index.js +5 -4
- package/src/utils/config/index.js.map +1 -1
- package/src/utils/config/utils.d.ts +9 -3
- package/src/utils/config/utils.js +56 -59
- package/src/utils/config/utils.js.map +1 -1
- package/src/utils/connection/open-api/files/components/__apiNameClassName__Provider.tsx.template +16 -3
- package/src/utils/connection/open-api/react.d.ts +31 -5
- package/src/utils/connection/open-api/react.js +106 -86
- package/src/utils/connection/open-api/react.js.map +1 -1
- package/src/utils/containers.js +22 -23
- package/src/utils/containers.js.map +1 -1
- package/src/utils/dcr-proxy-constructs/dcr-proxy-constructs.d.ts +38 -0
- package/src/utils/dcr-proxy-constructs/dcr-proxy-constructs.js +95 -0
- package/src/utils/dcr-proxy-constructs/dcr-proxy-constructs.js.map +1 -0
- package/src/utils/dcr-proxy-constructs/files/cdk/app/dcr-proxies/__nameKebabCase__/__nameKebabCase__.ts.template +227 -0
- package/src/utils/dcr-proxy-constructs/files/project/src/handlers/authorization-server-metadata.ts.template +39 -0
- package/src/utils/dcr-proxy-constructs/files/project/src/handlers/authorize.ts.template +26 -0
- package/src/utils/dcr-proxy-constructs/files/project/src/handlers/mcp-proxy.ts.template +89 -0
- package/src/utils/dcr-proxy-constructs/files/project/src/handlers/protected-resource-metadata.ts.template +13 -0
- package/src/utils/dcr-proxy-constructs/files/project/src/handlers/register.ts.template +70 -0
- package/src/utils/dcr-proxy-constructs/files/project/src/handlers/token.ts.template +75 -0
- package/src/utils/dcr-proxy-constructs/files/terraform/app/dcr-proxies/__nameKebabCase__/__nameKebabCase__.tf.template +414 -0
- package/src/utils/declared-dependencies.d.ts +140 -0
- package/src/utils/declared-dependencies.js +64 -0
- package/src/utils/declared-dependencies.js.map +1 -0
- package/src/utils/dependencies.d.ts +18 -0
- package/src/utils/dependencies.js +206 -0
- package/src/utils/dependencies.js.map +1 -0
- package/src/utils/docker.d.ts +101 -0
- package/src/utils/docker.js +135 -0
- package/src/utils/docker.js.map +1 -0
- package/src/utils/dynamodb-constructs/dynamodb-constructs.d.ts +2 -2
- package/src/utils/dynamodb-constructs/dynamodb-constructs.js +39 -33
- package/src/utils/dynamodb-constructs/dynamodb-constructs.js.map +1 -1
- package/src/utils/dynamodb-constructs/files/cdk/app/dynamodb/__nameKebabCase__.ts.template +18 -5
- package/src/utils/dynamodb-constructs/files/cdk/core/dynamodb.ts.template +24 -4
- package/src/utils/dynamodb-constructs/files/terraform/app/dynamodb/__nameKebabCase__/__nameKebabCase__.tf.template +66 -18
- package/src/utils/dynamodb-constructs/files/terraform/core/dynamodb/dynamodb.tf.template +46 -6
- package/src/utils/files/common/constructs/src/core/cloudfront.ts.template +14 -0
- package/src/utils/files/common/constructs/src/core/index.ts.template +5 -4
- package/src/utils/files/common/constructs/src/index.ts.template +2 -2
- package/src/utils/files/common/infra-config/src/index.ts.template +3 -3
- package/src/utils/files/common/infra-config/src/resolve-stage.ts.template +2 -2
- package/src/utils/files/common/infra-config/src/stages.config.ts.template +1 -1
- package/src/{ts/dynamodb/files/scripts → utils/files/common/scripts/src/dynamodb}/create-local-table.ts.template +65 -31
- package/src/utils/files/common/scripts/src/dynamodb/pull-image.ts.template +13 -0
- package/src/{ts/dynamodb/files/scripts → utils/files/common/scripts/src/dynamodb}/start-container.ts.template +29 -22
- package/src/utils/files/common/scripts/src/infra/infra-deploy.ts.template +2 -0
- package/src/utils/files/common/scripts/src/infra/infra-destroy.ts.template +2 -0
- package/src/utils/files/common/scripts/src/infra/stage-credentials/cdk-command.ts.template +25 -0
- package/src/utils/files/common/scripts/src/{stage-credentials → infra/stage-credentials}/run.ts.template +3 -3
- package/src/utils/files/common/scripts/src/rdb/mysql/wait-for-mysql-db.ts.template +32 -0
- package/src/utils/files/common/scripts/src/rdb/postgres/wait-for-postgres-db.ts.template +32 -0
- package/src/utils/files/common/scripts/src/rdb/shared/pull-image.ts.template +16 -0
- package/src/utils/files/common/scripts/src/rdb/shared/start-container.ts.template +100 -0
- package/src/utils/files/common/shadcn/readme/README.md.template +3 -3
- package/src/utils/files/common/shadcn/src/index.ts.template +2 -2
- package/src/utils/files/shadcn/components.json.template +1 -1
- package/src/utils/files/terraform/src/core/asset-bucket/asset-bucket.tf.template +63 -72
- package/src/utils/files/terraform/src/core/runtime-config/appconfig/appconfig.tf.template +3 -3
- package/src/utils/files/terraform/src/core/runtime-config/appconfig-deployment/appconfig-deployment.tf.template +13 -7
- package/src/utils/files/terraform/src/core/runtime-config/entry/entry.tf.template +1 -1
- package/src/utils/files/terraform/src/core/runtime-config/read/read.tf.template +9 -4
- package/src/utils/files/terraform/src/metrics/providers.tf.template +12 -0
- package/src/utils/files/website/hooks/sigv4/useSigV4.tsx.template +1 -1
- package/src/utils/format.d.ts +44 -4
- package/src/utils/format.js +323 -198
- package/src/utils/format.js.map +1 -1
- package/src/utils/fs.d.ts +24 -5
- package/src/utils/fs.js +40 -15
- package/src/utils/fs.js.map +1 -1
- package/src/utils/function-constructs/files/cdk/app/lambda-functions/__nameKebabCase__.ts.template +1 -1
- package/src/utils/function-constructs/files/terraform/app/lambda-functions/__nameKebabCase__/__nameKebabCase__.tf.template +6 -2
- package/src/utils/function-constructs/function-constructs.d.ts +1 -1
- package/src/utils/function-constructs/function-constructs.js +24 -27
- package/src/utils/function-constructs/function-constructs.js.map +1 -1
- package/src/utils/generators.d.ts +33 -0
- package/src/utils/generators.js +33 -20
- package/src/utils/generators.js.map +1 -1
- package/src/utils/git.js +19 -34
- package/src/utils/git.js.map +1 -1
- package/src/utils/iac-providers.js +5 -5
- package/src/utils/iac-providers.js.map +1 -1
- package/src/utils/iac.d.ts +2 -2
- package/src/utils/iac.js +12 -14
- package/src/utils/iac.js.map +1 -1
- package/src/utils/identity-constructs/files/cdk/core/user-identity.ts.template +218 -30
- package/src/utils/identity-constructs/files/terraform/core/user-identity/add-callback-url/add-callback-url.tf.template +32 -9
- package/src/utils/identity-constructs/files/terraform/core/user-identity/identity/identity.tf.template +226 -25
- package/src/utils/identity-constructs/files/terraform/core/user-identity/main.tf.template +33 -0
- package/src/utils/identity-constructs/identity-constructs.d.ts +11 -1
- package/src/utils/identity-constructs/identity-constructs.js +52 -31
- package/src/utils/identity-constructs/identity-constructs.js.map +1 -1
- package/src/utils/init.d.ts +73 -0
- package/src/utils/init.js +300 -0
- package/src/utils/init.js.map +1 -0
- package/src/utils/install.d.ts +32 -0
- package/src/utils/install.js +58 -0
- package/src/utils/install.js.map +1 -0
- package/src/utils/js.js +27 -20
- package/src/utils/js.js.map +1 -1
- package/src/utils/lambda-runtime-resolution.d.ts +53 -0
- package/src/utils/lambda-runtime-resolution.js +83 -0
- package/src/utils/lambda-runtime-resolution.js.map +1 -0
- package/src/utils/mcp.d.ts +9 -0
- package/src/utils/mcp.js +42 -41
- package/src/utils/mcp.js.map +1 -1
- package/src/utils/metrics.d.ts +1 -1
- package/src/utils/metrics.js +30 -45
- package/src/utils/metrics.js.map +1 -1
- package/src/utils/migration-manifest.d.ts +58 -0
- package/src/utils/migration-manifest.js +76 -0
- package/src/utils/migration-manifest.js.map +1 -0
- package/src/utils/migration-versions.d.ts +145 -0
- package/src/utils/migration-versions.js +250 -0
- package/src/utils/migration-versions.js.map +1 -0
- package/src/utils/mock-project-graph.js +12 -13
- package/src/utils/mock-project-graph.js.map +1 -1
- package/src/utils/module-format.d.ts +25 -0
- package/src/utils/module-format.js +45 -0
- package/src/utils/module-format.js.map +1 -0
- package/src/utils/names.d.ts +22 -0
- package/src/utils/names.js +44 -48
- package/src/utils/names.js.map +1 -1
- package/src/utils/npm-scope.d.ts +0 -4
- package/src/utils/npm-scope.js +7 -20
- package/src/utils/npm-scope.js.map +1 -1
- package/src/utils/nx.d.ts +91 -6
- package/src/utils/nx.js +186 -74
- package/src/utils/nx.js.map +1 -1
- package/src/utils/nxlv-python.js +27 -15
- package/src/utils/nxlv-python.js.map +1 -1
- package/src/utils/object.js +5 -11
- package/src/utils/object.js.map +1 -1
- package/src/utils/open-api-codegen-target.d.ts +28 -0
- package/src/utils/open-api-codegen-target.js +31 -0
- package/src/utils/open-api-codegen-target.js.map +1 -0
- package/src/utils/paths.js +11 -15
- package/src/utils/paths.js.map +1 -1
- package/src/utils/pkg-manager.d.ts +1 -1
- package/src/utils/pkg-manager.js +4 -9
- package/src/utils/pkg-manager.js.map +1 -1
- package/src/utils/pnpm-workspace.d.ts +1 -12
- package/src/utils/pnpm-workspace.js +16 -43
- package/src/utils/pnpm-workspace.js.map +1 -1
- package/src/utils/port.d.ts +6 -5
- package/src/utils/port.js +31 -39
- package/src/utils/port.js.map +1 -1
- package/src/utils/project-package-json.d.ts +39 -0
- package/src/utils/project-package-json.js +119 -0
- package/src/utils/project-package-json.js.map +1 -0
- package/src/utils/py.d.ts +18 -4
- package/src/utils/py.js +64 -46
- package/src/utils/py.js.map +1 -1
- package/src/utils/rdb-constructs/files/cdk/app/dbs/__nameKebabCase__.ts.template +72 -18
- package/src/utils/rdb-constructs/files/cdk/core/rdb/aurora.ts.template +130 -88
- package/src/utils/rdb-constructs/files/terraform/app/dbs/__nameKebabCase__/__nameKebabCase__.tf.template +132 -66
- package/src/utils/rdb-constructs/files/terraform/core/rdb/aurora/aurora.tf.template +78 -162
- package/src/utils/rdb-constructs/rdb-constructs.d.ts +26 -3
- package/src/utils/rdb-constructs/rdb-constructs.js +61 -33
- package/src/utils/rdb-constructs/rdb-constructs.js.map +1 -1
- package/src/utils/ruff.d.ts +59 -0
- package/src/utils/ruff.js +140 -0
- package/src/utils/ruff.js.map +1 -0
- package/src/utils/shared-constructs-constants.d.ts +68 -4
- package/src/utils/shared-constructs-constants.js +68 -15
- package/src/utils/shared-constructs-constants.js.map +1 -1
- package/src/utils/shared-constructs.d.ts +5 -2
- package/src/utils/shared-constructs.js +62 -67
- package/src/utils/shared-constructs.js.map +1 -1
- package/src/utils/shared-dynamodb-scripts.d.ts +18 -0
- package/src/utils/shared-dynamodb-scripts.js +35 -0
- package/src/utils/shared-dynamodb-scripts.js.map +1 -0
- package/src/utils/shared-infra-config.js +31 -30
- package/src/utils/shared-infra-config.js.map +1 -1
- package/src/utils/shared-infra-scripts.d.ts +26 -0
- package/src/utils/shared-infra-scripts.js +58 -0
- package/src/utils/shared-infra-scripts.js.map +1 -0
- package/src/utils/shared-rdb-scripts.d.ts +27 -0
- package/src/utils/shared-rdb-scripts.js +59 -0
- package/src/utils/shared-rdb-scripts.js.map +1 -0
- package/src/utils/shared-scripts.d.ts +1 -4
- package/src/utils/shared-scripts.js +12 -38
- package/src/utils/shared-scripts.js.map +1 -1
- package/src/utils/shared-shadcn.d.ts +26 -1
- package/src/utils/shared-shadcn.js +93 -67
- package/src/utils/shared-shadcn.js.map +1 -1
- package/src/utils/smithy.d.ts +59 -0
- package/src/utils/smithy.js +73 -0
- package/src/utils/smithy.js.map +1 -0
- package/src/utils/test-git.d.ts +39 -0
- package/src/utils/test-git.js +117 -0
- package/src/utils/test-git.js.map +1 -0
- package/src/utils/test.d.ts +10 -0
- package/src/utils/test.js +44 -25
- package/src/utils/test.js.map +1 -1
- package/src/utils/toml.d.ts +5 -0
- package/src/utils/toml.js +17 -15
- package/src/utils/toml.js.map +1 -1
- package/src/utils/version-upgrade-migration/migration.d.ts +14 -0
- package/src/utils/version-upgrade-migration/migration.js +16 -0
- package/src/utils/version-upgrade-migration/migration.js.map +1 -0
- package/src/utils/version-upgrade-migration/nx-package-updates.d.ts +45 -0
- package/src/utils/version-upgrade-migration/nx-package-updates.js +50 -0
- package/src/utils/version-upgrade-migration/nx-package-updates.js.map +1 -0
- package/src/utils/version-upgrade-migration/owned-dependencies.d.ts +76 -0
- package/src/utils/version-upgrade-migration/owned-dependencies.js +146 -0
- package/src/utils/version-upgrade-migration/owned-dependencies.js.map +1 -0
- package/src/utils/version-upgrade-migration/register.d.ts +29 -0
- package/src/utils/version-upgrade-migration/register.js +42 -0
- package/src/utils/version-upgrade-migration/register.js.map +1 -0
- package/src/utils/version-upgrade-migration/sync-embedded-versions.d.ts +26 -0
- package/src/utils/version-upgrade-migration/sync-embedded-versions.js +352 -0
- package/src/utils/version-upgrade-migration/sync-embedded-versions.js.map +1 -0
- package/src/utils/version-upgrade-migration/sync-lambda-runtimes.d.ts +28 -0
- package/src/utils/version-upgrade-migration/sync-lambda-runtimes.js +148 -0
- package/src/utils/version-upgrade-migration/sync-lambda-runtimes.js.map +1 -0
- package/src/utils/version-upgrade-migration/sync-metrics-version.d.ts +13 -0
- package/src/utils/version-upgrade-migration/sync-metrics-version.js +33 -0
- package/src/utils/version-upgrade-migration/sync-metrics-version.js.map +1 -0
- package/src/utils/version-upgrade-migration/sync-python-language-version.d.ts +31 -0
- package/src/utils/version-upgrade-migration/sync-python-language-version.js +110 -0
- package/src/utils/version-upgrade-migration/sync-python-language-version.js.map +1 -0
- package/src/utils/version-upgrade-migration/sync-vended-versions.d.ts +10 -0
- package/src/utils/version-upgrade-migration/sync-vended-versions.js +547 -0
- package/src/utils/version-upgrade-migration/sync-vended-versions.js.map +1 -0
- package/src/utils/version-upgrade-migration/vended-upgrade.d.ts +14 -0
- package/src/utils/version-upgrade-migration/vended-upgrade.js +40 -0
- package/src/utils/version-upgrade-migration/vended-upgrade.js.map +1 -0
- package/src/utils/versions.d.ts +300 -108
- package/src/utils/versions.js +317 -121
- package/src/utils/versions.js.map +1 -1
- package/src/utils/website-constructs/files/cdk/app/static-websites/__websiteNameKebabCase__.ts.template +12 -3
- package/src/utils/website-constructs/files/cdk/core/static-website.ts.template +252 -49
- package/src/utils/website-constructs/files/terraform/app/static-websites/__websiteNameKebabCase__/__websiteNameKebabCase__.tf.template +56 -1
- package/src/utils/website-constructs/files/terraform/core/static-website/static-website.tf.template +205 -107
- package/src/utils/website-constructs/website-constructs.d.ts +12 -1
- package/src/utils/website-constructs/website-constructs.js +49 -30
- package/src/utils/website-constructs/website-constructs.js.map +1 -1
- package/bin/aws-nx-mcp.d.ts +0 -2
- package/bin/aws-nx-mcp.js +0 -17
- package/bin/aws-nx-mcp.js.map +0 -1
- package/sdk/connection.d.ts +0 -6
- package/sdk/connection.js +0 -10
- package/sdk/connection.js.map +0 -1
- package/sdk/license.d.ts +0 -8
- package/sdk/license.js +0 -13
- package/sdk/license.js.map +0 -1
- package/sdk/open-api.d.ts +0 -10
- package/sdk/open-api.js +0 -15
- package/sdk/open-api.js.map +0 -1
- package/sdk/py.d.ts +0 -14
- package/sdk/py.js +0 -18
- package/sdk/py.js.map +0 -1
- package/sdk/terraform.d.ts +0 -6
- package/sdk/terraform.js +0 -11
- package/sdk/terraform.js.map +0 -1
- package/sdk/ts.d.ts +0 -29
- package/sdk/ts.js +0 -47
- package/sdk/ts.js.map +0 -1
- package/sdk/utils/ast.js +0 -12
- package/sdk/utils/ast.js.map +0 -1
- package/sdk/utils/format.js +0 -10
- package/sdk/utils/format.js.map +0 -1
- package/sdk/utils/test.js +0 -10
- package/sdk/utils/test.js.map +0 -1
- package/src/connection/agent-serve-local.d.ts +0 -33
- package/src/connection/agent-serve-local.js +0 -48
- package/src/connection/agent-serve-local.js.map +0 -1
- package/src/connection/serve-local.js +0 -41
- package/src/connection/serve-local.js.map +0 -1
- package/src/py/agent/__snapshots__/generator.spec.ts.snap +0 -771
- package/src/py/agent/a2a-connection/files/agent-connection/app/__targetAgentSnakeCase___client.py.template +0 -22
- package/src/py/agent/files/a2a/main.py.template +0 -54
- package/src/py/agent/files/ag-ui/main.py.template +0 -37
- package/src/py/agent/mcp-connection/files/agent-connection/app/__mcpServerSnakeCase___client.py.template +0 -22
- package/src/py/agent/react-connection/serve-local.js +0 -30
- package/src/py/agent/react-connection/serve-local.js.map +0 -1
- package/src/py/agent/scripts/http/chat.ts.template +0 -38
- package/src/ts/agent/a2a-connection/files/agent-connection/app/__targetAgentKebabCase__-client.ts.template +0 -19
- package/src/ts/agent/mcp-connection/files/agent-connection/app/__mcpServerKebabCase__-client.ts.template +0 -19
- package/src/ts/agent/react-connection/serve-local.d.ts +0 -13
- package/src/ts/agent/react-connection/serve-local.js +0 -19
- package/src/ts/agent/react-connection/serve-local.js.map +0 -1
- package/src/ts/agent/scripts/http/chat.ts.template +0 -35
- package/src/ts/dynamodb/files/scripts/pull-image.ts.template +0 -15
- package/src/ts/dynamodb/files/src/constants.ts.template +0 -9
- package/src/ts/dynamodb/files/src/gsi.ts.template +0 -14
- package/src/ts/rdb/files/scripts/pull-image.ts.template +0 -15
- package/src/ts/rdb/files/scripts/start-container.ts.template +0 -84
- package/src/ts/rdb/files/scripts/wait-for-db.ts.template +0 -55
- package/src/ts/rdb/files/src/constants.ts.template +0 -8
- package/src/ts/rdb/files/src/index.ts.template +0 -2
- package/src/utils/agent-connection/files/core-a2a/agentcore-a2a-client.ts.template +0 -123
- package/src/utils/agent-connection/files/core-mcp/agentcore-mcp-client.ts.template +0 -128
- package/src/utils/agent-connection/files/py-core-a2a/agentcore_a2a_client.py.template +0 -120
- package/src/utils/agent-connection/files/py-core-mcp/agentcore_mcp_client.py.template +0 -89
- package/src/utils/files/common/scripts/src/infra-deploy.ts.template +0 -2
- package/src/utils/files/common/scripts/src/infra-destroy.ts.template +0 -2
- package/src/utils/files/common/scripts/src/stage-credentials/cdk-command.ts.template +0 -18
- package/src/utils/files/terraform/scripts/reset-runtime-config.ts.template +0 -25
- /package/src/py/agent/files/{common → langchain/common}/__init__.py.template +0 -0
- /package/src/smithy/project/files/{src → service/src}/main.smithy.template +0 -0
- /package/src/utils/agent-connection/files/{py-core-runtime-config/model_errors.py.template → py-core-strands/base/model_errors_strands.py.template} +0 -0
- /package/src/utils/files/common/scripts/src/{index.ts.template → infra/index.ts.template} +0 -0
- /package/src/utils/files/common/scripts/src/{stage-credentials → infra/stage-credentials}/credentials.ts.template +0 -0
- /package/src/utils/files/common/scripts/src/{stage-credentials → infra/stage-credentials}/stage-parser.ts.template +0 -0
|
@@ -32,6 +32,7 @@ import {
|
|
|
32
32
|
IntegrationBuilder,
|
|
33
33
|
RestApiIntegration,
|
|
34
34
|
} from '../../core/api/utils.js';
|
|
35
|
+
import { findCloudFrontDomainNames } from '../../core/cloudfront.js';
|
|
35
36
|
import { AddCorsPreflightAspect, RestApi } from '../../core/api/rest-api.js';
|
|
36
37
|
import {
|
|
37
38
|
OPERATION_DETAILS,
|
|
@@ -86,8 +87,8 @@ export class TestApi<
|
|
|
86
87
|
return IntegrationBuilder.rest({
|
|
87
88
|
pattern: 'isolated',
|
|
88
89
|
operations: OPERATION_DETAILS,
|
|
89
|
-
defaultIntegrationOptions:
|
|
90
|
-
runtime: Runtime.
|
|
90
|
+
defaultIntegrationOptions: {
|
|
91
|
+
runtime: Runtime.NODEJS_24_X,
|
|
91
92
|
handler: 'index.handler',
|
|
92
93
|
code: Code.fromAsset(
|
|
93
94
|
url.fileURLToPath(
|
|
@@ -99,7 +100,7 @@ export class TestApi<
|
|
|
99
100
|
),
|
|
100
101
|
timeout: Duration.seconds(30),
|
|
101
102
|
tracing: Tracing.ACTIVE,
|
|
102
|
-
},
|
|
103
|
+
} as FunctionProps,
|
|
103
104
|
buildDefaultIntegration: (op, props: FunctionProps) => {
|
|
104
105
|
const handler = new Function(scope, \`TestApi\${op}Handler\`, props);
|
|
105
106
|
handler.addEnvironment(
|
|
@@ -127,6 +128,9 @@ export class TestApi<
|
|
|
127
128
|
authorizer: new CognitoUserPoolsAuthorizer(scope, 'TestApiAuthorizer', {
|
|
128
129
|
cognitoUserPools: [props.identity.userPool],
|
|
129
130
|
}),
|
|
131
|
+
// Accept access tokens from both sign-in flows: 'openid' (Cognito hosted UI)
|
|
132
|
+
// and 'aws.cognito.signin.user.admin' (Cognito admin/SRP auth APIs).
|
|
133
|
+
authorizationScopes: ['openid', 'aws.cognito.signin.user.admin'],
|
|
130
134
|
},
|
|
131
135
|
deployOptions: {
|
|
132
136
|
tracingEnabled: true,
|
|
@@ -153,7 +157,9 @@ export class TestApi<
|
|
|
153
157
|
*
|
|
154
158
|
* Configures the provided CloudFront distribution domains or origin strings
|
|
155
159
|
* as the only permitted CORS origins in API Gateway preflight responses and the
|
|
156
|
-
* AWS Lambda integrations.
|
|
160
|
+
* AWS Lambda integrations. Any custom domain names (aliases) configured on a
|
|
161
|
+
* CloudFront distribution are included automatically alongside its default
|
|
162
|
+
* \`*.cloudfront.net\` domain.
|
|
157
163
|
*
|
|
158
164
|
* @param origins - The origin strings, CloudFront distributions, or objects containing a CloudFront distribution to grant CORS from
|
|
159
165
|
*/
|
|
@@ -164,12 +170,14 @@ export class TestApi<
|
|
|
164
170
|
| { cloudFrontDistribution: Distribution }
|
|
165
171
|
)[]
|
|
166
172
|
) {
|
|
167
|
-
const allowedOrigins = origins.
|
|
173
|
+
const allowedOrigins = origins.flatMap((origin) =>
|
|
168
174
|
typeof origin === 'string'
|
|
169
|
-
? origin
|
|
170
|
-
:
|
|
171
|
-
|
|
172
|
-
|
|
175
|
+
? [origin]
|
|
176
|
+
: findCloudFrontDomainNames(
|
|
177
|
+
'cloudFrontDistribution' in origin
|
|
178
|
+
? origin.cloudFrontDistribution
|
|
179
|
+
: origin,
|
|
180
|
+
).map((domain) => \`https://\${domain}\`),
|
|
173
181
|
);
|
|
174
182
|
|
|
175
183
|
this.allowedOrigins = allowedOrigins;
|
|
@@ -218,6 +226,7 @@ import {
|
|
|
218
226
|
IntegrationBuilder,
|
|
219
227
|
RestApiIntegration,
|
|
220
228
|
} from '../../core/api/utils.js';
|
|
229
|
+
import { findCloudFrontDomainNames } from '../../core/cloudfront.js';
|
|
221
230
|
import { AddCorsPreflightAspect, RestApi } from '../../core/api/rest-api.js';
|
|
222
231
|
import {
|
|
223
232
|
OPERATION_DETAILS,
|
|
@@ -266,8 +275,8 @@ export class TestApi<
|
|
|
266
275
|
return IntegrationBuilder.rest({
|
|
267
276
|
pattern: 'isolated',
|
|
268
277
|
operations: OPERATION_DETAILS,
|
|
269
|
-
defaultIntegrationOptions:
|
|
270
|
-
runtime: Runtime.
|
|
278
|
+
defaultIntegrationOptions: {
|
|
279
|
+
runtime: Runtime.NODEJS_24_X,
|
|
271
280
|
handler: 'index.handler',
|
|
272
281
|
code: Code.fromAsset(
|
|
273
282
|
url.fileURLToPath(
|
|
@@ -279,7 +288,7 @@ export class TestApi<
|
|
|
279
288
|
),
|
|
280
289
|
timeout: Duration.seconds(30),
|
|
281
290
|
tracing: Tracing.ACTIVE,
|
|
282
|
-
},
|
|
291
|
+
} as FunctionProps,
|
|
283
292
|
buildDefaultIntegration: (op, props: FunctionProps) => {
|
|
284
293
|
const handler = new Function(scope, \`TestApi\${op}Handler\`, props);
|
|
285
294
|
handler.addEnvironment(
|
|
@@ -330,7 +339,9 @@ export class TestApi<
|
|
|
330
339
|
*
|
|
331
340
|
* Configures the provided CloudFront distribution domains or origin strings
|
|
332
341
|
* as the only permitted CORS origins in API Gateway preflight responses and the
|
|
333
|
-
* AWS Lambda integrations.
|
|
342
|
+
* AWS Lambda integrations. Any custom domain names (aliases) configured on a
|
|
343
|
+
* CloudFront distribution are included automatically alongside its default
|
|
344
|
+
* \`*.cloudfront.net\` domain.
|
|
334
345
|
*
|
|
335
346
|
* @param origins - The origin strings, CloudFront distributions, or objects containing a CloudFront distribution to grant CORS from
|
|
336
347
|
*/
|
|
@@ -341,12 +352,14 @@ export class TestApi<
|
|
|
341
352
|
| { cloudFrontDistribution: Distribution }
|
|
342
353
|
)[]
|
|
343
354
|
) {
|
|
344
|
-
const allowedOrigins = origins.
|
|
355
|
+
const allowedOrigins = origins.flatMap((origin) =>
|
|
345
356
|
typeof origin === 'string'
|
|
346
|
-
? origin
|
|
347
|
-
:
|
|
348
|
-
|
|
349
|
-
|
|
357
|
+
? [origin]
|
|
358
|
+
: findCloudFrontDomainNames(
|
|
359
|
+
'cloudFrontDistribution' in origin
|
|
360
|
+
? origin.cloudFrontDistribution
|
|
361
|
+
: origin,
|
|
362
|
+
).map((domain) => \`https://\${domain}\`),
|
|
350
363
|
);
|
|
351
364
|
|
|
352
365
|
this.allowedOrigins = allowedOrigins;
|
|
@@ -400,11 +413,11 @@ terraform {
|
|
|
400
413
|
required_providers {
|
|
401
414
|
aws = {
|
|
402
415
|
source = "hashicorp/aws"
|
|
403
|
-
version = "
|
|
416
|
+
version = "6.62.0"
|
|
404
417
|
}
|
|
405
418
|
random = {
|
|
406
419
|
source = "hashicorp/random"
|
|
407
|
-
version = "
|
|
420
|
+
version = "3.9.0"
|
|
408
421
|
}
|
|
409
422
|
}
|
|
410
423
|
}
|
|
@@ -474,8 +487,6 @@ data "aws_caller_identity" "current" {}
|
|
|
474
487
|
|
|
475
488
|
# Resources
|
|
476
489
|
|
|
477
|
-
# Note: CloudWatch logging removed due to account-level CloudWatch Logs role ARN requirement
|
|
478
|
-
|
|
479
490
|
# REST API Gateway
|
|
480
491
|
resource "aws_api_gateway_rest_api" "rest_api" {
|
|
481
492
|
name = var.api_name
|
|
@@ -492,10 +503,8 @@ resource "aws_api_gateway_rest_api" "rest_api" {
|
|
|
492
503
|
tags = var.tags
|
|
493
504
|
}
|
|
494
505
|
|
|
495
|
-
# Note: Deployment and
|
|
496
|
-
# after all methods and integrations are defined
|
|
497
|
-
|
|
498
|
-
# Note: CloudWatch Log Group removed due to account-level CloudWatch Logs role ARN requirement
|
|
506
|
+
# Note: Deployment, stage and access logging are created in the consuming module
|
|
507
|
+
# (e.g., foo-api.tf) after all methods and integrations are defined
|
|
499
508
|
|
|
500
509
|
# Gateway Response for CORS (4XX errors)
|
|
501
510
|
resource "aws_api_gateway_gateway_response" "cors_4xx" {
|
|
@@ -597,22 +606,75 @@ resource "aws_wafv2_web_acl" "api_waf" {
|
|
|
597
606
|
}
|
|
598
607
|
}
|
|
599
608
|
|
|
609
|
+
resource "random_id" "waf_log_suffix" {
|
|
610
|
+
count = var.enable_waf ? 1 : 0
|
|
611
|
+
byte_length = 4
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
locals {
|
|
615
|
+
waf_log_group_name = var.enable_waf ? "aws-waf-logs-\${var.api_name}-\${random_id.waf_log_suffix[0].hex}" : null
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
# KMS key for encrypting WAF request logs at rest
|
|
619
|
+
resource "aws_kms_key" "waf_logs" {
|
|
620
|
+
count = var.enable_waf ? 1 : 0
|
|
621
|
+
|
|
622
|
+
description = "\${var.api_name} API WAF log encryption"
|
|
623
|
+
deletion_window_in_days = 7
|
|
624
|
+
enable_key_rotation = true
|
|
625
|
+
|
|
626
|
+
policy = jsonencode({
|
|
627
|
+
Version = "2012-10-17"
|
|
628
|
+
Statement = [
|
|
629
|
+
{
|
|
630
|
+
Sid = "Enable IAM User Permissions"
|
|
631
|
+
Effect = "Allow"
|
|
632
|
+
Principal = { AWS = "arn:aws:iam::\${data.aws_caller_identity.current.account_id}:root" }
|
|
633
|
+
Action = "kms:*"
|
|
634
|
+
Resource = "*"
|
|
635
|
+
},
|
|
636
|
+
{
|
|
637
|
+
Sid = "Allow CloudWatch Logs"
|
|
638
|
+
Effect = "Allow"
|
|
639
|
+
Principal = { Service = "logs.\${data.aws_region.current.region}.amazonaws.com" }
|
|
640
|
+
Action = [
|
|
641
|
+
"kms:Encrypt",
|
|
642
|
+
"kms:Decrypt",
|
|
643
|
+
"kms:ReEncrypt*",
|
|
644
|
+
"kms:GenerateDataKey*",
|
|
645
|
+
"kms:DescribeKey"
|
|
646
|
+
]
|
|
647
|
+
Resource = "*"
|
|
648
|
+
Condition = {
|
|
649
|
+
ArnEquals = {
|
|
650
|
+
"kms:EncryptionContext:aws:logs:arn" = "arn:aws:logs:\${data.aws_region.current.region}:\${data.aws_caller_identity.current.account_id}:log-group:\${local.waf_log_group_name}"
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
]
|
|
655
|
+
})
|
|
656
|
+
|
|
657
|
+
tags = var.tags
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
resource "aws_kms_alias" "waf_logs" {
|
|
661
|
+
count = var.enable_waf ? 1 : 0
|
|
662
|
+
|
|
663
|
+
name = "alias/\${var.api_name}-\${random_id.waf_log_suffix[0].hex}-waf-logs"
|
|
664
|
+
target_key_id = aws_kms_key.waf_logs[0].key_id
|
|
665
|
+
}
|
|
666
|
+
|
|
600
667
|
# CloudWatch Log Group for WAF request logs. Name must start with \`aws-waf-logs-\`.
|
|
601
668
|
resource "aws_cloudwatch_log_group" "api_waf_logs" {
|
|
602
|
-
#checkov:skip=CKV_AWS_158:Using default CloudWatch log encryption
|
|
603
669
|
#checkov:skip=CKV_AWS_338:Log retention set to one month which is sufficient for WAF logs
|
|
604
670
|
count = var.enable_waf ? 1 : 0
|
|
605
671
|
|
|
606
|
-
name =
|
|
672
|
+
name = local.waf_log_group_name
|
|
607
673
|
retention_in_days = 30
|
|
674
|
+
kms_key_id = aws_kms_key.waf_logs[0].arn
|
|
608
675
|
tags = var.tags
|
|
609
676
|
}
|
|
610
677
|
|
|
611
|
-
resource "random_id" "waf_log_suffix" {
|
|
612
|
-
count = var.enable_waf ? 1 : 0
|
|
613
|
-
byte_length = 4
|
|
614
|
-
}
|
|
615
|
-
|
|
616
678
|
resource "aws_wafv2_web_acl_logging_configuration" "api_waf_logging" {
|
|
617
679
|
count = var.enable_waf ? 1 : 0
|
|
618
680
|
|
|
@@ -653,9 +715,7 @@ output "waf_web_acl_arn" {
|
|
|
653
715
|
value = var.enable_waf ? aws_wafv2_web_acl.api_waf[0].arn : null
|
|
654
716
|
}
|
|
655
717
|
|
|
656
|
-
# Note: Stage and
|
|
657
|
-
|
|
658
|
-
# Note: CloudWatch log group outputs removed due to account-level CloudWatch Logs role ARN requirement"
|
|
718
|
+
# Note: Stage, deployment and access log outputs are provided by the consuming module"
|
|
659
719
|
`;
|
|
660
720
|
|
|
661
721
|
exports[`tsSmithyApiGenerator > should generate smithy ts api with Terraform provider and None auth > none-auth-terraform.tf 1`] = `
|
|
@@ -663,9 +723,17 @@ exports[`tsSmithyApiGenerator > should generate smithy ts api with Terraform pro
|
|
|
663
723
|
required_version = ">= 1.0"
|
|
664
724
|
|
|
665
725
|
required_providers {
|
|
726
|
+
archive = {
|
|
727
|
+
source = "hashicorp/archive"
|
|
728
|
+
version = "2.8.0"
|
|
729
|
+
}
|
|
666
730
|
aws = {
|
|
667
731
|
source = "hashicorp/aws"
|
|
668
|
-
version = "
|
|
732
|
+
version = "6.62.0"
|
|
733
|
+
}
|
|
734
|
+
random = {
|
|
735
|
+
source = "hashicorp/random"
|
|
736
|
+
version = "3.9.0"
|
|
669
737
|
}
|
|
670
738
|
}
|
|
671
739
|
}
|
|
@@ -687,11 +755,47 @@ variable "additional_iam_policy_statements" {
|
|
|
687
755
|
default = []
|
|
688
756
|
}
|
|
689
757
|
|
|
758
|
+
variable "appconfig_application_id" {
|
|
759
|
+
description = "ID of the shared runtime-config AppConfig application (from \`core/runtime-config/appconfig.application_id\`). When set, the Lambda functions receive \`RUNTIME_CONFIG_APP_ID\` and read access to the application."
|
|
760
|
+
type = string
|
|
761
|
+
default = null
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
variable "appconfig_application_arn" {
|
|
765
|
+
description = "ARN of the shared runtime-config AppConfig application (from \`core/runtime-config/appconfig.application_arn\`). Used to scope the IAM read permission granted to the Lambda functions."
|
|
766
|
+
type = string
|
|
767
|
+
default = null
|
|
768
|
+
}
|
|
769
|
+
|
|
690
770
|
variable "asset_bucket_name" {
|
|
691
771
|
description = "Name of the shared asset S3 bucket used to stage the Lambda deployment zip. Instantiate the \`core/asset-bucket\` module once per deployment and pass its \`bucket_name\` output here."
|
|
692
772
|
type = string
|
|
693
773
|
}
|
|
694
774
|
|
|
775
|
+
# VPC Configuration (optional)
|
|
776
|
+
variable "enable_vpc" {
|
|
777
|
+
description = "Deploy the Lambda function into a VPC. Set alongside vpc_id/subnet_ids."
|
|
778
|
+
type = bool
|
|
779
|
+
default = false
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
variable "vpc_id" {
|
|
783
|
+
description = "VPC ID to deploy the Lambda function into. Required when enable_vpc is true."
|
|
784
|
+
type = string
|
|
785
|
+
default = null
|
|
786
|
+
|
|
787
|
+
validation {
|
|
788
|
+
condition = !var.enable_vpc || (var.vpc_id != null && var.subnet_ids != null)
|
|
789
|
+
error_message = "vpc_id and subnet_ids must be set when enable_vpc is true."
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
variable "subnet_ids" {
|
|
794
|
+
description = "Subnet IDs to deploy the Lambda function into. Required when enable_vpc is true."
|
|
795
|
+
type = list(string)
|
|
796
|
+
default = null
|
|
797
|
+
}
|
|
798
|
+
|
|
695
799
|
# CORS Configuration (passed to core module)
|
|
696
800
|
|
|
697
801
|
variable "cors_allow_headers" {
|
|
@@ -736,6 +840,235 @@ resource "random_string" "suffix" {
|
|
|
736
840
|
upper = false
|
|
737
841
|
}
|
|
738
842
|
|
|
843
|
+
locals {
|
|
844
|
+
# Generated at build time from the API definition
|
|
845
|
+
operations_file = "\${path.module}/../../../generated/test-api/operations.json"
|
|
846
|
+
operations = fileexists(local.operations_file) ? jsondecode(file(local.operations_file)) : {}
|
|
847
|
+
|
|
848
|
+
operation_slug = { for op in keys(local.operations) : op => replace(op, "/[^a-zA-Z0-9-_]/", "-") }
|
|
849
|
+
operation_hash = { for op in keys(local.operations) : op => substr(sha256(op), 0, 8) }
|
|
850
|
+
|
|
851
|
+
function_name = { for op in keys(local.operations) : op =>
|
|
852
|
+
"\${substr("TestApi-\${local.operation_slug[op]}", 0, 64 - length(local.operation_hash[op]) - length(random_string.suffix.result) - 2)}-\${local.operation_hash[op]}-\${random_string.suffix.result}"
|
|
853
|
+
}
|
|
854
|
+
role_name = { for op in keys(local.operations) : op =>
|
|
855
|
+
"\${substr("TestApi-\${local.operation_slug[op]}-role", 0, 64 - length(local.operation_hash[op]) - length(random_string.suffix.result) - 2)}-\${local.operation_hash[op]}-\${random_string.suffix.result}"
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
# A REST API needs a resource per path segment, so each operation's path is
|
|
859
|
+
# split into the distinct path prefixes the resource tree is built from below
|
|
860
|
+
operation_segments = { for op, details in local.operations : op => compact(split("/", details.path)) }
|
|
861
|
+
|
|
862
|
+
path_nodes = merge([
|
|
863
|
+
for op, segments in local.operation_segments : {
|
|
864
|
+
for i, segment in segments : join("/", slice(segments, 0, i + 1)) => {
|
|
865
|
+
depth = i
|
|
866
|
+
parent = i == 0 ? "" : join("/", slice(segments, 0, i))
|
|
867
|
+
part = segment
|
|
868
|
+
}
|
|
869
|
+
}
|
|
870
|
+
]...)
|
|
871
|
+
|
|
872
|
+
# Instances of a resource cannot reference one another, so each depth is a
|
|
873
|
+
# separate resource. Deeper paths are reported by the precondition below.
|
|
874
|
+
max_path_depth = 16
|
|
875
|
+
path_nodes_by_depth = { for depth in range(local.max_path_depth) : depth => {
|
|
876
|
+
for path, node in local.path_nodes : path => node if node.depth == depth
|
|
877
|
+
} }
|
|
878
|
+
paths_too_deep = [for path, node in local.path_nodes : path if node.depth >= local.max_path_depth]
|
|
879
|
+
|
|
880
|
+
resource_ids = merge(
|
|
881
|
+
{ for path, resource in aws_api_gateway_resource.path_depth_0 : path => resource.id },
|
|
882
|
+
{ for path, resource in aws_api_gateway_resource.path_depth_1 : path => resource.id },
|
|
883
|
+
{ for path, resource in aws_api_gateway_resource.path_depth_2 : path => resource.id },
|
|
884
|
+
{ for path, resource in aws_api_gateway_resource.path_depth_3 : path => resource.id },
|
|
885
|
+
{ for path, resource in aws_api_gateway_resource.path_depth_4 : path => resource.id },
|
|
886
|
+
{ for path, resource in aws_api_gateway_resource.path_depth_5 : path => resource.id },
|
|
887
|
+
{ for path, resource in aws_api_gateway_resource.path_depth_6 : path => resource.id },
|
|
888
|
+
{ for path, resource in aws_api_gateway_resource.path_depth_7 : path => resource.id },
|
|
889
|
+
{ for path, resource in aws_api_gateway_resource.path_depth_8 : path => resource.id },
|
|
890
|
+
{ for path, resource in aws_api_gateway_resource.path_depth_9 : path => resource.id },
|
|
891
|
+
{ for path, resource in aws_api_gateway_resource.path_depth_10 : path => resource.id },
|
|
892
|
+
{ for path, resource in aws_api_gateway_resource.path_depth_11 : path => resource.id },
|
|
893
|
+
{ for path, resource in aws_api_gateway_resource.path_depth_12 : path => resource.id },
|
|
894
|
+
{ for path, resource in aws_api_gateway_resource.path_depth_13 : path => resource.id },
|
|
895
|
+
{ for path, resource in aws_api_gateway_resource.path_depth_14 : path => resource.id },
|
|
896
|
+
{ for path, resource in aws_api_gateway_resource.path_depth_15 : path => resource.id },
|
|
897
|
+
)
|
|
898
|
+
|
|
899
|
+
operation_resource_id = { for op, segments in local.operation_segments : op =>
|
|
900
|
+
local.resource_ids[join("/", segments)]
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
permission_source_suffix = { for op, details in local.operations : op =>
|
|
904
|
+
"\${upper(details.method)}/\${replace(join("/", local.operation_segments[op]), "/{[^}]*}/", "*")}"
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
resource "terraform_data" "operations_metadata" {
|
|
909
|
+
# Fails the plan when the operations metadata has not been generated
|
|
910
|
+
input = local.operations_file
|
|
911
|
+
|
|
912
|
+
lifecycle {
|
|
913
|
+
precondition {
|
|
914
|
+
condition = fileexists(local.operations_file)
|
|
915
|
+
error_message = "Operations metadata not found at \${local.operations_file}. Build the TestApi project to generate it."
|
|
916
|
+
}
|
|
917
|
+
precondition {
|
|
918
|
+
condition = length(local.operations) > 0
|
|
919
|
+
error_message = "No operations found in \${local.operations_file}. The TestApi API must define at least one operation."
|
|
920
|
+
}
|
|
921
|
+
precondition {
|
|
922
|
+
condition = length(local.paths_too_deep) == 0
|
|
923
|
+
error_message = "Operation paths exceed the supported depth of \${local.max_path_depth} segments: \${join(", ", local.paths_too_deep)}. Add further aws_api_gateway_resource levels to this module to support them."
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
# API Gateway resources at path depth 0
|
|
929
|
+
resource "aws_api_gateway_resource" "path_depth_0" {
|
|
930
|
+
for_each = local.path_nodes_by_depth[0]
|
|
931
|
+
|
|
932
|
+
rest_api_id = module.rest_api.api_id
|
|
933
|
+
parent_id = module.rest_api.api_root_resource_id
|
|
934
|
+
path_part = each.value.part
|
|
935
|
+
}
|
|
936
|
+
|
|
937
|
+
# API Gateway resources at path depth 1
|
|
938
|
+
resource "aws_api_gateway_resource" "path_depth_1" {
|
|
939
|
+
for_each = local.path_nodes_by_depth[1]
|
|
940
|
+
|
|
941
|
+
rest_api_id = module.rest_api.api_id
|
|
942
|
+
parent_id = aws_api_gateway_resource.path_depth_0[each.value.parent].id
|
|
943
|
+
path_part = each.value.part
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
# API Gateway resources at path depth 2
|
|
947
|
+
resource "aws_api_gateway_resource" "path_depth_2" {
|
|
948
|
+
for_each = local.path_nodes_by_depth[2]
|
|
949
|
+
|
|
950
|
+
rest_api_id = module.rest_api.api_id
|
|
951
|
+
parent_id = aws_api_gateway_resource.path_depth_1[each.value.parent].id
|
|
952
|
+
path_part = each.value.part
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
# API Gateway resources at path depth 3
|
|
956
|
+
resource "aws_api_gateway_resource" "path_depth_3" {
|
|
957
|
+
for_each = local.path_nodes_by_depth[3]
|
|
958
|
+
|
|
959
|
+
rest_api_id = module.rest_api.api_id
|
|
960
|
+
parent_id = aws_api_gateway_resource.path_depth_2[each.value.parent].id
|
|
961
|
+
path_part = each.value.part
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
# API Gateway resources at path depth 4
|
|
965
|
+
resource "aws_api_gateway_resource" "path_depth_4" {
|
|
966
|
+
for_each = local.path_nodes_by_depth[4]
|
|
967
|
+
|
|
968
|
+
rest_api_id = module.rest_api.api_id
|
|
969
|
+
parent_id = aws_api_gateway_resource.path_depth_3[each.value.parent].id
|
|
970
|
+
path_part = each.value.part
|
|
971
|
+
}
|
|
972
|
+
|
|
973
|
+
# API Gateway resources at path depth 5
|
|
974
|
+
resource "aws_api_gateway_resource" "path_depth_5" {
|
|
975
|
+
for_each = local.path_nodes_by_depth[5]
|
|
976
|
+
|
|
977
|
+
rest_api_id = module.rest_api.api_id
|
|
978
|
+
parent_id = aws_api_gateway_resource.path_depth_4[each.value.parent].id
|
|
979
|
+
path_part = each.value.part
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
# API Gateway resources at path depth 6
|
|
983
|
+
resource "aws_api_gateway_resource" "path_depth_6" {
|
|
984
|
+
for_each = local.path_nodes_by_depth[6]
|
|
985
|
+
|
|
986
|
+
rest_api_id = module.rest_api.api_id
|
|
987
|
+
parent_id = aws_api_gateway_resource.path_depth_5[each.value.parent].id
|
|
988
|
+
path_part = each.value.part
|
|
989
|
+
}
|
|
990
|
+
|
|
991
|
+
# API Gateway resources at path depth 7
|
|
992
|
+
resource "aws_api_gateway_resource" "path_depth_7" {
|
|
993
|
+
for_each = local.path_nodes_by_depth[7]
|
|
994
|
+
|
|
995
|
+
rest_api_id = module.rest_api.api_id
|
|
996
|
+
parent_id = aws_api_gateway_resource.path_depth_6[each.value.parent].id
|
|
997
|
+
path_part = each.value.part
|
|
998
|
+
}
|
|
999
|
+
|
|
1000
|
+
# API Gateway resources at path depth 8
|
|
1001
|
+
resource "aws_api_gateway_resource" "path_depth_8" {
|
|
1002
|
+
for_each = local.path_nodes_by_depth[8]
|
|
1003
|
+
|
|
1004
|
+
rest_api_id = module.rest_api.api_id
|
|
1005
|
+
parent_id = aws_api_gateway_resource.path_depth_7[each.value.parent].id
|
|
1006
|
+
path_part = each.value.part
|
|
1007
|
+
}
|
|
1008
|
+
|
|
1009
|
+
# API Gateway resources at path depth 9
|
|
1010
|
+
resource "aws_api_gateway_resource" "path_depth_9" {
|
|
1011
|
+
for_each = local.path_nodes_by_depth[9]
|
|
1012
|
+
|
|
1013
|
+
rest_api_id = module.rest_api.api_id
|
|
1014
|
+
parent_id = aws_api_gateway_resource.path_depth_8[each.value.parent].id
|
|
1015
|
+
path_part = each.value.part
|
|
1016
|
+
}
|
|
1017
|
+
|
|
1018
|
+
# API Gateway resources at path depth 10
|
|
1019
|
+
resource "aws_api_gateway_resource" "path_depth_10" {
|
|
1020
|
+
for_each = local.path_nodes_by_depth[10]
|
|
1021
|
+
|
|
1022
|
+
rest_api_id = module.rest_api.api_id
|
|
1023
|
+
parent_id = aws_api_gateway_resource.path_depth_9[each.value.parent].id
|
|
1024
|
+
path_part = each.value.part
|
|
1025
|
+
}
|
|
1026
|
+
|
|
1027
|
+
# API Gateway resources at path depth 11
|
|
1028
|
+
resource "aws_api_gateway_resource" "path_depth_11" {
|
|
1029
|
+
for_each = local.path_nodes_by_depth[11]
|
|
1030
|
+
|
|
1031
|
+
rest_api_id = module.rest_api.api_id
|
|
1032
|
+
parent_id = aws_api_gateway_resource.path_depth_10[each.value.parent].id
|
|
1033
|
+
path_part = each.value.part
|
|
1034
|
+
}
|
|
1035
|
+
|
|
1036
|
+
# API Gateway resources at path depth 12
|
|
1037
|
+
resource "aws_api_gateway_resource" "path_depth_12" {
|
|
1038
|
+
for_each = local.path_nodes_by_depth[12]
|
|
1039
|
+
|
|
1040
|
+
rest_api_id = module.rest_api.api_id
|
|
1041
|
+
parent_id = aws_api_gateway_resource.path_depth_11[each.value.parent].id
|
|
1042
|
+
path_part = each.value.part
|
|
1043
|
+
}
|
|
1044
|
+
|
|
1045
|
+
# API Gateway resources at path depth 13
|
|
1046
|
+
resource "aws_api_gateway_resource" "path_depth_13" {
|
|
1047
|
+
for_each = local.path_nodes_by_depth[13]
|
|
1048
|
+
|
|
1049
|
+
rest_api_id = module.rest_api.api_id
|
|
1050
|
+
parent_id = aws_api_gateway_resource.path_depth_12[each.value.parent].id
|
|
1051
|
+
path_part = each.value.part
|
|
1052
|
+
}
|
|
1053
|
+
|
|
1054
|
+
# API Gateway resources at path depth 14
|
|
1055
|
+
resource "aws_api_gateway_resource" "path_depth_14" {
|
|
1056
|
+
for_each = local.path_nodes_by_depth[14]
|
|
1057
|
+
|
|
1058
|
+
rest_api_id = module.rest_api.api_id
|
|
1059
|
+
parent_id = aws_api_gateway_resource.path_depth_13[each.value.parent].id
|
|
1060
|
+
path_part = each.value.part
|
|
1061
|
+
}
|
|
1062
|
+
|
|
1063
|
+
# API Gateway resources at path depth 15
|
|
1064
|
+
resource "aws_api_gateway_resource" "path_depth_15" {
|
|
1065
|
+
for_each = local.path_nodes_by_depth[15]
|
|
1066
|
+
|
|
1067
|
+
rest_api_id = module.rest_api.api_id
|
|
1068
|
+
parent_id = aws_api_gateway_resource.path_depth_14[each.value.parent].id
|
|
1069
|
+
path_part = each.value.part
|
|
1070
|
+
}
|
|
1071
|
+
|
|
739
1072
|
# Resources
|
|
740
1073
|
|
|
741
1074
|
# Create Lambda ZIP file from the bundle directory
|
|
@@ -754,6 +1087,11 @@ resource "aws_s3_object" "lambda_zip" {
|
|
|
754
1087
|
}
|
|
755
1088
|
|
|
756
1089
|
# Use the core REST API module
|
|
1090
|
+
# Account-level CloudWatch role required for REST API access logging
|
|
1091
|
+
module "account" {
|
|
1092
|
+
source = "../../../core/api/api-gateway-account"
|
|
1093
|
+
}
|
|
1094
|
+
|
|
757
1095
|
module "rest_api" {
|
|
758
1096
|
source = "../../../core/api/rest-api"
|
|
759
1097
|
|
|
@@ -783,9 +1121,33 @@ resource "aws_wafv2_web_acl_association" "api_waf_association" {
|
|
|
783
1121
|
depends_on = [aws_api_gateway_stage.api_stage]
|
|
784
1122
|
}
|
|
785
1123
|
|
|
786
|
-
# Lambda function
|
|
1124
|
+
# Security group for the API Lambda function, used when deployed into a VPC
|
|
1125
|
+
resource "aws_security_group" "api_lambda" {
|
|
1126
|
+
count = var.enable_vpc ? 1 : 0
|
|
1127
|
+
|
|
1128
|
+
#checkov:skip=CKV2_AWS_5:Attached to api_lambda via vpc_config block; Checkov cannot resolve this reference
|
|
1129
|
+
name_prefix = "test-api-lambda-"
|
|
1130
|
+
description = "Security group for the TestApi API Lambda function"
|
|
1131
|
+
vpc_id = var.vpc_id
|
|
1132
|
+
tags = var.tags
|
|
1133
|
+
}
|
|
1134
|
+
|
|
1135
|
+
resource "aws_vpc_security_group_egress_rule" "api_lambda_https" {
|
|
1136
|
+
count = var.enable_vpc ? 1 : 0
|
|
1137
|
+
|
|
1138
|
+
security_group_id = aws_security_group.api_lambda[0].id
|
|
1139
|
+
cidr_ipv4 = "0.0.0.0/0"
|
|
1140
|
+
from_port = 443
|
|
1141
|
+
to_port = 443
|
|
1142
|
+
ip_protocol = "tcp"
|
|
1143
|
+
description = "Allow outbound HTTPS to AWS service endpoints"
|
|
1144
|
+
}
|
|
1145
|
+
|
|
787
1146
|
resource "aws_lambda_function" "api_lambda" {
|
|
788
|
-
#
|
|
1147
|
+
# One lambda function per operation, each serving just that operation
|
|
1148
|
+
for_each = local.operations
|
|
1149
|
+
|
|
1150
|
+
#checkov:skip=CKV_AWS_117:Lambda function is optionally deployed into a VPC via vpc_id/subnet_ids; not required for this use case
|
|
789
1151
|
#checkov:skip=CKV_AWS_116:Dead Letter Queue not required for this simple API use case
|
|
790
1152
|
#checkov:skip=CKV_AWS_272:Code signing not required for this use case
|
|
791
1153
|
#checkov:skip=CKV_AWS_115:Concurrent execution limit not required for this use case
|
|
@@ -793,10 +1155,10 @@ resource "aws_lambda_function" "api_lambda" {
|
|
|
793
1155
|
s3_bucket = aws_s3_object.lambda_zip.bucket
|
|
794
1156
|
s3_key = aws_s3_object.lambda_zip.key
|
|
795
1157
|
s3_object_version = aws_s3_object.lambda_zip.version_id
|
|
796
|
-
function_name =
|
|
797
|
-
role = aws_iam_role.lambda_execution_role.arn
|
|
1158
|
+
function_name = local.function_name[each.key]
|
|
1159
|
+
role = aws_iam_role.lambda_execution_role[each.key].arn
|
|
798
1160
|
handler = "index.handler"
|
|
799
|
-
runtime = "
|
|
1161
|
+
runtime = "nodejs24.x"
|
|
800
1162
|
timeout = 30
|
|
801
1163
|
memory_size = 128
|
|
802
1164
|
|
|
@@ -807,18 +1169,32 @@ resource "aws_lambda_function" "api_lambda" {
|
|
|
807
1169
|
mode = "Active"
|
|
808
1170
|
}
|
|
809
1171
|
|
|
1172
|
+
dynamic "vpc_config" {
|
|
1173
|
+
for_each = var.enable_vpc ? [1] : []
|
|
1174
|
+
content {
|
|
1175
|
+
subnet_ids = var.subnet_ids
|
|
1176
|
+
security_group_ids = [aws_security_group.api_lambda[0].id]
|
|
1177
|
+
}
|
|
1178
|
+
}
|
|
1179
|
+
|
|
810
1180
|
|
|
811
1181
|
environment {
|
|
812
1182
|
variables = merge({
|
|
813
|
-
}, var.
|
|
1183
|
+
}, var.appconfig_application_id != null ? {
|
|
1184
|
+
RUNTIME_CONFIG_APP_ID = var.appconfig_application_id
|
|
1185
|
+
} : {}, var.env)
|
|
814
1186
|
}
|
|
815
1187
|
|
|
816
1188
|
tags = var.tags
|
|
1189
|
+
|
|
1190
|
+
depends_on = [aws_iam_role_policy_attachment.lambda_vpc_access]
|
|
817
1191
|
}
|
|
818
1192
|
|
|
819
1193
|
# IAM role for Lambda execution
|
|
820
1194
|
resource "aws_iam_role" "lambda_execution_role" {
|
|
821
|
-
|
|
1195
|
+
for_each = local.operations
|
|
1196
|
+
|
|
1197
|
+
name = local.role_name[each.key]
|
|
822
1198
|
|
|
823
1199
|
assume_role_policy = jsonencode({
|
|
824
1200
|
Version = "2012-10-17"
|
|
@@ -838,35 +1214,73 @@ resource "aws_iam_role" "lambda_execution_role" {
|
|
|
838
1214
|
|
|
839
1215
|
# Attach basic execution policy to Lambda role
|
|
840
1216
|
resource "aws_iam_role_policy_attachment" "lambda_basic_execution" {
|
|
1217
|
+
for_each = local.operations
|
|
1218
|
+
|
|
841
1219
|
policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
|
|
842
|
-
role = aws_iam_role.lambda_execution_role.name
|
|
1220
|
+
role = aws_iam_role.lambda_execution_role[each.key].name
|
|
843
1221
|
}
|
|
844
1222
|
|
|
845
1223
|
# Attach X-Ray tracing policy to Lambda role
|
|
846
1224
|
resource "aws_iam_role_policy_attachment" "lambda_xray_execution" {
|
|
1225
|
+
for_each = local.operations
|
|
1226
|
+
|
|
847
1227
|
policy_arn = "arn:aws:iam::aws:policy/AWSXRayDaemonWriteAccess"
|
|
848
|
-
role = aws_iam_role.lambda_execution_role.name
|
|
1228
|
+
role = aws_iam_role.lambda_execution_role[each.key].name
|
|
1229
|
+
}
|
|
1230
|
+
|
|
1231
|
+
# Attach VPC access policy to Lambda role when deployed into a VPC
|
|
1232
|
+
resource "aws_iam_role_policy_attachment" "lambda_vpc_access" {
|
|
1233
|
+
for_each = var.enable_vpc ? local.operations : {}
|
|
1234
|
+
|
|
1235
|
+
policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole"
|
|
1236
|
+
role = aws_iam_role.lambda_execution_role[each.key].name
|
|
849
1237
|
}
|
|
850
1238
|
|
|
851
1239
|
# Additional IAM policies for Lambda (if provided)
|
|
852
1240
|
resource "aws_iam_role_policy" "lambda_additional_policies" {
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
1241
|
+
for_each = local.operations
|
|
1242
|
+
|
|
1243
|
+
name = "\${substr(local.function_name[each.key], 0, 55)}-policies"
|
|
1244
|
+
role = aws_iam_role.lambda_execution_role[each.key].id
|
|
856
1245
|
|
|
857
1246
|
policy = jsonencode({
|
|
858
1247
|
Version = "2012-10-17"
|
|
859
|
-
Statement =
|
|
1248
|
+
Statement = local.lambda_policy_document_statements
|
|
860
1249
|
})
|
|
861
1250
|
}
|
|
862
1251
|
|
|
1252
|
+
locals {
|
|
1253
|
+
# Grant read access to the runtime-config AppConfig application when wired
|
|
1254
|
+
lambda_policy_statements = concat(var.appconfig_application_arn != null ? [
|
|
1255
|
+
{
|
|
1256
|
+
Effect = "Allow"
|
|
1257
|
+
Action = [
|
|
1258
|
+
"appconfig:StartConfigurationSession",
|
|
1259
|
+
"appconfig:GetLatestConfiguration"
|
|
1260
|
+
]
|
|
1261
|
+
Resource = ["\${var.appconfig_application_arn}/*"]
|
|
1262
|
+
}
|
|
1263
|
+
] : [], var.additional_iam_policy_statements)
|
|
1264
|
+
|
|
1265
|
+
# IAM rejects an empty statement list, so fall back to a no-op deny
|
|
1266
|
+
lambda_policy_document_statements = length(local.lambda_policy_statements) > 0 ? local.lambda_policy_statements : [
|
|
1267
|
+
{
|
|
1268
|
+
Effect = "Deny"
|
|
1269
|
+
Action = ["appconfig:GetLatestConfiguration"]
|
|
1270
|
+
Resource = ["arn:aws:appconfig:\${data.aws_region.current.region}:\${data.aws_caller_identity.current.account_id}:application/none"]
|
|
1271
|
+
}
|
|
1272
|
+
]
|
|
1273
|
+
}
|
|
1274
|
+
|
|
863
1275
|
# CloudWatch Log Group for Lambda
|
|
864
1276
|
resource "aws_cloudwatch_log_group" "lambda_logs" {
|
|
865
1277
|
#checkov:skip=CKV_AWS_158:Using default CloudWatch log encryption
|
|
866
1278
|
#checkov:skip=CKV_AWS_338:Log retention set to forever
|
|
867
1279
|
#checkov:skip=CKV_AWS_66:Log retention set to forever
|
|
868
|
-
|
|
869
|
-
|
|
1280
|
+
for_each = local.operations
|
|
1281
|
+
|
|
1282
|
+
name = "/aws/lambda/\${local.function_name[each.key]}"
|
|
1283
|
+
tags = var.tags
|
|
870
1284
|
}
|
|
871
1285
|
|
|
872
1286
|
|
|
@@ -883,7 +1297,7 @@ resource "aws_lambda_function" "authorizer_lambda" {
|
|
|
883
1297
|
function_name = "TestApiAuthorizer-\${random_string.suffix.result}"
|
|
884
1298
|
role = aws_iam_role.authorizer_execution_role.arn
|
|
885
1299
|
handler = "index.handler"
|
|
886
|
-
runtime = "
|
|
1300
|
+
runtime = "nodejs24.x"
|
|
887
1301
|
timeout = 10
|
|
888
1302
|
memory_size = 128
|
|
889
1303
|
|
|
@@ -963,58 +1377,62 @@ resource "aws_lambda_permission" "authorizer_invoke" {
|
|
|
963
1377
|
source_arn = "\${module.rest_api.api_execution_arn}/authorizers/\${aws_api_gateway_authorizer.custom_authorizer.id}"
|
|
964
1378
|
}
|
|
965
1379
|
|
|
966
|
-
#
|
|
967
|
-
resource "
|
|
968
|
-
rest_api_id = module.rest_api.api_id
|
|
969
|
-
parent_id = module.rest_api.api_root_resource_id
|
|
970
|
-
path_part = "{proxy+}"
|
|
971
|
-
}
|
|
972
|
-
|
|
973
|
-
# Lambda integration for REST API
|
|
974
|
-
resource "aws_api_gateway_integration" "lambda_integration" {
|
|
975
|
-
rest_api_id = module.rest_api.api_id
|
|
976
|
-
resource_id = aws_api_gateway_resource.proxy_resource.id
|
|
977
|
-
http_method = aws_api_gateway_method.proxy_method.http_method
|
|
978
|
-
|
|
979
|
-
integration_http_method = "POST"
|
|
980
|
-
type = "AWS_PROXY"
|
|
981
|
-
uri = aws_lambda_function.api_lambda.invoke_arn
|
|
982
|
-
|
|
983
|
-
depends_on = [aws_lambda_function.api_lambda]
|
|
984
|
-
}
|
|
985
|
-
|
|
986
|
-
# Method for proxy integration
|
|
987
|
-
resource "aws_api_gateway_method" "proxy_method" {
|
|
1380
|
+
# Method per operation
|
|
1381
|
+
resource "aws_api_gateway_method" "operation_methods" {
|
|
988
1382
|
#checkov:skip=CKV2_AWS_53:Request validation not required for proxy integration as Lambda handles validation
|
|
1383
|
+
for_each = local.operations
|
|
1384
|
+
|
|
989
1385
|
rest_api_id = module.rest_api.api_id
|
|
990
|
-
resource_id =
|
|
991
|
-
http_method =
|
|
1386
|
+
resource_id = local.operation_resource_id[each.key]
|
|
1387
|
+
http_method = upper(each.value.method)
|
|
992
1388
|
|
|
993
1389
|
authorization = "CUSTOM"
|
|
994
1390
|
authorizer_id = aws_api_gateway_authorizer.custom_authorizer.id
|
|
995
1391
|
|
|
1392
|
+
# Path parameters must be declared on the method
|
|
996
1393
|
request_parameters = {
|
|
997
|
-
|
|
1394
|
+
for segment in local.operation_segments[each.key] :
|
|
1395
|
+
"method.request.path.\${trimsuffix(trimprefix(segment, "{"), "}")}" => true
|
|
1396
|
+
if startswith(segment, "{")
|
|
998
1397
|
}
|
|
999
1398
|
|
|
1000
1399
|
depends_on = [aws_api_gateway_authorizer.custom_authorizer]
|
|
1001
1400
|
}
|
|
1002
1401
|
|
|
1003
|
-
#
|
|
1402
|
+
# Lambda integration per operation
|
|
1403
|
+
resource "aws_api_gateway_integration" "lambda_integration" {
|
|
1404
|
+
for_each = local.operations
|
|
1405
|
+
|
|
1406
|
+
rest_api_id = module.rest_api.api_id
|
|
1407
|
+
resource_id = local.operation_resource_id[each.key]
|
|
1408
|
+
http_method = aws_api_gateway_method.operation_methods[each.key].http_method
|
|
1409
|
+
|
|
1410
|
+
integration_http_method = "POST"
|
|
1411
|
+
type = "AWS_PROXY"
|
|
1412
|
+
uri = aws_lambda_function.api_lambda[each.key].invoke_arn
|
|
1413
|
+
|
|
1414
|
+
depends_on = [aws_lambda_function.api_lambda]
|
|
1415
|
+
}
|
|
1416
|
+
|
|
1417
|
+
# OPTIONS method for CORS preflight, on every resource an operation is served from
|
|
1004
1418
|
resource "aws_api_gateway_method" "options_method" {
|
|
1005
1419
|
#checkov:skip=CKV2_AWS_70:OPTIONS method must be unauthenticated for CORS preflight requests
|
|
1006
1420
|
#checkov:skip=CKV2_AWS_53:Request validation not required for OPTIONS CORS preflight method
|
|
1421
|
+
for_each = local.resource_ids
|
|
1422
|
+
|
|
1007
1423
|
rest_api_id = module.rest_api.api_id
|
|
1008
|
-
resource_id =
|
|
1424
|
+
resource_id = each.value
|
|
1009
1425
|
http_method = "OPTIONS"
|
|
1010
1426
|
authorization = "NONE"
|
|
1011
1427
|
}
|
|
1012
1428
|
|
|
1013
|
-
# CORS integration for OPTIONS
|
|
1429
|
+
# CORS integration for OPTIONS methods
|
|
1014
1430
|
resource "aws_api_gateway_integration" "options_integration" {
|
|
1431
|
+
for_each = local.resource_ids
|
|
1432
|
+
|
|
1015
1433
|
rest_api_id = module.rest_api.api_id
|
|
1016
|
-
resource_id =
|
|
1017
|
-
http_method = aws_api_gateway_method.options_method.http_method
|
|
1434
|
+
resource_id = each.value
|
|
1435
|
+
http_method = aws_api_gateway_method.options_method[each.key].http_method
|
|
1018
1436
|
|
|
1019
1437
|
type = "MOCK"
|
|
1020
1438
|
request_templates = {
|
|
@@ -1022,11 +1440,13 @@ resource "aws_api_gateway_integration" "options_integration" {
|
|
|
1022
1440
|
}
|
|
1023
1441
|
}
|
|
1024
1442
|
|
|
1025
|
-
# OPTIONS method
|
|
1443
|
+
# OPTIONS method responses
|
|
1026
1444
|
resource "aws_api_gateway_method_response" "options_response" {
|
|
1445
|
+
for_each = local.resource_ids
|
|
1446
|
+
|
|
1027
1447
|
rest_api_id = module.rest_api.api_id
|
|
1028
|
-
resource_id =
|
|
1029
|
-
http_method = aws_api_gateway_method.options_method.http_method
|
|
1448
|
+
resource_id = each.value
|
|
1449
|
+
http_method = aws_api_gateway_method.options_method[each.key].http_method
|
|
1030
1450
|
status_code = "204"
|
|
1031
1451
|
|
|
1032
1452
|
response_parameters = {
|
|
@@ -1036,18 +1456,22 @@ resource "aws_api_gateway_method_response" "options_response" {
|
|
|
1036
1456
|
}
|
|
1037
1457
|
}
|
|
1038
1458
|
|
|
1039
|
-
# OPTIONS integration
|
|
1459
|
+
# OPTIONS integration responses
|
|
1040
1460
|
resource "aws_api_gateway_integration_response" "options_integration_response" {
|
|
1461
|
+
for_each = local.resource_ids
|
|
1462
|
+
|
|
1041
1463
|
rest_api_id = module.rest_api.api_id
|
|
1042
|
-
resource_id =
|
|
1043
|
-
http_method = aws_api_gateway_method.options_method.http_method
|
|
1044
|
-
status_code = aws_api_gateway_method_response.options_response.status_code
|
|
1464
|
+
resource_id = each.value
|
|
1465
|
+
http_method = aws_api_gateway_method.options_method[each.key].http_method
|
|
1466
|
+
status_code = aws_api_gateway_method_response.options_response[each.key].status_code
|
|
1045
1467
|
|
|
1046
1468
|
response_parameters = {
|
|
1047
1469
|
"method.response.header.Access-Control-Allow-Headers" = "'\${join(",", var.cors_allow_headers)}'"
|
|
1048
1470
|
"method.response.header.Access-Control-Allow-Methods" = "'\${join(",", var.cors_allow_methods)}'"
|
|
1049
1471
|
"method.response.header.Access-Control-Allow-Origin" = "'\${join(",", var.cors_allow_origins)}'"
|
|
1050
1472
|
}
|
|
1473
|
+
|
|
1474
|
+
depends_on = [aws_api_gateway_integration.options_integration]
|
|
1051
1475
|
}
|
|
1052
1476
|
|
|
1053
1477
|
# API Gateway deployment
|
|
@@ -1055,13 +1479,28 @@ resource "aws_api_gateway_deployment" "api_deployment" {
|
|
|
1055
1479
|
rest_api_id = module.rest_api.api_id
|
|
1056
1480
|
|
|
1057
1481
|
triggers = {
|
|
1058
|
-
redeployment = sha1(jsonencode(
|
|
1059
|
-
aws_api_gateway_resource.
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1482
|
+
redeployment = sha1(jsonencode(concat(
|
|
1483
|
+
[for r in aws_api_gateway_resource.path_depth_0 : r.id],
|
|
1484
|
+
[for r in aws_api_gateway_resource.path_depth_1 : r.id],
|
|
1485
|
+
[for r in aws_api_gateway_resource.path_depth_2 : r.id],
|
|
1486
|
+
[for r in aws_api_gateway_resource.path_depth_3 : r.id],
|
|
1487
|
+
[for r in aws_api_gateway_resource.path_depth_4 : r.id],
|
|
1488
|
+
[for r in aws_api_gateway_resource.path_depth_5 : r.id],
|
|
1489
|
+
[for r in aws_api_gateway_resource.path_depth_6 : r.id],
|
|
1490
|
+
[for r in aws_api_gateway_resource.path_depth_7 : r.id],
|
|
1491
|
+
[for r in aws_api_gateway_resource.path_depth_8 : r.id],
|
|
1492
|
+
[for r in aws_api_gateway_resource.path_depth_9 : r.id],
|
|
1493
|
+
[for r in aws_api_gateway_resource.path_depth_10 : r.id],
|
|
1494
|
+
[for r in aws_api_gateway_resource.path_depth_11 : r.id],
|
|
1495
|
+
[for r in aws_api_gateway_resource.path_depth_12 : r.id],
|
|
1496
|
+
[for r in aws_api_gateway_resource.path_depth_13 : r.id],
|
|
1497
|
+
[for r in aws_api_gateway_resource.path_depth_14 : r.id],
|
|
1498
|
+
[for r in aws_api_gateway_resource.path_depth_15 : r.id],
|
|
1499
|
+
[for m in aws_api_gateway_method.operation_methods : m.id],
|
|
1500
|
+
[for i in aws_api_gateway_integration.lambda_integration : i.id],
|
|
1501
|
+
[for m in aws_api_gateway_method.options_method : m.id],
|
|
1502
|
+
[for i in aws_api_gateway_integration.options_integration : i.id],
|
|
1503
|
+
)))
|
|
1065
1504
|
}
|
|
1066
1505
|
|
|
1067
1506
|
lifecycle {
|
|
@@ -1069,7 +1508,7 @@ resource "aws_api_gateway_deployment" "api_deployment" {
|
|
|
1069
1508
|
}
|
|
1070
1509
|
|
|
1071
1510
|
depends_on = [
|
|
1072
|
-
aws_api_gateway_method.
|
|
1511
|
+
aws_api_gateway_method.operation_methods,
|
|
1073
1512
|
aws_api_gateway_integration.lambda_integration,
|
|
1074
1513
|
aws_api_gateway_method.options_method,
|
|
1075
1514
|
aws_api_gateway_integration.options_integration,
|
|
@@ -1079,11 +1518,63 @@ resource "aws_api_gateway_deployment" "api_deployment" {
|
|
|
1079
1518
|
]
|
|
1080
1519
|
}
|
|
1081
1520
|
|
|
1521
|
+
# KMS key for encrypting access logs at rest
|
|
1522
|
+
resource "aws_kms_key" "access_logs" {
|
|
1523
|
+
description = "TestApi API access log encryption"
|
|
1524
|
+
deletion_window_in_days = 7
|
|
1525
|
+
enable_key_rotation = true
|
|
1526
|
+
|
|
1527
|
+
policy = jsonencode({
|
|
1528
|
+
Version = "2012-10-17"
|
|
1529
|
+
Statement = [
|
|
1530
|
+
{
|
|
1531
|
+
Sid = "Enable IAM User Permissions"
|
|
1532
|
+
Effect = "Allow"
|
|
1533
|
+
Principal = { AWS = "arn:aws:iam::\${data.aws_caller_identity.current.account_id}:root" }
|
|
1534
|
+
Action = "kms:*"
|
|
1535
|
+
Resource = "*"
|
|
1536
|
+
},
|
|
1537
|
+
{
|
|
1538
|
+
Sid = "Allow CloudWatch Logs"
|
|
1539
|
+
Effect = "Allow"
|
|
1540
|
+
Principal = { Service = "logs.\${data.aws_region.current.region}.amazonaws.com" }
|
|
1541
|
+
Action = [
|
|
1542
|
+
"kms:Encrypt",
|
|
1543
|
+
"kms:Decrypt",
|
|
1544
|
+
"kms:ReEncrypt*",
|
|
1545
|
+
"kms:GenerateDataKey*",
|
|
1546
|
+
"kms:DescribeKey"
|
|
1547
|
+
]
|
|
1548
|
+
Resource = "*"
|
|
1549
|
+
Condition = {
|
|
1550
|
+
ArnEquals = {
|
|
1551
|
+
"kms:EncryptionContext:aws:logs:arn" = "arn:aws:logs:\${data.aws_region.current.region}:\${data.aws_caller_identity.current.account_id}:log-group:/aws/apigateway/test-api-\${random_string.suffix.result}/access"
|
|
1552
|
+
}
|
|
1553
|
+
}
|
|
1554
|
+
}
|
|
1555
|
+
]
|
|
1556
|
+
})
|
|
1557
|
+
|
|
1558
|
+
tags = var.tags
|
|
1559
|
+
}
|
|
1560
|
+
|
|
1561
|
+
resource "aws_kms_alias" "access_logs" {
|
|
1562
|
+
name = "alias/test-api-\${random_string.suffix.result}-access-logs"
|
|
1563
|
+
target_key_id = aws_kms_key.access_logs.key_id
|
|
1564
|
+
}
|
|
1565
|
+
|
|
1566
|
+
# Access logs for the API Gateway stage
|
|
1567
|
+
resource "aws_cloudwatch_log_group" "access_logs" {
|
|
1568
|
+
name = "/aws/apigateway/test-api-\${random_string.suffix.result}/access"
|
|
1569
|
+
retention_in_days = 365
|
|
1570
|
+
kms_key_id = aws_kms_key.access_logs.arn
|
|
1571
|
+
tags = var.tags
|
|
1572
|
+
}
|
|
1573
|
+
|
|
1082
1574
|
# API Gateway stage
|
|
1083
1575
|
resource "aws_api_gateway_stage" "api_stage" {
|
|
1084
1576
|
#checkov:skip=CKV_AWS_120:API Gateway caching not required for this use case
|
|
1085
|
-
#checkov:skip=
|
|
1086
|
-
#checkov:skip=CKV2_AWS_4:API Gateway logging level not applicable as access logging is disabled
|
|
1577
|
+
#checkov:skip=CKV2_AWS_4:Access logging is enabled below; verbose execution logging is intentionally not enabled
|
|
1087
1578
|
#checkov:skip=CKV2_AWS_51:Client certificate authentication not required for this use case
|
|
1088
1579
|
#checkov:skip=CKV2_AWS_77:WAFv2 Web ACL is attached via aws_wafv2_web_acl_association when var.enable_waf is true (default) and includes AWSManagedRulesKnownBadInputsRuleSet for Log4j protection; Checkov does not track the association across modules
|
|
1089
1580
|
deployment_id = aws_api_gateway_deployment.api_deployment.id
|
|
@@ -1091,9 +1582,39 @@ resource "aws_api_gateway_stage" "api_stage" {
|
|
|
1091
1582
|
stage_name = "prod"
|
|
1092
1583
|
xray_tracing_enabled = true
|
|
1093
1584
|
|
|
1585
|
+
access_log_settings {
|
|
1586
|
+
destination_arn = aws_cloudwatch_log_group.access_logs.arn
|
|
1587
|
+
format = jsonencode({
|
|
1588
|
+
requestId = "$context.requestId"
|
|
1589
|
+
ip = "$context.identity.sourceIp"
|
|
1590
|
+
caller = "$context.identity.caller"
|
|
1591
|
+
user = "$context.identity.user"
|
|
1592
|
+
requestTime = "$context.requestTime"
|
|
1593
|
+
httpMethod = "$context.httpMethod"
|
|
1594
|
+
resourcePath = "$context.resourcePath"
|
|
1595
|
+
status = "$context.status"
|
|
1596
|
+
protocol = "$context.protocol"
|
|
1597
|
+
responseLength = "$context.responseLength"
|
|
1598
|
+
})
|
|
1599
|
+
}
|
|
1600
|
+
|
|
1094
1601
|
tags = var.tags
|
|
1095
1602
|
|
|
1096
|
-
|
|
1603
|
+
# Ensure the account-level role is configured before the stage is created
|
|
1604
|
+
depends_on = [aws_api_gateway_deployment.api_deployment, module.account]
|
|
1605
|
+
}
|
|
1606
|
+
|
|
1607
|
+
# Default throttling applied to all resource paths and methods
|
|
1608
|
+
resource "aws_api_gateway_method_settings" "throttling" {
|
|
1609
|
+
#checkov:skip=CKV_AWS_225:API Gateway caching not required for this use case
|
|
1610
|
+
rest_api_id = module.rest_api.api_id
|
|
1611
|
+
stage_name = aws_api_gateway_stage.api_stage.stage_name
|
|
1612
|
+
method_path = "*/*"
|
|
1613
|
+
|
|
1614
|
+
settings {
|
|
1615
|
+
throttling_rate_limit = 10000
|
|
1616
|
+
throttling_burst_limit = 5000
|
|
1617
|
+
}
|
|
1097
1618
|
}
|
|
1098
1619
|
|
|
1099
1620
|
# API Gateway Resource Policy
|
|
@@ -1116,11 +1637,13 @@ resource "aws_api_gateway_rest_api_policy" "api_policy" {
|
|
|
1116
1637
|
|
|
1117
1638
|
# Lambda permission for API Gateway to invoke the function
|
|
1118
1639
|
resource "aws_lambda_permission" "api_gateway_invoke" {
|
|
1640
|
+
for_each = local.operations
|
|
1641
|
+
|
|
1119
1642
|
statement_id = "AllowExecutionFromAPIGateway"
|
|
1120
1643
|
action = "lambda:InvokeFunction"
|
|
1121
|
-
function_name = aws_lambda_function.api_lambda.function_name
|
|
1644
|
+
function_name = aws_lambda_function.api_lambda[each.key].function_name
|
|
1122
1645
|
principal = "apigateway.amazonaws.com"
|
|
1123
|
-
source_arn = "\${module.rest_api.api_execution_arn}
|
|
1646
|
+
source_arn = "\${module.rest_api.api_execution_arn}/*/\${local.permission_source_suffix[each.key]}"
|
|
1124
1647
|
|
|
1125
1648
|
depends_on = [module.rest_api, aws_lambda_function.api_lambda]
|
|
1126
1649
|
}
|
|
@@ -1132,7 +1655,7 @@ module "add_url_to_runtime_config" {
|
|
|
1132
1655
|
|
|
1133
1656
|
namespace = "connection"
|
|
1134
1657
|
key = "apis"
|
|
1135
|
-
value = { "TestApi" = aws_api_gateway_stage.api_stage.invoke_url }
|
|
1658
|
+
value = { "TestApi" = "\${aws_api_gateway_stage.api_stage.invoke_url}/" }
|
|
1136
1659
|
|
|
1137
1660
|
depends_on = [aws_api_gateway_stage.api_stage]
|
|
1138
1661
|
}
|
|
@@ -1185,78 +1708,83 @@ output "stage_id" {
|
|
|
1185
1708
|
value = aws_api_gateway_stage.api_stage.id
|
|
1186
1709
|
}
|
|
1187
1710
|
|
|
1188
|
-
# Lambda Function Outputs
|
|
1189
|
-
output "
|
|
1190
|
-
description = "
|
|
1191
|
-
value =
|
|
1711
|
+
# Lambda Function Outputs, keyed by operation name
|
|
1712
|
+
output "operations" {
|
|
1713
|
+
description = "Names of the API operations, each with its own Lambda function"
|
|
1714
|
+
value = keys(local.operations)
|
|
1715
|
+
}
|
|
1716
|
+
|
|
1717
|
+
output "lambda_function_names" {
|
|
1718
|
+
description = "Name of each operation's Lambda function, keyed by operation name"
|
|
1719
|
+
value = { for op, fn in aws_lambda_function.api_lambda : op => fn.function_name }
|
|
1192
1720
|
}
|
|
1193
1721
|
|
|
1194
|
-
output "
|
|
1195
|
-
description = "ARN of
|
|
1196
|
-
value = aws_lambda_function.api_lambda.arn
|
|
1722
|
+
output "lambda_function_arns" {
|
|
1723
|
+
description = "ARN of each operation's Lambda function, keyed by operation name"
|
|
1724
|
+
value = { for op, fn in aws_lambda_function.api_lambda : op => fn.arn }
|
|
1197
1725
|
}
|
|
1198
1726
|
|
|
1199
|
-
output "
|
|
1200
|
-
description = "Invoke ARN of
|
|
1201
|
-
value = aws_lambda_function.api_lambda.invoke_arn
|
|
1727
|
+
output "lambda_invoke_arns" {
|
|
1728
|
+
description = "Invoke ARN of each operation's Lambda function, keyed by operation name"
|
|
1729
|
+
value = { for op, fn in aws_lambda_function.api_lambda : op => fn.invoke_arn }
|
|
1202
1730
|
}
|
|
1203
1731
|
|
|
1204
|
-
output "
|
|
1205
|
-
description = "Qualified ARN of
|
|
1206
|
-
value = aws_lambda_function.api_lambda.qualified_arn
|
|
1732
|
+
output "lambda_qualified_arns" {
|
|
1733
|
+
description = "Qualified ARN of each operation's Lambda function, keyed by operation name"
|
|
1734
|
+
value = { for op, fn in aws_lambda_function.api_lambda : op => fn.qualified_arn }
|
|
1207
1735
|
}
|
|
1208
1736
|
|
|
1209
|
-
output "
|
|
1210
|
-
description = "Version of
|
|
1211
|
-
value = aws_lambda_function.api_lambda.version
|
|
1737
|
+
output "lambda_versions" {
|
|
1738
|
+
description = "Version of each operation's Lambda function, keyed by operation name"
|
|
1739
|
+
value = { for op, fn in aws_lambda_function.api_lambda : op => fn.version }
|
|
1212
1740
|
}
|
|
1213
1741
|
|
|
1214
1742
|
output "lambda_source_code_hash" {
|
|
1215
|
-
description = "Base64-encoded SHA256 hash of the Lambda deployment package"
|
|
1216
|
-
value =
|
|
1743
|
+
description = "Base64-encoded SHA256 hash of the Lambda deployment package, shared by every operation"
|
|
1744
|
+
value = data.archive_file.lambda_zip.output_base64sha256
|
|
1217
1745
|
}
|
|
1218
1746
|
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1747
|
+
# IAM Role Outputs, keyed by operation name
|
|
1748
|
+
output "lambda_execution_role_arns" {
|
|
1749
|
+
description = "ARN of each operation's Lambda execution role, keyed by operation name"
|
|
1750
|
+
value = { for op, role in aws_iam_role.lambda_execution_role : op => role.arn }
|
|
1222
1751
|
}
|
|
1223
1752
|
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
value = aws_iam_role.lambda_execution_role.arn
|
|
1753
|
+
output "lambda_execution_role_names" {
|
|
1754
|
+
description = "Name of each operation's Lambda execution role, keyed by operation name. Attach additional policies to a specific operation's role by name."
|
|
1755
|
+
value = { for op, role in aws_iam_role.lambda_execution_role : op => role.name }
|
|
1228
1756
|
}
|
|
1229
1757
|
|
|
1230
|
-
output "
|
|
1231
|
-
description = "
|
|
1232
|
-
value =
|
|
1758
|
+
output "security_group_id" {
|
|
1759
|
+
description = "Security group ID shared by the API Lambda functions, for use in ingress rules on resources they must reach (e.g. a database). Null unless enable_vpc is true."
|
|
1760
|
+
value = var.enable_vpc ? aws_security_group.api_lambda[0].id : null
|
|
1233
1761
|
}
|
|
1234
1762
|
|
|
1235
|
-
# Integration Outputs
|
|
1236
|
-
output "
|
|
1237
|
-
description = "ID of
|
|
1238
|
-
value = aws_api_gateway_integration.lambda_integration.id
|
|
1763
|
+
# Integration Outputs, keyed by operation name
|
|
1764
|
+
output "integration_ids" {
|
|
1765
|
+
description = "ID of each operation's Lambda integration, keyed by operation name"
|
|
1766
|
+
value = { for op, i in aws_api_gateway_integration.lambda_integration : op => i.id }
|
|
1239
1767
|
}
|
|
1240
1768
|
|
|
1241
|
-
output "
|
|
1242
|
-
description = "ID of
|
|
1243
|
-
value =
|
|
1769
|
+
output "method_ids" {
|
|
1770
|
+
description = "ID of each operation's API Gateway method, keyed by operation name"
|
|
1771
|
+
value = { for op, m in aws_api_gateway_method.operation_methods : op => m.id }
|
|
1244
1772
|
}
|
|
1245
1773
|
|
|
1246
|
-
output "
|
|
1247
|
-
description = "ID of
|
|
1248
|
-
value =
|
|
1774
|
+
output "resource_ids" {
|
|
1775
|
+
description = "ID of each API Gateway resource, keyed by its path"
|
|
1776
|
+
value = local.resource_ids
|
|
1249
1777
|
}
|
|
1250
1778
|
|
|
1251
|
-
# CloudWatch Log Groups
|
|
1252
|
-
output "
|
|
1253
|
-
description = "Name of
|
|
1254
|
-
value = aws_cloudwatch_log_group.lambda_logs.name
|
|
1779
|
+
# CloudWatch Log Groups, keyed by operation name
|
|
1780
|
+
output "lambda_log_group_names" {
|
|
1781
|
+
description = "Name of each operation's Lambda CloudWatch log group, keyed by operation name"
|
|
1782
|
+
value = { for op, lg in aws_cloudwatch_log_group.lambda_logs : op => lg.name }
|
|
1255
1783
|
}
|
|
1256
1784
|
|
|
1257
|
-
output "
|
|
1258
|
-
description = "ARN of
|
|
1259
|
-
value = aws_cloudwatch_log_group.lambda_logs.arn
|
|
1785
|
+
output "lambda_log_group_arns" {
|
|
1786
|
+
description = "ARN of each operation's Lambda CloudWatch log group, keyed by operation name"
|
|
1787
|
+
value = { for op, lg in aws_cloudwatch_log_group.lambda_logs : op => lg.arn }
|
|
1260
1788
|
}
|
|
1261
1789
|
"
|
|
1262
1790
|
`;
|
|
@@ -1296,25 +1824,46 @@ exports[`tsSmithyApiGenerator > should generate smithy ts api with default optio
|
|
|
1296
1824
|
"apiName": "test-api",
|
|
1297
1825
|
"auth": "custom",
|
|
1298
1826
|
"modelProject": "@proj/test-api-model",
|
|
1827
|
+
"iac": "cdk",
|
|
1299
1828
|
"ports": [3001]
|
|
1300
1829
|
},
|
|
1301
1830
|
"targets": {
|
|
1831
|
+
"assemble": {
|
|
1832
|
+
"dependsOn": ["compile", "bundle"]
|
|
1833
|
+
},
|
|
1302
1834
|
"build": {
|
|
1303
1835
|
"dependsOn": ["lint", "compile", "test", "bundle"]
|
|
1304
1836
|
},
|
|
1305
1837
|
"compile": {
|
|
1306
1838
|
"executor": "nx:run-commands",
|
|
1839
|
+
"dependsOn": ["copy-ssdk"],
|
|
1307
1840
|
"outputs": ["{workspaceRoot}/dist/{projectRoot}/tsc"],
|
|
1308
1841
|
"options": {
|
|
1309
1842
|
"command": "tsc --build tsconfig.lib.json",
|
|
1310
1843
|
"cwd": "{projectRoot}"
|
|
1844
|
+
}
|
|
1845
|
+
},
|
|
1846
|
+
"format": {
|
|
1847
|
+
"executor": "nx:run-commands",
|
|
1848
|
+
"cache": true,
|
|
1849
|
+
"inputs": ["biome"],
|
|
1850
|
+
"options": {
|
|
1851
|
+
"command": "biome format {projectRoot}"
|
|
1311
1852
|
},
|
|
1312
|
-
"
|
|
1853
|
+
"configurations": {
|
|
1854
|
+
"fix": {
|
|
1855
|
+
"command": "biome format --write {projectRoot}"
|
|
1856
|
+
},
|
|
1857
|
+
"skip-lint": {
|
|
1858
|
+
"command": "node -e \\"\\""
|
|
1859
|
+
}
|
|
1860
|
+
}
|
|
1313
1861
|
},
|
|
1314
1862
|
"lint": {
|
|
1315
1863
|
"executor": "nx:run-commands",
|
|
1316
1864
|
"cache": true,
|
|
1317
1865
|
"inputs": ["biome"],
|
|
1866
|
+
"dependsOn": ["format"],
|
|
1318
1867
|
"options": {
|
|
1319
1868
|
"command": "biome lint {projectRoot}"
|
|
1320
1869
|
},
|
|
@@ -1327,22 +1876,16 @@ exports[`tsSmithyApiGenerator > should generate smithy ts api with default optio
|
|
|
1327
1876
|
}
|
|
1328
1877
|
}
|
|
1329
1878
|
},
|
|
1330
|
-
"test": {
|
|
1331
|
-
"executor": "@nx/vitest:test",
|
|
1332
|
-
"outputs": ["{options.reportsDirectory}"],
|
|
1333
|
-
"options": {
|
|
1334
|
-
"reportsDirectory": "{workspaceRoot}/coverage/{projectRoot}"
|
|
1335
|
-
}
|
|
1336
|
-
},
|
|
1337
1879
|
"bundle": {
|
|
1880
|
+
"executor": "nx:run-commands",
|
|
1881
|
+
"dependsOn": ["compile"],
|
|
1338
1882
|
"cache": true,
|
|
1883
|
+
"inputs": ["default"],
|
|
1339
1884
|
"outputs": ["{workspaceRoot}/dist/{projectRoot}/bundle"],
|
|
1340
|
-
"executor": "nx:run-commands",
|
|
1341
1885
|
"options": {
|
|
1342
1886
|
"command": "rolldown -c rolldown.config.ts",
|
|
1343
1887
|
"cwd": "{projectRoot}"
|
|
1344
|
-
}
|
|
1345
|
-
"dependsOn": ["compile"]
|
|
1888
|
+
}
|
|
1346
1889
|
},
|
|
1347
1890
|
"copy-ssdk": {
|
|
1348
1891
|
"cache": true,
|
|
@@ -1365,31 +1908,31 @@ exports[`tsSmithyApiGenerator > should generate smithy ts api with default optio
|
|
|
1365
1908
|
},
|
|
1366
1909
|
"watch-copy-ssdk": {
|
|
1367
1910
|
"executor": "nx:run-commands",
|
|
1911
|
+
"continuous": true,
|
|
1368
1912
|
"options": {
|
|
1369
|
-
"command": "nx watch --projects=@proj/test-api-model --
|
|
1370
|
-
}
|
|
1371
|
-
"continuous": true
|
|
1913
|
+
"command": "nx watch --projects=@proj/test-api-model --includeDependencies -- nx run @proj/test-api:copy-ssdk"
|
|
1914
|
+
}
|
|
1372
1915
|
},
|
|
1373
1916
|
"serve": {
|
|
1374
1917
|
"executor": "nx:run-commands",
|
|
1918
|
+
"dependsOn": ["copy-ssdk", "watch-copy-ssdk"],
|
|
1919
|
+
"continuous": true,
|
|
1375
1920
|
"options": {
|
|
1376
1921
|
"command": "tsx --watch src/local-server.ts",
|
|
1377
1922
|
"cwd": "{projectRoot}"
|
|
1378
|
-
}
|
|
1379
|
-
"continuous": true,
|
|
1380
|
-
"dependsOn": ["copy-ssdk", "watch-copy-ssdk"]
|
|
1923
|
+
}
|
|
1381
1924
|
},
|
|
1382
|
-
"
|
|
1925
|
+
"dev": {
|
|
1383
1926
|
"executor": "nx:run-commands",
|
|
1927
|
+
"dependsOn": ["copy-ssdk", "watch-copy-ssdk"],
|
|
1928
|
+
"continuous": true,
|
|
1384
1929
|
"options": {
|
|
1385
1930
|
"command": "tsx --watch src/local-server.ts",
|
|
1386
1931
|
"cwd": "{projectRoot}",
|
|
1387
1932
|
"env": {
|
|
1388
|
-
"
|
|
1933
|
+
"LOCAL_DEV": "true"
|
|
1389
1934
|
}
|
|
1390
|
-
}
|
|
1391
|
-
"continuous": true,
|
|
1392
|
-
"dependsOn": ["copy-ssdk", "watch-copy-ssdk"]
|
|
1935
|
+
}
|
|
1393
1936
|
}
|
|
1394
1937
|
}
|
|
1395
1938
|
}
|
|
@@ -1427,7 +1970,7 @@ exports[`tsSmithyApiGenerator > should generate smithy ts api with default optio
|
|
|
1427
1970
|
"import {
|
|
1428
1971
|
convertEvent,
|
|
1429
1972
|
convertVersion1Response,
|
|
1430
|
-
} from '@
|
|
1973
|
+
} from '@smithy/server-apigateway';
|
|
1431
1974
|
import type { APIGatewayProxyEvent, APIGatewayProxyResult } from 'aws-lambda';
|
|
1432
1975
|
import middy from '@middy/core';
|
|
1433
1976
|
import { Tracer } from '@aws-lambda-powertools/tracer';
|
|
@@ -1492,7 +2035,7 @@ export const handler = middy<APIGatewayProxyEvent, APIGatewayProxyResult>()
|
|
|
1492
2035
|
|
|
1493
2036
|
exports[`tsSmithyApiGenerator > should generate smithy ts api with default options > local-server.ts 1`] = `
|
|
1494
2037
|
"import { IncomingMessage, ServerResponse, createServer } from 'http';
|
|
1495
|
-
import { convertRequest, writeResponse } from '@
|
|
2038
|
+
import { convertRequest, writeResponse } from '@smithy/server-node';
|
|
1496
2039
|
import { Logger } from '@aws-lambda-powertools/logger';
|
|
1497
2040
|
import { Metrics } from '@aws-lambda-powertools/metrics';
|
|
1498
2041
|
import { Tracer } from '@aws-lambda-powertools/tracer';
|
|
@@ -1543,22 +2086,46 @@ exports[`tsSmithyApiGenerator > should generate smithy ts api with default optio
|
|
|
1543
2086
|
"projectType": "library",
|
|
1544
2087
|
"metadata": {
|
|
1545
2088
|
"generator": "smithy#project",
|
|
2089
|
+
"smithyType": "service",
|
|
2090
|
+
"namespace": "proj",
|
|
1546
2091
|
"apiName": "test-api-model",
|
|
1547
2092
|
"backendProject": "@proj/test-api"
|
|
1548
2093
|
},
|
|
1549
2094
|
"targets": {
|
|
1550
2095
|
"build": {
|
|
1551
|
-
"dependsOn": ["compile"]
|
|
2096
|
+
"dependsOn": ["compile", "generate-ssdk"]
|
|
2097
|
+
},
|
|
2098
|
+
"assemble": {
|
|
2099
|
+
"dependsOn": ["compile", "generate-ssdk"]
|
|
1552
2100
|
},
|
|
1553
2101
|
"compile": {
|
|
1554
2102
|
"cache": true,
|
|
1555
|
-
"outputs": [
|
|
2103
|
+
"outputs": [
|
|
2104
|
+
"{workspaceRoot}/dist/{projectRoot}/smithy",
|
|
2105
|
+
"{workspaceRoot}/dist/{projectRoot}/build/openapi"
|
|
2106
|
+
],
|
|
1556
2107
|
"executor": "nx:run-commands",
|
|
1557
2108
|
"options": {
|
|
1558
2109
|
"commands": [
|
|
1559
2110
|
"rimraf dist/{projectRoot}/build",
|
|
2111
|
+
"rimraf dist/{projectRoot}/smithy",
|
|
1560
2112
|
"make-dir dist/{projectRoot}/build",
|
|
1561
|
-
"
|
|
2113
|
+
"npx -y mise@2026.8.14 exec smithy@1.73.0 -- smithy build -c {projectRoot}/smithy-build.json --output dist/{projectRoot}/smithy",
|
|
2114
|
+
"cpy \\"dist/{projectRoot}/smithy/source/openapi/*.openapi.json\\" dist/{projectRoot}/build/openapi --flat --rename=openapi.json"
|
|
2115
|
+
],
|
|
2116
|
+
"parallel": false,
|
|
2117
|
+
"cwd": "{workspaceRoot}"
|
|
2118
|
+
}
|
|
2119
|
+
},
|
|
2120
|
+
"generate-ssdk": {
|
|
2121
|
+
"cache": true,
|
|
2122
|
+
"outputs": ["{workspaceRoot}/dist/{projectRoot}/build/ssdk"],
|
|
2123
|
+
"executor": "nx:run-commands",
|
|
2124
|
+
"dependsOn": ["compile"],
|
|
2125
|
+
"options": {
|
|
2126
|
+
"commands": [
|
|
2127
|
+
"npm install --prefix dist/{projectRoot}/smithy/source/typescript-ssdk-codegen --include=dev --ignore-scripts --no-audit --no-fund",
|
|
2128
|
+
"rolldown -c {projectRoot}/ssdk.rolldown.config.mjs"
|
|
1562
2129
|
],
|
|
1563
2130
|
"parallel": false,
|
|
1564
2131
|
"cwd": "{workspaceRoot}"
|
|
@@ -1585,7 +2152,7 @@ exports[`tsSmithyApiGenerator > should handle kebab-case API names correctly > k
|
|
|
1585
2152
|
"import {
|
|
1586
2153
|
convertEvent,
|
|
1587
2154
|
convertVersion1Response,
|
|
1588
|
-
} from '@
|
|
2155
|
+
} from '@smithy/server-apigateway';
|
|
1589
2156
|
import type { APIGatewayProxyEvent, APIGatewayProxyResult } from 'aws-lambda';
|
|
1590
2157
|
import middy from '@middy/core';
|
|
1591
2158
|
import { Tracer } from '@aws-lambda-powertools/tracer';
|
|
@@ -1682,11 +2249,11 @@ terraform {
|
|
|
1682
2249
|
required_providers {
|
|
1683
2250
|
aws = {
|
|
1684
2251
|
source = "hashicorp/aws"
|
|
1685
|
-
version = "
|
|
2252
|
+
version = "6.62.0"
|
|
1686
2253
|
}
|
|
1687
2254
|
random = {
|
|
1688
2255
|
source = "hashicorp/random"
|
|
1689
|
-
version = "
|
|
2256
|
+
version = "3.9.0"
|
|
1690
2257
|
}
|
|
1691
2258
|
}
|
|
1692
2259
|
}
|
|
@@ -1756,8 +2323,6 @@ data "aws_caller_identity" "current" {}
|
|
|
1756
2323
|
|
|
1757
2324
|
# Resources
|
|
1758
2325
|
|
|
1759
|
-
# Note: CloudWatch logging removed due to account-level CloudWatch Logs role ARN requirement
|
|
1760
|
-
|
|
1761
2326
|
# REST API Gateway
|
|
1762
2327
|
resource "aws_api_gateway_rest_api" "rest_api" {
|
|
1763
2328
|
name = var.api_name
|
|
@@ -1774,10 +2339,8 @@ resource "aws_api_gateway_rest_api" "rest_api" {
|
|
|
1774
2339
|
tags = var.tags
|
|
1775
2340
|
}
|
|
1776
2341
|
|
|
1777
|
-
# Note: Deployment and
|
|
1778
|
-
# after all methods and integrations are defined
|
|
1779
|
-
|
|
1780
|
-
# Note: CloudWatch Log Group removed due to account-level CloudWatch Logs role ARN requirement
|
|
2342
|
+
# Note: Deployment, stage and access logging are created in the consuming module
|
|
2343
|
+
# (e.g., foo-api.tf) after all methods and integrations are defined
|
|
1781
2344
|
|
|
1782
2345
|
# Gateway Response for CORS (4XX errors)
|
|
1783
2346
|
resource "aws_api_gateway_gateway_response" "cors_4xx" {
|
|
@@ -1879,22 +2442,75 @@ resource "aws_wafv2_web_acl" "api_waf" {
|
|
|
1879
2442
|
}
|
|
1880
2443
|
}
|
|
1881
2444
|
|
|
2445
|
+
resource "random_id" "waf_log_suffix" {
|
|
2446
|
+
count = var.enable_waf ? 1 : 0
|
|
2447
|
+
byte_length = 4
|
|
2448
|
+
}
|
|
2449
|
+
|
|
2450
|
+
locals {
|
|
2451
|
+
waf_log_group_name = var.enable_waf ? "aws-waf-logs-\${var.api_name}-\${random_id.waf_log_suffix[0].hex}" : null
|
|
2452
|
+
}
|
|
2453
|
+
|
|
2454
|
+
# KMS key for encrypting WAF request logs at rest
|
|
2455
|
+
resource "aws_kms_key" "waf_logs" {
|
|
2456
|
+
count = var.enable_waf ? 1 : 0
|
|
2457
|
+
|
|
2458
|
+
description = "\${var.api_name} API WAF log encryption"
|
|
2459
|
+
deletion_window_in_days = 7
|
|
2460
|
+
enable_key_rotation = true
|
|
2461
|
+
|
|
2462
|
+
policy = jsonencode({
|
|
2463
|
+
Version = "2012-10-17"
|
|
2464
|
+
Statement = [
|
|
2465
|
+
{
|
|
2466
|
+
Sid = "Enable IAM User Permissions"
|
|
2467
|
+
Effect = "Allow"
|
|
2468
|
+
Principal = { AWS = "arn:aws:iam::\${data.aws_caller_identity.current.account_id}:root" }
|
|
2469
|
+
Action = "kms:*"
|
|
2470
|
+
Resource = "*"
|
|
2471
|
+
},
|
|
2472
|
+
{
|
|
2473
|
+
Sid = "Allow CloudWatch Logs"
|
|
2474
|
+
Effect = "Allow"
|
|
2475
|
+
Principal = { Service = "logs.\${data.aws_region.current.region}.amazonaws.com" }
|
|
2476
|
+
Action = [
|
|
2477
|
+
"kms:Encrypt",
|
|
2478
|
+
"kms:Decrypt",
|
|
2479
|
+
"kms:ReEncrypt*",
|
|
2480
|
+
"kms:GenerateDataKey*",
|
|
2481
|
+
"kms:DescribeKey"
|
|
2482
|
+
]
|
|
2483
|
+
Resource = "*"
|
|
2484
|
+
Condition = {
|
|
2485
|
+
ArnEquals = {
|
|
2486
|
+
"kms:EncryptionContext:aws:logs:arn" = "arn:aws:logs:\${data.aws_region.current.region}:\${data.aws_caller_identity.current.account_id}:log-group:\${local.waf_log_group_name}"
|
|
2487
|
+
}
|
|
2488
|
+
}
|
|
2489
|
+
}
|
|
2490
|
+
]
|
|
2491
|
+
})
|
|
2492
|
+
|
|
2493
|
+
tags = var.tags
|
|
2494
|
+
}
|
|
2495
|
+
|
|
2496
|
+
resource "aws_kms_alias" "waf_logs" {
|
|
2497
|
+
count = var.enable_waf ? 1 : 0
|
|
2498
|
+
|
|
2499
|
+
name = "alias/\${var.api_name}-\${random_id.waf_log_suffix[0].hex}-waf-logs"
|
|
2500
|
+
target_key_id = aws_kms_key.waf_logs[0].key_id
|
|
2501
|
+
}
|
|
2502
|
+
|
|
1882
2503
|
# CloudWatch Log Group for WAF request logs. Name must start with \`aws-waf-logs-\`.
|
|
1883
2504
|
resource "aws_cloudwatch_log_group" "api_waf_logs" {
|
|
1884
|
-
#checkov:skip=CKV_AWS_158:Using default CloudWatch log encryption
|
|
1885
2505
|
#checkov:skip=CKV_AWS_338:Log retention set to one month which is sufficient for WAF logs
|
|
1886
2506
|
count = var.enable_waf ? 1 : 0
|
|
1887
2507
|
|
|
1888
|
-
name =
|
|
2508
|
+
name = local.waf_log_group_name
|
|
1889
2509
|
retention_in_days = 30
|
|
2510
|
+
kms_key_id = aws_kms_key.waf_logs[0].arn
|
|
1890
2511
|
tags = var.tags
|
|
1891
2512
|
}
|
|
1892
2513
|
|
|
1893
|
-
resource "random_id" "waf_log_suffix" {
|
|
1894
|
-
count = var.enable_waf ? 1 : 0
|
|
1895
|
-
byte_length = 4
|
|
1896
|
-
}
|
|
1897
|
-
|
|
1898
2514
|
resource "aws_wafv2_web_acl_logging_configuration" "api_waf_logging" {
|
|
1899
2515
|
count = var.enable_waf ? 1 : 0
|
|
1900
2516
|
|
|
@@ -1935,16 +2551,22 @@ output "waf_web_acl_arn" {
|
|
|
1935
2551
|
value = var.enable_waf ? aws_wafv2_web_acl.api_waf[0].arn : null
|
|
1936
2552
|
}
|
|
1937
2553
|
|
|
1938
|
-
# Note: Stage and
|
|
1939
|
-
|
|
1940
|
-
# Note: CloudWatch log group outputs removed due to account-level CloudWatch Logs role ARN requirement",
|
|
2554
|
+
# Note: Stage, deployment and access log outputs are provided by the consuming module",
|
|
1941
2555
|
"test-api.tf": "terraform {
|
|
1942
2556
|
required_version = ">= 1.0"
|
|
1943
2557
|
|
|
1944
2558
|
required_providers {
|
|
2559
|
+
archive = {
|
|
2560
|
+
source = "hashicorp/archive"
|
|
2561
|
+
version = "2.8.0"
|
|
2562
|
+
}
|
|
1945
2563
|
aws = {
|
|
1946
2564
|
source = "hashicorp/aws"
|
|
1947
|
-
version = "
|
|
2565
|
+
version = "6.62.0"
|
|
2566
|
+
}
|
|
2567
|
+
random = {
|
|
2568
|
+
source = "hashicorp/random"
|
|
2569
|
+
version = "3.9.0"
|
|
1948
2570
|
}
|
|
1949
2571
|
}
|
|
1950
2572
|
}
|
|
@@ -1976,11 +2598,47 @@ variable "additional_iam_policy_statements" {
|
|
|
1976
2598
|
default = []
|
|
1977
2599
|
}
|
|
1978
2600
|
|
|
2601
|
+
variable "appconfig_application_id" {
|
|
2602
|
+
description = "ID of the shared runtime-config AppConfig application (from \`core/runtime-config/appconfig.application_id\`). When set, the Lambda functions receive \`RUNTIME_CONFIG_APP_ID\` and read access to the application."
|
|
2603
|
+
type = string
|
|
2604
|
+
default = null
|
|
2605
|
+
}
|
|
2606
|
+
|
|
2607
|
+
variable "appconfig_application_arn" {
|
|
2608
|
+
description = "ARN of the shared runtime-config AppConfig application (from \`core/runtime-config/appconfig.application_arn\`). Used to scope the IAM read permission granted to the Lambda functions."
|
|
2609
|
+
type = string
|
|
2610
|
+
default = null
|
|
2611
|
+
}
|
|
2612
|
+
|
|
1979
2613
|
variable "asset_bucket_name" {
|
|
1980
2614
|
description = "Name of the shared asset S3 bucket used to stage the Lambda deployment zip. Instantiate the \`core/asset-bucket\` module once per deployment and pass its \`bucket_name\` output here."
|
|
1981
2615
|
type = string
|
|
1982
2616
|
}
|
|
1983
2617
|
|
|
2618
|
+
# VPC Configuration (optional)
|
|
2619
|
+
variable "enable_vpc" {
|
|
2620
|
+
description = "Deploy the Lambda function into a VPC. Set alongside vpc_id/subnet_ids."
|
|
2621
|
+
type = bool
|
|
2622
|
+
default = false
|
|
2623
|
+
}
|
|
2624
|
+
|
|
2625
|
+
variable "vpc_id" {
|
|
2626
|
+
description = "VPC ID to deploy the Lambda function into. Required when enable_vpc is true."
|
|
2627
|
+
type = string
|
|
2628
|
+
default = null
|
|
2629
|
+
|
|
2630
|
+
validation {
|
|
2631
|
+
condition = !var.enable_vpc || (var.vpc_id != null && var.subnet_ids != null)
|
|
2632
|
+
error_message = "vpc_id and subnet_ids must be set when enable_vpc is true."
|
|
2633
|
+
}
|
|
2634
|
+
}
|
|
2635
|
+
|
|
2636
|
+
variable "subnet_ids" {
|
|
2637
|
+
description = "Subnet IDs to deploy the Lambda function into. Required when enable_vpc is true."
|
|
2638
|
+
type = list(string)
|
|
2639
|
+
default = null
|
|
2640
|
+
}
|
|
2641
|
+
|
|
1984
2642
|
# CORS Configuration (passed to core module)
|
|
1985
2643
|
|
|
1986
2644
|
variable "cors_allow_headers" {
|
|
@@ -2025,6 +2683,235 @@ resource "random_string" "suffix" {
|
|
|
2025
2683
|
upper = false
|
|
2026
2684
|
}
|
|
2027
2685
|
|
|
2686
|
+
locals {
|
|
2687
|
+
# Generated at build time from the API definition
|
|
2688
|
+
operations_file = "\${path.module}/../../../generated/test-api/operations.json"
|
|
2689
|
+
operations = fileexists(local.operations_file) ? jsondecode(file(local.operations_file)) : {}
|
|
2690
|
+
|
|
2691
|
+
operation_slug = { for op in keys(local.operations) : op => replace(op, "/[^a-zA-Z0-9-_]/", "-") }
|
|
2692
|
+
operation_hash = { for op in keys(local.operations) : op => substr(sha256(op), 0, 8) }
|
|
2693
|
+
|
|
2694
|
+
function_name = { for op in keys(local.operations) : op =>
|
|
2695
|
+
"\${substr("TestApi-\${local.operation_slug[op]}", 0, 64 - length(local.operation_hash[op]) - length(random_string.suffix.result) - 2)}-\${local.operation_hash[op]}-\${random_string.suffix.result}"
|
|
2696
|
+
}
|
|
2697
|
+
role_name = { for op in keys(local.operations) : op =>
|
|
2698
|
+
"\${substr("TestApi-\${local.operation_slug[op]}-role", 0, 64 - length(local.operation_hash[op]) - length(random_string.suffix.result) - 2)}-\${local.operation_hash[op]}-\${random_string.suffix.result}"
|
|
2699
|
+
}
|
|
2700
|
+
|
|
2701
|
+
# A REST API needs a resource per path segment, so each operation's path is
|
|
2702
|
+
# split into the distinct path prefixes the resource tree is built from below
|
|
2703
|
+
operation_segments = { for op, details in local.operations : op => compact(split("/", details.path)) }
|
|
2704
|
+
|
|
2705
|
+
path_nodes = merge([
|
|
2706
|
+
for op, segments in local.operation_segments : {
|
|
2707
|
+
for i, segment in segments : join("/", slice(segments, 0, i + 1)) => {
|
|
2708
|
+
depth = i
|
|
2709
|
+
parent = i == 0 ? "" : join("/", slice(segments, 0, i))
|
|
2710
|
+
part = segment
|
|
2711
|
+
}
|
|
2712
|
+
}
|
|
2713
|
+
]...)
|
|
2714
|
+
|
|
2715
|
+
# Instances of a resource cannot reference one another, so each depth is a
|
|
2716
|
+
# separate resource. Deeper paths are reported by the precondition below.
|
|
2717
|
+
max_path_depth = 16
|
|
2718
|
+
path_nodes_by_depth = { for depth in range(local.max_path_depth) : depth => {
|
|
2719
|
+
for path, node in local.path_nodes : path => node if node.depth == depth
|
|
2720
|
+
} }
|
|
2721
|
+
paths_too_deep = [for path, node in local.path_nodes : path if node.depth >= local.max_path_depth]
|
|
2722
|
+
|
|
2723
|
+
resource_ids = merge(
|
|
2724
|
+
{ for path, resource in aws_api_gateway_resource.path_depth_0 : path => resource.id },
|
|
2725
|
+
{ for path, resource in aws_api_gateway_resource.path_depth_1 : path => resource.id },
|
|
2726
|
+
{ for path, resource in aws_api_gateway_resource.path_depth_2 : path => resource.id },
|
|
2727
|
+
{ for path, resource in aws_api_gateway_resource.path_depth_3 : path => resource.id },
|
|
2728
|
+
{ for path, resource in aws_api_gateway_resource.path_depth_4 : path => resource.id },
|
|
2729
|
+
{ for path, resource in aws_api_gateway_resource.path_depth_5 : path => resource.id },
|
|
2730
|
+
{ for path, resource in aws_api_gateway_resource.path_depth_6 : path => resource.id },
|
|
2731
|
+
{ for path, resource in aws_api_gateway_resource.path_depth_7 : path => resource.id },
|
|
2732
|
+
{ for path, resource in aws_api_gateway_resource.path_depth_8 : path => resource.id },
|
|
2733
|
+
{ for path, resource in aws_api_gateway_resource.path_depth_9 : path => resource.id },
|
|
2734
|
+
{ for path, resource in aws_api_gateway_resource.path_depth_10 : path => resource.id },
|
|
2735
|
+
{ for path, resource in aws_api_gateway_resource.path_depth_11 : path => resource.id },
|
|
2736
|
+
{ for path, resource in aws_api_gateway_resource.path_depth_12 : path => resource.id },
|
|
2737
|
+
{ for path, resource in aws_api_gateway_resource.path_depth_13 : path => resource.id },
|
|
2738
|
+
{ for path, resource in aws_api_gateway_resource.path_depth_14 : path => resource.id },
|
|
2739
|
+
{ for path, resource in aws_api_gateway_resource.path_depth_15 : path => resource.id },
|
|
2740
|
+
)
|
|
2741
|
+
|
|
2742
|
+
operation_resource_id = { for op, segments in local.operation_segments : op =>
|
|
2743
|
+
local.resource_ids[join("/", segments)]
|
|
2744
|
+
}
|
|
2745
|
+
|
|
2746
|
+
permission_source_suffix = { for op, details in local.operations : op =>
|
|
2747
|
+
"\${upper(details.method)}/\${replace(join("/", local.operation_segments[op]), "/{[^}]*}/", "*")}"
|
|
2748
|
+
}
|
|
2749
|
+
}
|
|
2750
|
+
|
|
2751
|
+
resource "terraform_data" "operations_metadata" {
|
|
2752
|
+
# Fails the plan when the operations metadata has not been generated
|
|
2753
|
+
input = local.operations_file
|
|
2754
|
+
|
|
2755
|
+
lifecycle {
|
|
2756
|
+
precondition {
|
|
2757
|
+
condition = fileexists(local.operations_file)
|
|
2758
|
+
error_message = "Operations metadata not found at \${local.operations_file}. Build the TestApi project to generate it."
|
|
2759
|
+
}
|
|
2760
|
+
precondition {
|
|
2761
|
+
condition = length(local.operations) > 0
|
|
2762
|
+
error_message = "No operations found in \${local.operations_file}. The TestApi API must define at least one operation."
|
|
2763
|
+
}
|
|
2764
|
+
precondition {
|
|
2765
|
+
condition = length(local.paths_too_deep) == 0
|
|
2766
|
+
error_message = "Operation paths exceed the supported depth of \${local.max_path_depth} segments: \${join(", ", local.paths_too_deep)}. Add further aws_api_gateway_resource levels to this module to support them."
|
|
2767
|
+
}
|
|
2768
|
+
}
|
|
2769
|
+
}
|
|
2770
|
+
|
|
2771
|
+
# API Gateway resources at path depth 0
|
|
2772
|
+
resource "aws_api_gateway_resource" "path_depth_0" {
|
|
2773
|
+
for_each = local.path_nodes_by_depth[0]
|
|
2774
|
+
|
|
2775
|
+
rest_api_id = module.rest_api.api_id
|
|
2776
|
+
parent_id = module.rest_api.api_root_resource_id
|
|
2777
|
+
path_part = each.value.part
|
|
2778
|
+
}
|
|
2779
|
+
|
|
2780
|
+
# API Gateway resources at path depth 1
|
|
2781
|
+
resource "aws_api_gateway_resource" "path_depth_1" {
|
|
2782
|
+
for_each = local.path_nodes_by_depth[1]
|
|
2783
|
+
|
|
2784
|
+
rest_api_id = module.rest_api.api_id
|
|
2785
|
+
parent_id = aws_api_gateway_resource.path_depth_0[each.value.parent].id
|
|
2786
|
+
path_part = each.value.part
|
|
2787
|
+
}
|
|
2788
|
+
|
|
2789
|
+
# API Gateway resources at path depth 2
|
|
2790
|
+
resource "aws_api_gateway_resource" "path_depth_2" {
|
|
2791
|
+
for_each = local.path_nodes_by_depth[2]
|
|
2792
|
+
|
|
2793
|
+
rest_api_id = module.rest_api.api_id
|
|
2794
|
+
parent_id = aws_api_gateway_resource.path_depth_1[each.value.parent].id
|
|
2795
|
+
path_part = each.value.part
|
|
2796
|
+
}
|
|
2797
|
+
|
|
2798
|
+
# API Gateway resources at path depth 3
|
|
2799
|
+
resource "aws_api_gateway_resource" "path_depth_3" {
|
|
2800
|
+
for_each = local.path_nodes_by_depth[3]
|
|
2801
|
+
|
|
2802
|
+
rest_api_id = module.rest_api.api_id
|
|
2803
|
+
parent_id = aws_api_gateway_resource.path_depth_2[each.value.parent].id
|
|
2804
|
+
path_part = each.value.part
|
|
2805
|
+
}
|
|
2806
|
+
|
|
2807
|
+
# API Gateway resources at path depth 4
|
|
2808
|
+
resource "aws_api_gateway_resource" "path_depth_4" {
|
|
2809
|
+
for_each = local.path_nodes_by_depth[4]
|
|
2810
|
+
|
|
2811
|
+
rest_api_id = module.rest_api.api_id
|
|
2812
|
+
parent_id = aws_api_gateway_resource.path_depth_3[each.value.parent].id
|
|
2813
|
+
path_part = each.value.part
|
|
2814
|
+
}
|
|
2815
|
+
|
|
2816
|
+
# API Gateway resources at path depth 5
|
|
2817
|
+
resource "aws_api_gateway_resource" "path_depth_5" {
|
|
2818
|
+
for_each = local.path_nodes_by_depth[5]
|
|
2819
|
+
|
|
2820
|
+
rest_api_id = module.rest_api.api_id
|
|
2821
|
+
parent_id = aws_api_gateway_resource.path_depth_4[each.value.parent].id
|
|
2822
|
+
path_part = each.value.part
|
|
2823
|
+
}
|
|
2824
|
+
|
|
2825
|
+
# API Gateway resources at path depth 6
|
|
2826
|
+
resource "aws_api_gateway_resource" "path_depth_6" {
|
|
2827
|
+
for_each = local.path_nodes_by_depth[6]
|
|
2828
|
+
|
|
2829
|
+
rest_api_id = module.rest_api.api_id
|
|
2830
|
+
parent_id = aws_api_gateway_resource.path_depth_5[each.value.parent].id
|
|
2831
|
+
path_part = each.value.part
|
|
2832
|
+
}
|
|
2833
|
+
|
|
2834
|
+
# API Gateway resources at path depth 7
|
|
2835
|
+
resource "aws_api_gateway_resource" "path_depth_7" {
|
|
2836
|
+
for_each = local.path_nodes_by_depth[7]
|
|
2837
|
+
|
|
2838
|
+
rest_api_id = module.rest_api.api_id
|
|
2839
|
+
parent_id = aws_api_gateway_resource.path_depth_6[each.value.parent].id
|
|
2840
|
+
path_part = each.value.part
|
|
2841
|
+
}
|
|
2842
|
+
|
|
2843
|
+
# API Gateway resources at path depth 8
|
|
2844
|
+
resource "aws_api_gateway_resource" "path_depth_8" {
|
|
2845
|
+
for_each = local.path_nodes_by_depth[8]
|
|
2846
|
+
|
|
2847
|
+
rest_api_id = module.rest_api.api_id
|
|
2848
|
+
parent_id = aws_api_gateway_resource.path_depth_7[each.value.parent].id
|
|
2849
|
+
path_part = each.value.part
|
|
2850
|
+
}
|
|
2851
|
+
|
|
2852
|
+
# API Gateway resources at path depth 9
|
|
2853
|
+
resource "aws_api_gateway_resource" "path_depth_9" {
|
|
2854
|
+
for_each = local.path_nodes_by_depth[9]
|
|
2855
|
+
|
|
2856
|
+
rest_api_id = module.rest_api.api_id
|
|
2857
|
+
parent_id = aws_api_gateway_resource.path_depth_8[each.value.parent].id
|
|
2858
|
+
path_part = each.value.part
|
|
2859
|
+
}
|
|
2860
|
+
|
|
2861
|
+
# API Gateway resources at path depth 10
|
|
2862
|
+
resource "aws_api_gateway_resource" "path_depth_10" {
|
|
2863
|
+
for_each = local.path_nodes_by_depth[10]
|
|
2864
|
+
|
|
2865
|
+
rest_api_id = module.rest_api.api_id
|
|
2866
|
+
parent_id = aws_api_gateway_resource.path_depth_9[each.value.parent].id
|
|
2867
|
+
path_part = each.value.part
|
|
2868
|
+
}
|
|
2869
|
+
|
|
2870
|
+
# API Gateway resources at path depth 11
|
|
2871
|
+
resource "aws_api_gateway_resource" "path_depth_11" {
|
|
2872
|
+
for_each = local.path_nodes_by_depth[11]
|
|
2873
|
+
|
|
2874
|
+
rest_api_id = module.rest_api.api_id
|
|
2875
|
+
parent_id = aws_api_gateway_resource.path_depth_10[each.value.parent].id
|
|
2876
|
+
path_part = each.value.part
|
|
2877
|
+
}
|
|
2878
|
+
|
|
2879
|
+
# API Gateway resources at path depth 12
|
|
2880
|
+
resource "aws_api_gateway_resource" "path_depth_12" {
|
|
2881
|
+
for_each = local.path_nodes_by_depth[12]
|
|
2882
|
+
|
|
2883
|
+
rest_api_id = module.rest_api.api_id
|
|
2884
|
+
parent_id = aws_api_gateway_resource.path_depth_11[each.value.parent].id
|
|
2885
|
+
path_part = each.value.part
|
|
2886
|
+
}
|
|
2887
|
+
|
|
2888
|
+
# API Gateway resources at path depth 13
|
|
2889
|
+
resource "aws_api_gateway_resource" "path_depth_13" {
|
|
2890
|
+
for_each = local.path_nodes_by_depth[13]
|
|
2891
|
+
|
|
2892
|
+
rest_api_id = module.rest_api.api_id
|
|
2893
|
+
parent_id = aws_api_gateway_resource.path_depth_12[each.value.parent].id
|
|
2894
|
+
path_part = each.value.part
|
|
2895
|
+
}
|
|
2896
|
+
|
|
2897
|
+
# API Gateway resources at path depth 14
|
|
2898
|
+
resource "aws_api_gateway_resource" "path_depth_14" {
|
|
2899
|
+
for_each = local.path_nodes_by_depth[14]
|
|
2900
|
+
|
|
2901
|
+
rest_api_id = module.rest_api.api_id
|
|
2902
|
+
parent_id = aws_api_gateway_resource.path_depth_13[each.value.parent].id
|
|
2903
|
+
path_part = each.value.part
|
|
2904
|
+
}
|
|
2905
|
+
|
|
2906
|
+
# API Gateway resources at path depth 15
|
|
2907
|
+
resource "aws_api_gateway_resource" "path_depth_15" {
|
|
2908
|
+
for_each = local.path_nodes_by_depth[15]
|
|
2909
|
+
|
|
2910
|
+
rest_api_id = module.rest_api.api_id
|
|
2911
|
+
parent_id = aws_api_gateway_resource.path_depth_14[each.value.parent].id
|
|
2912
|
+
path_part = each.value.part
|
|
2913
|
+
}
|
|
2914
|
+
|
|
2028
2915
|
# Resources
|
|
2029
2916
|
|
|
2030
2917
|
# Create Lambda ZIP file from the bundle directory
|
|
@@ -2043,6 +2930,11 @@ resource "aws_s3_object" "lambda_zip" {
|
|
|
2043
2930
|
}
|
|
2044
2931
|
|
|
2045
2932
|
# Use the core REST API module
|
|
2933
|
+
# Account-level CloudWatch role required for REST API access logging
|
|
2934
|
+
module "account" {
|
|
2935
|
+
source = "../../../core/api/api-gateway-account"
|
|
2936
|
+
}
|
|
2937
|
+
|
|
2046
2938
|
module "rest_api" {
|
|
2047
2939
|
source = "../../../core/api/rest-api"
|
|
2048
2940
|
|
|
@@ -2072,9 +2964,33 @@ resource "aws_wafv2_web_acl_association" "api_waf_association" {
|
|
|
2072
2964
|
depends_on = [aws_api_gateway_stage.api_stage]
|
|
2073
2965
|
}
|
|
2074
2966
|
|
|
2075
|
-
# Lambda function
|
|
2967
|
+
# Security group for the API Lambda function, used when deployed into a VPC
|
|
2968
|
+
resource "aws_security_group" "api_lambda" {
|
|
2969
|
+
count = var.enable_vpc ? 1 : 0
|
|
2970
|
+
|
|
2971
|
+
#checkov:skip=CKV2_AWS_5:Attached to api_lambda via vpc_config block; Checkov cannot resolve this reference
|
|
2972
|
+
name_prefix = "test-api-lambda-"
|
|
2973
|
+
description = "Security group for the TestApi API Lambda function"
|
|
2974
|
+
vpc_id = var.vpc_id
|
|
2975
|
+
tags = var.tags
|
|
2976
|
+
}
|
|
2977
|
+
|
|
2978
|
+
resource "aws_vpc_security_group_egress_rule" "api_lambda_https" {
|
|
2979
|
+
count = var.enable_vpc ? 1 : 0
|
|
2980
|
+
|
|
2981
|
+
security_group_id = aws_security_group.api_lambda[0].id
|
|
2982
|
+
cidr_ipv4 = "0.0.0.0/0"
|
|
2983
|
+
from_port = 443
|
|
2984
|
+
to_port = 443
|
|
2985
|
+
ip_protocol = "tcp"
|
|
2986
|
+
description = "Allow outbound HTTPS to AWS service endpoints"
|
|
2987
|
+
}
|
|
2988
|
+
|
|
2076
2989
|
resource "aws_lambda_function" "api_lambda" {
|
|
2077
|
-
#
|
|
2990
|
+
# One lambda function per operation, each serving just that operation
|
|
2991
|
+
for_each = local.operations
|
|
2992
|
+
|
|
2993
|
+
#checkov:skip=CKV_AWS_117:Lambda function is optionally deployed into a VPC via vpc_id/subnet_ids; not required for this use case
|
|
2078
2994
|
#checkov:skip=CKV_AWS_116:Dead Letter Queue not required for this simple API use case
|
|
2079
2995
|
#checkov:skip=CKV_AWS_272:Code signing not required for this use case
|
|
2080
2996
|
#checkov:skip=CKV_AWS_115:Concurrent execution limit not required for this use case
|
|
@@ -2082,10 +2998,10 @@ resource "aws_lambda_function" "api_lambda" {
|
|
|
2082
2998
|
s3_bucket = aws_s3_object.lambda_zip.bucket
|
|
2083
2999
|
s3_key = aws_s3_object.lambda_zip.key
|
|
2084
3000
|
s3_object_version = aws_s3_object.lambda_zip.version_id
|
|
2085
|
-
function_name =
|
|
2086
|
-
role = aws_iam_role.lambda_execution_role.arn
|
|
3001
|
+
function_name = local.function_name[each.key]
|
|
3002
|
+
role = aws_iam_role.lambda_execution_role[each.key].arn
|
|
2087
3003
|
handler = "index.handler"
|
|
2088
|
-
runtime = "
|
|
3004
|
+
runtime = "nodejs24.x"
|
|
2089
3005
|
timeout = 30
|
|
2090
3006
|
memory_size = 128
|
|
2091
3007
|
|
|
@@ -2096,18 +3012,32 @@ resource "aws_lambda_function" "api_lambda" {
|
|
|
2096
3012
|
mode = "Active"
|
|
2097
3013
|
}
|
|
2098
3014
|
|
|
3015
|
+
dynamic "vpc_config" {
|
|
3016
|
+
for_each = var.enable_vpc ? [1] : []
|
|
3017
|
+
content {
|
|
3018
|
+
subnet_ids = var.subnet_ids
|
|
3019
|
+
security_group_ids = [aws_security_group.api_lambda[0].id]
|
|
3020
|
+
}
|
|
3021
|
+
}
|
|
3022
|
+
|
|
2099
3023
|
|
|
2100
3024
|
environment {
|
|
2101
3025
|
variables = merge({
|
|
2102
|
-
}, var.
|
|
3026
|
+
}, var.appconfig_application_id != null ? {
|
|
3027
|
+
RUNTIME_CONFIG_APP_ID = var.appconfig_application_id
|
|
3028
|
+
} : {}, var.env)
|
|
2103
3029
|
}
|
|
2104
3030
|
|
|
2105
3031
|
tags = var.tags
|
|
3032
|
+
|
|
3033
|
+
depends_on = [aws_iam_role_policy_attachment.lambda_vpc_access]
|
|
2106
3034
|
}
|
|
2107
3035
|
|
|
2108
3036
|
# IAM role for Lambda execution
|
|
2109
3037
|
resource "aws_iam_role" "lambda_execution_role" {
|
|
2110
|
-
|
|
3038
|
+
for_each = local.operations
|
|
3039
|
+
|
|
3040
|
+
name = local.role_name[each.key]
|
|
2111
3041
|
|
|
2112
3042
|
assume_role_policy = jsonencode({
|
|
2113
3043
|
Version = "2012-10-17"
|
|
@@ -2127,35 +3057,73 @@ resource "aws_iam_role" "lambda_execution_role" {
|
|
|
2127
3057
|
|
|
2128
3058
|
# Attach basic execution policy to Lambda role
|
|
2129
3059
|
resource "aws_iam_role_policy_attachment" "lambda_basic_execution" {
|
|
3060
|
+
for_each = local.operations
|
|
3061
|
+
|
|
2130
3062
|
policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
|
|
2131
|
-
role = aws_iam_role.lambda_execution_role.name
|
|
3063
|
+
role = aws_iam_role.lambda_execution_role[each.key].name
|
|
2132
3064
|
}
|
|
2133
3065
|
|
|
2134
3066
|
# Attach X-Ray tracing policy to Lambda role
|
|
2135
3067
|
resource "aws_iam_role_policy_attachment" "lambda_xray_execution" {
|
|
3068
|
+
for_each = local.operations
|
|
3069
|
+
|
|
2136
3070
|
policy_arn = "arn:aws:iam::aws:policy/AWSXRayDaemonWriteAccess"
|
|
2137
|
-
role = aws_iam_role.lambda_execution_role.name
|
|
3071
|
+
role = aws_iam_role.lambda_execution_role[each.key].name
|
|
3072
|
+
}
|
|
3073
|
+
|
|
3074
|
+
# Attach VPC access policy to Lambda role when deployed into a VPC
|
|
3075
|
+
resource "aws_iam_role_policy_attachment" "lambda_vpc_access" {
|
|
3076
|
+
for_each = var.enable_vpc ? local.operations : {}
|
|
3077
|
+
|
|
3078
|
+
policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole"
|
|
3079
|
+
role = aws_iam_role.lambda_execution_role[each.key].name
|
|
2138
3080
|
}
|
|
2139
3081
|
|
|
2140
3082
|
# Additional IAM policies for Lambda (if provided)
|
|
2141
3083
|
resource "aws_iam_role_policy" "lambda_additional_policies" {
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
3084
|
+
for_each = local.operations
|
|
3085
|
+
|
|
3086
|
+
name = "\${substr(local.function_name[each.key], 0, 55)}-policies"
|
|
3087
|
+
role = aws_iam_role.lambda_execution_role[each.key].id
|
|
2145
3088
|
|
|
2146
3089
|
policy = jsonencode({
|
|
2147
3090
|
Version = "2012-10-17"
|
|
2148
|
-
Statement =
|
|
3091
|
+
Statement = local.lambda_policy_document_statements
|
|
2149
3092
|
})
|
|
2150
3093
|
}
|
|
2151
3094
|
|
|
3095
|
+
locals {
|
|
3096
|
+
# Grant read access to the runtime-config AppConfig application when wired
|
|
3097
|
+
lambda_policy_statements = concat(var.appconfig_application_arn != null ? [
|
|
3098
|
+
{
|
|
3099
|
+
Effect = "Allow"
|
|
3100
|
+
Action = [
|
|
3101
|
+
"appconfig:StartConfigurationSession",
|
|
3102
|
+
"appconfig:GetLatestConfiguration"
|
|
3103
|
+
]
|
|
3104
|
+
Resource = ["\${var.appconfig_application_arn}/*"]
|
|
3105
|
+
}
|
|
3106
|
+
] : [], var.additional_iam_policy_statements)
|
|
3107
|
+
|
|
3108
|
+
# IAM rejects an empty statement list, so fall back to a no-op deny
|
|
3109
|
+
lambda_policy_document_statements = length(local.lambda_policy_statements) > 0 ? local.lambda_policy_statements : [
|
|
3110
|
+
{
|
|
3111
|
+
Effect = "Deny"
|
|
3112
|
+
Action = ["appconfig:GetLatestConfiguration"]
|
|
3113
|
+
Resource = ["arn:aws:appconfig:\${data.aws_region.current.region}:\${data.aws_caller_identity.current.account_id}:application/none"]
|
|
3114
|
+
}
|
|
3115
|
+
]
|
|
3116
|
+
}
|
|
3117
|
+
|
|
2152
3118
|
# CloudWatch Log Group for Lambda
|
|
2153
3119
|
resource "aws_cloudwatch_log_group" "lambda_logs" {
|
|
2154
3120
|
#checkov:skip=CKV_AWS_158:Using default CloudWatch log encryption
|
|
2155
3121
|
#checkov:skip=CKV_AWS_338:Log retention set to forever
|
|
2156
3122
|
#checkov:skip=CKV_AWS_66:Log retention set to forever
|
|
2157
|
-
|
|
2158
|
-
|
|
3123
|
+
for_each = local.operations
|
|
3124
|
+
|
|
3125
|
+
name = "/aws/lambda/\${local.function_name[each.key]}"
|
|
3126
|
+
tags = var.tags
|
|
2159
3127
|
}
|
|
2160
3128
|
|
|
2161
3129
|
|
|
@@ -2168,58 +3136,65 @@ resource "aws_api_gateway_authorizer" "cognito_authorizer" {
|
|
|
2168
3136
|
identity_source = "method.request.header.Authorization"
|
|
2169
3137
|
}
|
|
2170
3138
|
|
|
2171
|
-
#
|
|
2172
|
-
resource "
|
|
2173
|
-
rest_api_id = module.rest_api.api_id
|
|
2174
|
-
parent_id = module.rest_api.api_root_resource_id
|
|
2175
|
-
path_part = "{proxy+}"
|
|
2176
|
-
}
|
|
2177
|
-
|
|
2178
|
-
# Lambda integration for REST API
|
|
2179
|
-
resource "aws_api_gateway_integration" "lambda_integration" {
|
|
2180
|
-
rest_api_id = module.rest_api.api_id
|
|
2181
|
-
resource_id = aws_api_gateway_resource.proxy_resource.id
|
|
2182
|
-
http_method = aws_api_gateway_method.proxy_method.http_method
|
|
2183
|
-
|
|
2184
|
-
integration_http_method = "POST"
|
|
2185
|
-
type = "AWS_PROXY"
|
|
2186
|
-
uri = aws_lambda_function.api_lambda.invoke_arn
|
|
2187
|
-
|
|
2188
|
-
depends_on = [aws_lambda_function.api_lambda]
|
|
2189
|
-
}
|
|
2190
|
-
|
|
2191
|
-
# Method for proxy integration
|
|
2192
|
-
resource "aws_api_gateway_method" "proxy_method" {
|
|
3139
|
+
# Method per operation
|
|
3140
|
+
resource "aws_api_gateway_method" "operation_methods" {
|
|
2193
3141
|
#checkov:skip=CKV2_AWS_53:Request validation not required for proxy integration as Lambda handles validation
|
|
3142
|
+
for_each = local.operations
|
|
3143
|
+
|
|
2194
3144
|
rest_api_id = module.rest_api.api_id
|
|
2195
|
-
resource_id =
|
|
2196
|
-
http_method =
|
|
3145
|
+
resource_id = local.operation_resource_id[each.key]
|
|
3146
|
+
http_method = upper(each.value.method)
|
|
2197
3147
|
|
|
2198
3148
|
authorization = "COGNITO_USER_POOLS"
|
|
2199
3149
|
authorizer_id = aws_api_gateway_authorizer.cognito_authorizer.id
|
|
3150
|
+
# Accept access tokens from both sign-in flows: 'openid' (Cognito hosted UI)
|
|
3151
|
+
# and 'aws.cognito.signin.user.admin' (Cognito admin/SRP auth APIs).
|
|
3152
|
+
authorization_scopes = ["openid", "aws.cognito.signin.user.admin"]
|
|
2200
3153
|
|
|
3154
|
+
# Path parameters must be declared on the method
|
|
2201
3155
|
request_parameters = {
|
|
2202
|
-
|
|
3156
|
+
for segment in local.operation_segments[each.key] :
|
|
3157
|
+
"method.request.path.\${trimsuffix(trimprefix(segment, "{"), "}")}" => true
|
|
3158
|
+
if startswith(segment, "{")
|
|
2203
3159
|
}
|
|
2204
3160
|
|
|
2205
3161
|
depends_on = [aws_api_gateway_authorizer.cognito_authorizer]
|
|
2206
3162
|
}
|
|
2207
3163
|
|
|
2208
|
-
#
|
|
3164
|
+
# Lambda integration per operation
|
|
3165
|
+
resource "aws_api_gateway_integration" "lambda_integration" {
|
|
3166
|
+
for_each = local.operations
|
|
3167
|
+
|
|
3168
|
+
rest_api_id = module.rest_api.api_id
|
|
3169
|
+
resource_id = local.operation_resource_id[each.key]
|
|
3170
|
+
http_method = aws_api_gateway_method.operation_methods[each.key].http_method
|
|
3171
|
+
|
|
3172
|
+
integration_http_method = "POST"
|
|
3173
|
+
type = "AWS_PROXY"
|
|
3174
|
+
uri = aws_lambda_function.api_lambda[each.key].invoke_arn
|
|
3175
|
+
|
|
3176
|
+
depends_on = [aws_lambda_function.api_lambda]
|
|
3177
|
+
}
|
|
3178
|
+
|
|
3179
|
+
# OPTIONS method for CORS preflight, on every resource an operation is served from
|
|
2209
3180
|
resource "aws_api_gateway_method" "options_method" {
|
|
2210
3181
|
#checkov:skip=CKV2_AWS_70:OPTIONS method must be unauthenticated for CORS preflight requests
|
|
2211
3182
|
#checkov:skip=CKV2_AWS_53:Request validation not required for OPTIONS CORS preflight method
|
|
3183
|
+
for_each = local.resource_ids
|
|
3184
|
+
|
|
2212
3185
|
rest_api_id = module.rest_api.api_id
|
|
2213
|
-
resource_id =
|
|
3186
|
+
resource_id = each.value
|
|
2214
3187
|
http_method = "OPTIONS"
|
|
2215
3188
|
authorization = "NONE"
|
|
2216
3189
|
}
|
|
2217
3190
|
|
|
2218
|
-
# CORS integration for OPTIONS
|
|
3191
|
+
# CORS integration for OPTIONS methods
|
|
2219
3192
|
resource "aws_api_gateway_integration" "options_integration" {
|
|
3193
|
+
for_each = local.resource_ids
|
|
3194
|
+
|
|
2220
3195
|
rest_api_id = module.rest_api.api_id
|
|
2221
|
-
resource_id =
|
|
2222
|
-
http_method = aws_api_gateway_method.options_method.http_method
|
|
3196
|
+
resource_id = each.value
|
|
3197
|
+
http_method = aws_api_gateway_method.options_method[each.key].http_method
|
|
2223
3198
|
|
|
2224
3199
|
type = "MOCK"
|
|
2225
3200
|
request_templates = {
|
|
@@ -2227,11 +3202,13 @@ resource "aws_api_gateway_integration" "options_integration" {
|
|
|
2227
3202
|
}
|
|
2228
3203
|
}
|
|
2229
3204
|
|
|
2230
|
-
# OPTIONS method
|
|
3205
|
+
# OPTIONS method responses
|
|
2231
3206
|
resource "aws_api_gateway_method_response" "options_response" {
|
|
3207
|
+
for_each = local.resource_ids
|
|
3208
|
+
|
|
2232
3209
|
rest_api_id = module.rest_api.api_id
|
|
2233
|
-
resource_id =
|
|
2234
|
-
http_method = aws_api_gateway_method.options_method.http_method
|
|
3210
|
+
resource_id = each.value
|
|
3211
|
+
http_method = aws_api_gateway_method.options_method[each.key].http_method
|
|
2235
3212
|
status_code = "204"
|
|
2236
3213
|
|
|
2237
3214
|
response_parameters = {
|
|
@@ -2241,18 +3218,22 @@ resource "aws_api_gateway_method_response" "options_response" {
|
|
|
2241
3218
|
}
|
|
2242
3219
|
}
|
|
2243
3220
|
|
|
2244
|
-
# OPTIONS integration
|
|
3221
|
+
# OPTIONS integration responses
|
|
2245
3222
|
resource "aws_api_gateway_integration_response" "options_integration_response" {
|
|
3223
|
+
for_each = local.resource_ids
|
|
3224
|
+
|
|
2246
3225
|
rest_api_id = module.rest_api.api_id
|
|
2247
|
-
resource_id =
|
|
2248
|
-
http_method = aws_api_gateway_method.options_method.http_method
|
|
2249
|
-
status_code = aws_api_gateway_method_response.options_response.status_code
|
|
3226
|
+
resource_id = each.value
|
|
3227
|
+
http_method = aws_api_gateway_method.options_method[each.key].http_method
|
|
3228
|
+
status_code = aws_api_gateway_method_response.options_response[each.key].status_code
|
|
2250
3229
|
|
|
2251
3230
|
response_parameters = {
|
|
2252
3231
|
"method.response.header.Access-Control-Allow-Headers" = "'\${join(",", var.cors_allow_headers)}'"
|
|
2253
3232
|
"method.response.header.Access-Control-Allow-Methods" = "'\${join(",", var.cors_allow_methods)}'"
|
|
2254
3233
|
"method.response.header.Access-Control-Allow-Origin" = "'\${join(",", var.cors_allow_origins)}'"
|
|
2255
3234
|
}
|
|
3235
|
+
|
|
3236
|
+
depends_on = [aws_api_gateway_integration.options_integration]
|
|
2256
3237
|
}
|
|
2257
3238
|
|
|
2258
3239
|
# API Gateway deployment
|
|
@@ -2260,13 +3241,28 @@ resource "aws_api_gateway_deployment" "api_deployment" {
|
|
|
2260
3241
|
rest_api_id = module.rest_api.api_id
|
|
2261
3242
|
|
|
2262
3243
|
triggers = {
|
|
2263
|
-
redeployment = sha1(jsonencode(
|
|
2264
|
-
aws_api_gateway_resource.
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
3244
|
+
redeployment = sha1(jsonencode(concat(
|
|
3245
|
+
[for r in aws_api_gateway_resource.path_depth_0 : r.id],
|
|
3246
|
+
[for r in aws_api_gateway_resource.path_depth_1 : r.id],
|
|
3247
|
+
[for r in aws_api_gateway_resource.path_depth_2 : r.id],
|
|
3248
|
+
[for r in aws_api_gateway_resource.path_depth_3 : r.id],
|
|
3249
|
+
[for r in aws_api_gateway_resource.path_depth_4 : r.id],
|
|
3250
|
+
[for r in aws_api_gateway_resource.path_depth_5 : r.id],
|
|
3251
|
+
[for r in aws_api_gateway_resource.path_depth_6 : r.id],
|
|
3252
|
+
[for r in aws_api_gateway_resource.path_depth_7 : r.id],
|
|
3253
|
+
[for r in aws_api_gateway_resource.path_depth_8 : r.id],
|
|
3254
|
+
[for r in aws_api_gateway_resource.path_depth_9 : r.id],
|
|
3255
|
+
[for r in aws_api_gateway_resource.path_depth_10 : r.id],
|
|
3256
|
+
[for r in aws_api_gateway_resource.path_depth_11 : r.id],
|
|
3257
|
+
[for r in aws_api_gateway_resource.path_depth_12 : r.id],
|
|
3258
|
+
[for r in aws_api_gateway_resource.path_depth_13 : r.id],
|
|
3259
|
+
[for r in aws_api_gateway_resource.path_depth_14 : r.id],
|
|
3260
|
+
[for r in aws_api_gateway_resource.path_depth_15 : r.id],
|
|
3261
|
+
[for m in aws_api_gateway_method.operation_methods : m.id],
|
|
3262
|
+
[for i in aws_api_gateway_integration.lambda_integration : i.id],
|
|
3263
|
+
[for m in aws_api_gateway_method.options_method : m.id],
|
|
3264
|
+
[for i in aws_api_gateway_integration.options_integration : i.id],
|
|
3265
|
+
)))
|
|
2270
3266
|
}
|
|
2271
3267
|
|
|
2272
3268
|
lifecycle {
|
|
@@ -2274,7 +3270,7 @@ resource "aws_api_gateway_deployment" "api_deployment" {
|
|
|
2274
3270
|
}
|
|
2275
3271
|
|
|
2276
3272
|
depends_on = [
|
|
2277
|
-
aws_api_gateway_method.
|
|
3273
|
+
aws_api_gateway_method.operation_methods,
|
|
2278
3274
|
aws_api_gateway_integration.lambda_integration,
|
|
2279
3275
|
aws_api_gateway_method.options_method,
|
|
2280
3276
|
aws_api_gateway_integration.options_integration,
|
|
@@ -2283,11 +3279,63 @@ resource "aws_api_gateway_deployment" "api_deployment" {
|
|
|
2283
3279
|
]
|
|
2284
3280
|
}
|
|
2285
3281
|
|
|
3282
|
+
# KMS key for encrypting access logs at rest
|
|
3283
|
+
resource "aws_kms_key" "access_logs" {
|
|
3284
|
+
description = "TestApi API access log encryption"
|
|
3285
|
+
deletion_window_in_days = 7
|
|
3286
|
+
enable_key_rotation = true
|
|
3287
|
+
|
|
3288
|
+
policy = jsonencode({
|
|
3289
|
+
Version = "2012-10-17"
|
|
3290
|
+
Statement = [
|
|
3291
|
+
{
|
|
3292
|
+
Sid = "Enable IAM User Permissions"
|
|
3293
|
+
Effect = "Allow"
|
|
3294
|
+
Principal = { AWS = "arn:aws:iam::\${data.aws_caller_identity.current.account_id}:root" }
|
|
3295
|
+
Action = "kms:*"
|
|
3296
|
+
Resource = "*"
|
|
3297
|
+
},
|
|
3298
|
+
{
|
|
3299
|
+
Sid = "Allow CloudWatch Logs"
|
|
3300
|
+
Effect = "Allow"
|
|
3301
|
+
Principal = { Service = "logs.\${data.aws_region.current.region}.amazonaws.com" }
|
|
3302
|
+
Action = [
|
|
3303
|
+
"kms:Encrypt",
|
|
3304
|
+
"kms:Decrypt",
|
|
3305
|
+
"kms:ReEncrypt*",
|
|
3306
|
+
"kms:GenerateDataKey*",
|
|
3307
|
+
"kms:DescribeKey"
|
|
3308
|
+
]
|
|
3309
|
+
Resource = "*"
|
|
3310
|
+
Condition = {
|
|
3311
|
+
ArnEquals = {
|
|
3312
|
+
"kms:EncryptionContext:aws:logs:arn" = "arn:aws:logs:\${data.aws_region.current.region}:\${data.aws_caller_identity.current.account_id}:log-group:/aws/apigateway/test-api-\${random_string.suffix.result}/access"
|
|
3313
|
+
}
|
|
3314
|
+
}
|
|
3315
|
+
}
|
|
3316
|
+
]
|
|
3317
|
+
})
|
|
3318
|
+
|
|
3319
|
+
tags = var.tags
|
|
3320
|
+
}
|
|
3321
|
+
|
|
3322
|
+
resource "aws_kms_alias" "access_logs" {
|
|
3323
|
+
name = "alias/test-api-\${random_string.suffix.result}-access-logs"
|
|
3324
|
+
target_key_id = aws_kms_key.access_logs.key_id
|
|
3325
|
+
}
|
|
3326
|
+
|
|
3327
|
+
# Access logs for the API Gateway stage
|
|
3328
|
+
resource "aws_cloudwatch_log_group" "access_logs" {
|
|
3329
|
+
name = "/aws/apigateway/test-api-\${random_string.suffix.result}/access"
|
|
3330
|
+
retention_in_days = 365
|
|
3331
|
+
kms_key_id = aws_kms_key.access_logs.arn
|
|
3332
|
+
tags = var.tags
|
|
3333
|
+
}
|
|
3334
|
+
|
|
2286
3335
|
# API Gateway stage
|
|
2287
3336
|
resource "aws_api_gateway_stage" "api_stage" {
|
|
2288
3337
|
#checkov:skip=CKV_AWS_120:API Gateway caching not required for this use case
|
|
2289
|
-
#checkov:skip=
|
|
2290
|
-
#checkov:skip=CKV2_AWS_4:API Gateway logging level not applicable as access logging is disabled
|
|
3338
|
+
#checkov:skip=CKV2_AWS_4:Access logging is enabled below; verbose execution logging is intentionally not enabled
|
|
2291
3339
|
#checkov:skip=CKV2_AWS_51:Client certificate authentication not required for this use case
|
|
2292
3340
|
#checkov:skip=CKV2_AWS_77:WAFv2 Web ACL is attached via aws_wafv2_web_acl_association when var.enable_waf is true (default) and includes AWSManagedRulesKnownBadInputsRuleSet for Log4j protection; Checkov does not track the association across modules
|
|
2293
3341
|
deployment_id = aws_api_gateway_deployment.api_deployment.id
|
|
@@ -2295,9 +3343,39 @@ resource "aws_api_gateway_stage" "api_stage" {
|
|
|
2295
3343
|
stage_name = "prod"
|
|
2296
3344
|
xray_tracing_enabled = true
|
|
2297
3345
|
|
|
3346
|
+
access_log_settings {
|
|
3347
|
+
destination_arn = aws_cloudwatch_log_group.access_logs.arn
|
|
3348
|
+
format = jsonencode({
|
|
3349
|
+
requestId = "$context.requestId"
|
|
3350
|
+
ip = "$context.identity.sourceIp"
|
|
3351
|
+
caller = "$context.identity.caller"
|
|
3352
|
+
user = "$context.identity.user"
|
|
3353
|
+
requestTime = "$context.requestTime"
|
|
3354
|
+
httpMethod = "$context.httpMethod"
|
|
3355
|
+
resourcePath = "$context.resourcePath"
|
|
3356
|
+
status = "$context.status"
|
|
3357
|
+
protocol = "$context.protocol"
|
|
3358
|
+
responseLength = "$context.responseLength"
|
|
3359
|
+
})
|
|
3360
|
+
}
|
|
3361
|
+
|
|
2298
3362
|
tags = var.tags
|
|
2299
3363
|
|
|
2300
|
-
|
|
3364
|
+
# Ensure the account-level role is configured before the stage is created
|
|
3365
|
+
depends_on = [aws_api_gateway_deployment.api_deployment, module.account]
|
|
3366
|
+
}
|
|
3367
|
+
|
|
3368
|
+
# Default throttling applied to all resource paths and methods
|
|
3369
|
+
resource "aws_api_gateway_method_settings" "throttling" {
|
|
3370
|
+
#checkov:skip=CKV_AWS_225:API Gateway caching not required for this use case
|
|
3371
|
+
rest_api_id = module.rest_api.api_id
|
|
3372
|
+
stage_name = aws_api_gateway_stage.api_stage.stage_name
|
|
3373
|
+
method_path = "*/*"
|
|
3374
|
+
|
|
3375
|
+
settings {
|
|
3376
|
+
throttling_rate_limit = 10000
|
|
3377
|
+
throttling_burst_limit = 5000
|
|
3378
|
+
}
|
|
2301
3379
|
}
|
|
2302
3380
|
|
|
2303
3381
|
# API Gateway Resource Policy
|
|
@@ -2320,11 +3398,13 @@ resource "aws_api_gateway_rest_api_policy" "api_policy" {
|
|
|
2320
3398
|
|
|
2321
3399
|
# Lambda permission for API Gateway to invoke the function
|
|
2322
3400
|
resource "aws_lambda_permission" "api_gateway_invoke" {
|
|
3401
|
+
for_each = local.operations
|
|
3402
|
+
|
|
2323
3403
|
statement_id = "AllowExecutionFromAPIGateway"
|
|
2324
3404
|
action = "lambda:InvokeFunction"
|
|
2325
|
-
function_name = aws_lambda_function.api_lambda.function_name
|
|
3405
|
+
function_name = aws_lambda_function.api_lambda[each.key].function_name
|
|
2326
3406
|
principal = "apigateway.amazonaws.com"
|
|
2327
|
-
source_arn = "\${module.rest_api.api_execution_arn}
|
|
3407
|
+
source_arn = "\${module.rest_api.api_execution_arn}/*/\${local.permission_source_suffix[each.key]}"
|
|
2328
3408
|
|
|
2329
3409
|
depends_on = [module.rest_api, aws_lambda_function.api_lambda]
|
|
2330
3410
|
}
|
|
@@ -2336,7 +3416,7 @@ module "add_url_to_runtime_config" {
|
|
|
2336
3416
|
|
|
2337
3417
|
namespace = "connection"
|
|
2338
3418
|
key = "apis"
|
|
2339
|
-
value = { "TestApi" = aws_api_gateway_stage.api_stage.invoke_url }
|
|
3419
|
+
value = { "TestApi" = "\${aws_api_gateway_stage.api_stage.invoke_url}/" }
|
|
2340
3420
|
|
|
2341
3421
|
depends_on = [aws_api_gateway_stage.api_stage]
|
|
2342
3422
|
}
|
|
@@ -2389,78 +3469,83 @@ output "stage_id" {
|
|
|
2389
3469
|
value = aws_api_gateway_stage.api_stage.id
|
|
2390
3470
|
}
|
|
2391
3471
|
|
|
2392
|
-
# Lambda Function Outputs
|
|
2393
|
-
output "
|
|
2394
|
-
description = "
|
|
2395
|
-
value =
|
|
3472
|
+
# Lambda Function Outputs, keyed by operation name
|
|
3473
|
+
output "operations" {
|
|
3474
|
+
description = "Names of the API operations, each with its own Lambda function"
|
|
3475
|
+
value = keys(local.operations)
|
|
2396
3476
|
}
|
|
2397
3477
|
|
|
2398
|
-
output "
|
|
2399
|
-
description = "
|
|
2400
|
-
value = aws_lambda_function.api_lambda.
|
|
3478
|
+
output "lambda_function_names" {
|
|
3479
|
+
description = "Name of each operation's Lambda function, keyed by operation name"
|
|
3480
|
+
value = { for op, fn in aws_lambda_function.api_lambda : op => fn.function_name }
|
|
2401
3481
|
}
|
|
2402
3482
|
|
|
2403
|
-
output "
|
|
2404
|
-
description = "
|
|
2405
|
-
value = aws_lambda_function.api_lambda.
|
|
3483
|
+
output "lambda_function_arns" {
|
|
3484
|
+
description = "ARN of each operation's Lambda function, keyed by operation name"
|
|
3485
|
+
value = { for op, fn in aws_lambda_function.api_lambda : op => fn.arn }
|
|
2406
3486
|
}
|
|
2407
3487
|
|
|
2408
|
-
output "
|
|
2409
|
-
description = "
|
|
2410
|
-
value = aws_lambda_function.api_lambda.
|
|
3488
|
+
output "lambda_invoke_arns" {
|
|
3489
|
+
description = "Invoke ARN of each operation's Lambda function, keyed by operation name"
|
|
3490
|
+
value = { for op, fn in aws_lambda_function.api_lambda : op => fn.invoke_arn }
|
|
2411
3491
|
}
|
|
2412
3492
|
|
|
2413
|
-
output "
|
|
2414
|
-
description = "
|
|
2415
|
-
value = aws_lambda_function.api_lambda.
|
|
3493
|
+
output "lambda_qualified_arns" {
|
|
3494
|
+
description = "Qualified ARN of each operation's Lambda function, keyed by operation name"
|
|
3495
|
+
value = { for op, fn in aws_lambda_function.api_lambda : op => fn.qualified_arn }
|
|
2416
3496
|
}
|
|
2417
3497
|
|
|
2418
|
-
output "
|
|
2419
|
-
description = "
|
|
2420
|
-
value = aws_lambda_function.api_lambda.
|
|
3498
|
+
output "lambda_versions" {
|
|
3499
|
+
description = "Version of each operation's Lambda function, keyed by operation name"
|
|
3500
|
+
value = { for op, fn in aws_lambda_function.api_lambda : op => fn.version }
|
|
2421
3501
|
}
|
|
2422
3502
|
|
|
2423
|
-
output "
|
|
2424
|
-
description = "
|
|
2425
|
-
value =
|
|
3503
|
+
output "lambda_source_code_hash" {
|
|
3504
|
+
description = "Base64-encoded SHA256 hash of the Lambda deployment package, shared by every operation"
|
|
3505
|
+
value = data.archive_file.lambda_zip.output_base64sha256
|
|
3506
|
+
}
|
|
3507
|
+
|
|
3508
|
+
# IAM Role Outputs, keyed by operation name
|
|
3509
|
+
output "lambda_execution_role_arns" {
|
|
3510
|
+
description = "ARN of each operation's Lambda execution role, keyed by operation name"
|
|
3511
|
+
value = { for op, role in aws_iam_role.lambda_execution_role : op => role.arn }
|
|
2426
3512
|
}
|
|
2427
3513
|
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
value = aws_iam_role.lambda_execution_role.arn
|
|
3514
|
+
output "lambda_execution_role_names" {
|
|
3515
|
+
description = "Name of each operation's Lambda execution role, keyed by operation name. Attach additional policies to a specific operation's role by name."
|
|
3516
|
+
value = { for op, role in aws_iam_role.lambda_execution_role : op => role.name }
|
|
2432
3517
|
}
|
|
2433
3518
|
|
|
2434
|
-
output "
|
|
2435
|
-
description = "
|
|
2436
|
-
value =
|
|
3519
|
+
output "security_group_id" {
|
|
3520
|
+
description = "Security group ID shared by the API Lambda functions, for use in ingress rules on resources they must reach (e.g. a database). Null unless enable_vpc is true."
|
|
3521
|
+
value = var.enable_vpc ? aws_security_group.api_lambda[0].id : null
|
|
2437
3522
|
}
|
|
2438
3523
|
|
|
2439
|
-
# Integration Outputs
|
|
2440
|
-
output "
|
|
2441
|
-
description = "ID of
|
|
2442
|
-
value = aws_api_gateway_integration.lambda_integration.id
|
|
3524
|
+
# Integration Outputs, keyed by operation name
|
|
3525
|
+
output "integration_ids" {
|
|
3526
|
+
description = "ID of each operation's Lambda integration, keyed by operation name"
|
|
3527
|
+
value = { for op, i in aws_api_gateway_integration.lambda_integration : op => i.id }
|
|
2443
3528
|
}
|
|
2444
3529
|
|
|
2445
|
-
output "
|
|
2446
|
-
description = "ID of
|
|
2447
|
-
value =
|
|
3530
|
+
output "method_ids" {
|
|
3531
|
+
description = "ID of each operation's API Gateway method, keyed by operation name"
|
|
3532
|
+
value = { for op, m in aws_api_gateway_method.operation_methods : op => m.id }
|
|
2448
3533
|
}
|
|
2449
3534
|
|
|
2450
|
-
output "
|
|
2451
|
-
description = "ID of
|
|
2452
|
-
value =
|
|
3535
|
+
output "resource_ids" {
|
|
3536
|
+
description = "ID of each API Gateway resource, keyed by its path"
|
|
3537
|
+
value = local.resource_ids
|
|
2453
3538
|
}
|
|
2454
3539
|
|
|
2455
|
-
# CloudWatch Log Groups
|
|
2456
|
-
output "
|
|
2457
|
-
description = "Name of
|
|
2458
|
-
value = aws_cloudwatch_log_group.lambda_logs.name
|
|
3540
|
+
# CloudWatch Log Groups, keyed by operation name
|
|
3541
|
+
output "lambda_log_group_names" {
|
|
3542
|
+
description = "Name of each operation's Lambda CloudWatch log group, keyed by operation name"
|
|
3543
|
+
value = { for op, lg in aws_cloudwatch_log_group.lambda_logs : op => lg.name }
|
|
2459
3544
|
}
|
|
2460
3545
|
|
|
2461
|
-
output "
|
|
2462
|
-
description = "ARN of
|
|
2463
|
-
value = aws_cloudwatch_log_group.lambda_logs.arn
|
|
3546
|
+
output "lambda_log_group_arns" {
|
|
3547
|
+
description = "ARN of each operation's Lambda CloudWatch log group, keyed by operation name"
|
|
3548
|
+
value = { for op, lg in aws_cloudwatch_log_group.lambda_logs : op => lg.arn }
|
|
2464
3549
|
}
|
|
2465
3550
|
",
|
|
2466
3551
|
}
|
|
@@ -2477,11 +3562,11 @@ terraform {
|
|
|
2477
3562
|
required_providers {
|
|
2478
3563
|
aws = {
|
|
2479
3564
|
source = "hashicorp/aws"
|
|
2480
|
-
version = "
|
|
3565
|
+
version = "6.62.0"
|
|
2481
3566
|
}
|
|
2482
3567
|
random = {
|
|
2483
3568
|
source = "hashicorp/random"
|
|
2484
|
-
version = "
|
|
3569
|
+
version = "3.9.0"
|
|
2485
3570
|
}
|
|
2486
3571
|
}
|
|
2487
3572
|
}
|
|
@@ -2551,8 +3636,6 @@ data "aws_caller_identity" "current" {}
|
|
|
2551
3636
|
|
|
2552
3637
|
# Resources
|
|
2553
3638
|
|
|
2554
|
-
# Note: CloudWatch logging removed due to account-level CloudWatch Logs role ARN requirement
|
|
2555
|
-
|
|
2556
3639
|
# REST API Gateway
|
|
2557
3640
|
resource "aws_api_gateway_rest_api" "rest_api" {
|
|
2558
3641
|
name = var.api_name
|
|
@@ -2569,10 +3652,8 @@ resource "aws_api_gateway_rest_api" "rest_api" {
|
|
|
2569
3652
|
tags = var.tags
|
|
2570
3653
|
}
|
|
2571
3654
|
|
|
2572
|
-
# Note: Deployment and
|
|
2573
|
-
# after all methods and integrations are defined
|
|
2574
|
-
|
|
2575
|
-
# Note: CloudWatch Log Group removed due to account-level CloudWatch Logs role ARN requirement
|
|
3655
|
+
# Note: Deployment, stage and access logging are created in the consuming module
|
|
3656
|
+
# (e.g., foo-api.tf) after all methods and integrations are defined
|
|
2576
3657
|
|
|
2577
3658
|
# Gateway Response for CORS (4XX errors)
|
|
2578
3659
|
resource "aws_api_gateway_gateway_response" "cors_4xx" {
|
|
@@ -2674,22 +3755,75 @@ resource "aws_wafv2_web_acl" "api_waf" {
|
|
|
2674
3755
|
}
|
|
2675
3756
|
}
|
|
2676
3757
|
|
|
3758
|
+
resource "random_id" "waf_log_suffix" {
|
|
3759
|
+
count = var.enable_waf ? 1 : 0
|
|
3760
|
+
byte_length = 4
|
|
3761
|
+
}
|
|
3762
|
+
|
|
3763
|
+
locals {
|
|
3764
|
+
waf_log_group_name = var.enable_waf ? "aws-waf-logs-\${var.api_name}-\${random_id.waf_log_suffix[0].hex}" : null
|
|
3765
|
+
}
|
|
3766
|
+
|
|
3767
|
+
# KMS key for encrypting WAF request logs at rest
|
|
3768
|
+
resource "aws_kms_key" "waf_logs" {
|
|
3769
|
+
count = var.enable_waf ? 1 : 0
|
|
3770
|
+
|
|
3771
|
+
description = "\${var.api_name} API WAF log encryption"
|
|
3772
|
+
deletion_window_in_days = 7
|
|
3773
|
+
enable_key_rotation = true
|
|
3774
|
+
|
|
3775
|
+
policy = jsonencode({
|
|
3776
|
+
Version = "2012-10-17"
|
|
3777
|
+
Statement = [
|
|
3778
|
+
{
|
|
3779
|
+
Sid = "Enable IAM User Permissions"
|
|
3780
|
+
Effect = "Allow"
|
|
3781
|
+
Principal = { AWS = "arn:aws:iam::\${data.aws_caller_identity.current.account_id}:root" }
|
|
3782
|
+
Action = "kms:*"
|
|
3783
|
+
Resource = "*"
|
|
3784
|
+
},
|
|
3785
|
+
{
|
|
3786
|
+
Sid = "Allow CloudWatch Logs"
|
|
3787
|
+
Effect = "Allow"
|
|
3788
|
+
Principal = { Service = "logs.\${data.aws_region.current.region}.amazonaws.com" }
|
|
3789
|
+
Action = [
|
|
3790
|
+
"kms:Encrypt",
|
|
3791
|
+
"kms:Decrypt",
|
|
3792
|
+
"kms:ReEncrypt*",
|
|
3793
|
+
"kms:GenerateDataKey*",
|
|
3794
|
+
"kms:DescribeKey"
|
|
3795
|
+
]
|
|
3796
|
+
Resource = "*"
|
|
3797
|
+
Condition = {
|
|
3798
|
+
ArnEquals = {
|
|
3799
|
+
"kms:EncryptionContext:aws:logs:arn" = "arn:aws:logs:\${data.aws_region.current.region}:\${data.aws_caller_identity.current.account_id}:log-group:\${local.waf_log_group_name}"
|
|
3800
|
+
}
|
|
3801
|
+
}
|
|
3802
|
+
}
|
|
3803
|
+
]
|
|
3804
|
+
})
|
|
3805
|
+
|
|
3806
|
+
tags = var.tags
|
|
3807
|
+
}
|
|
3808
|
+
|
|
3809
|
+
resource "aws_kms_alias" "waf_logs" {
|
|
3810
|
+
count = var.enable_waf ? 1 : 0
|
|
3811
|
+
|
|
3812
|
+
name = "alias/\${var.api_name}-\${random_id.waf_log_suffix[0].hex}-waf-logs"
|
|
3813
|
+
target_key_id = aws_kms_key.waf_logs[0].key_id
|
|
3814
|
+
}
|
|
3815
|
+
|
|
2677
3816
|
# CloudWatch Log Group for WAF request logs. Name must start with \`aws-waf-logs-\`.
|
|
2678
3817
|
resource "aws_cloudwatch_log_group" "api_waf_logs" {
|
|
2679
|
-
#checkov:skip=CKV_AWS_158:Using default CloudWatch log encryption
|
|
2680
3818
|
#checkov:skip=CKV_AWS_338:Log retention set to one month which is sufficient for WAF logs
|
|
2681
3819
|
count = var.enable_waf ? 1 : 0
|
|
2682
3820
|
|
|
2683
|
-
name =
|
|
3821
|
+
name = local.waf_log_group_name
|
|
2684
3822
|
retention_in_days = 30
|
|
3823
|
+
kms_key_id = aws_kms_key.waf_logs[0].arn
|
|
2685
3824
|
tags = var.tags
|
|
2686
3825
|
}
|
|
2687
3826
|
|
|
2688
|
-
resource "random_id" "waf_log_suffix" {
|
|
2689
|
-
count = var.enable_waf ? 1 : 0
|
|
2690
|
-
byte_length = 4
|
|
2691
|
-
}
|
|
2692
|
-
|
|
2693
3827
|
resource "aws_wafv2_web_acl_logging_configuration" "api_waf_logging" {
|
|
2694
3828
|
count = var.enable_waf ? 1 : 0
|
|
2695
3829
|
|
|
@@ -2730,16 +3864,22 @@ output "waf_web_acl_arn" {
|
|
|
2730
3864
|
value = var.enable_waf ? aws_wafv2_web_acl.api_waf[0].arn : null
|
|
2731
3865
|
}
|
|
2732
3866
|
|
|
2733
|
-
# Note: Stage and
|
|
2734
|
-
|
|
2735
|
-
# Note: CloudWatch log group outputs removed due to account-level CloudWatch Logs role ARN requirement",
|
|
3867
|
+
# Note: Stage, deployment and access log outputs are provided by the consuming module",
|
|
2736
3868
|
"test-api.tf": "terraform {
|
|
2737
3869
|
required_version = ">= 1.0"
|
|
2738
3870
|
|
|
2739
3871
|
required_providers {
|
|
3872
|
+
archive = {
|
|
3873
|
+
source = "hashicorp/archive"
|
|
3874
|
+
version = "2.8.0"
|
|
3875
|
+
}
|
|
2740
3876
|
aws = {
|
|
2741
3877
|
source = "hashicorp/aws"
|
|
2742
|
-
version = "
|
|
3878
|
+
version = "6.62.0"
|
|
3879
|
+
}
|
|
3880
|
+
random = {
|
|
3881
|
+
source = "hashicorp/random"
|
|
3882
|
+
version = "3.9.0"
|
|
2743
3883
|
}
|
|
2744
3884
|
}
|
|
2745
3885
|
}
|
|
@@ -2761,11 +3901,47 @@ variable "additional_iam_policy_statements" {
|
|
|
2761
3901
|
default = []
|
|
2762
3902
|
}
|
|
2763
3903
|
|
|
3904
|
+
variable "appconfig_application_id" {
|
|
3905
|
+
description = "ID of the shared runtime-config AppConfig application (from \`core/runtime-config/appconfig.application_id\`). When set, the Lambda functions receive \`RUNTIME_CONFIG_APP_ID\` and read access to the application."
|
|
3906
|
+
type = string
|
|
3907
|
+
default = null
|
|
3908
|
+
}
|
|
3909
|
+
|
|
3910
|
+
variable "appconfig_application_arn" {
|
|
3911
|
+
description = "ARN of the shared runtime-config AppConfig application (from \`core/runtime-config/appconfig.application_arn\`). Used to scope the IAM read permission granted to the Lambda functions."
|
|
3912
|
+
type = string
|
|
3913
|
+
default = null
|
|
3914
|
+
}
|
|
3915
|
+
|
|
2764
3916
|
variable "asset_bucket_name" {
|
|
2765
3917
|
description = "Name of the shared asset S3 bucket used to stage the Lambda deployment zip. Instantiate the \`core/asset-bucket\` module once per deployment and pass its \`bucket_name\` output here."
|
|
2766
3918
|
type = string
|
|
2767
3919
|
}
|
|
2768
3920
|
|
|
3921
|
+
# VPC Configuration (optional)
|
|
3922
|
+
variable "enable_vpc" {
|
|
3923
|
+
description = "Deploy the Lambda function into a VPC. Set alongside vpc_id/subnet_ids."
|
|
3924
|
+
type = bool
|
|
3925
|
+
default = false
|
|
3926
|
+
}
|
|
3927
|
+
|
|
3928
|
+
variable "vpc_id" {
|
|
3929
|
+
description = "VPC ID to deploy the Lambda function into. Required when enable_vpc is true."
|
|
3930
|
+
type = string
|
|
3931
|
+
default = null
|
|
3932
|
+
|
|
3933
|
+
validation {
|
|
3934
|
+
condition = !var.enable_vpc || (var.vpc_id != null && var.subnet_ids != null)
|
|
3935
|
+
error_message = "vpc_id and subnet_ids must be set when enable_vpc is true."
|
|
3936
|
+
}
|
|
3937
|
+
}
|
|
3938
|
+
|
|
3939
|
+
variable "subnet_ids" {
|
|
3940
|
+
description = "Subnet IDs to deploy the Lambda function into. Required when enable_vpc is true."
|
|
3941
|
+
type = list(string)
|
|
3942
|
+
default = null
|
|
3943
|
+
}
|
|
3944
|
+
|
|
2769
3945
|
# CORS Configuration (passed to core module)
|
|
2770
3946
|
|
|
2771
3947
|
variable "cors_allow_headers" {
|
|
@@ -2810,6 +3986,235 @@ resource "random_string" "suffix" {
|
|
|
2810
3986
|
upper = false
|
|
2811
3987
|
}
|
|
2812
3988
|
|
|
3989
|
+
locals {
|
|
3990
|
+
# Generated at build time from the API definition
|
|
3991
|
+
operations_file = "\${path.module}/../../../generated/test-api/operations.json"
|
|
3992
|
+
operations = fileexists(local.operations_file) ? jsondecode(file(local.operations_file)) : {}
|
|
3993
|
+
|
|
3994
|
+
operation_slug = { for op in keys(local.operations) : op => replace(op, "/[^a-zA-Z0-9-_]/", "-") }
|
|
3995
|
+
operation_hash = { for op in keys(local.operations) : op => substr(sha256(op), 0, 8) }
|
|
3996
|
+
|
|
3997
|
+
function_name = { for op in keys(local.operations) : op =>
|
|
3998
|
+
"\${substr("TestApi-\${local.operation_slug[op]}", 0, 64 - length(local.operation_hash[op]) - length(random_string.suffix.result) - 2)}-\${local.operation_hash[op]}-\${random_string.suffix.result}"
|
|
3999
|
+
}
|
|
4000
|
+
role_name = { for op in keys(local.operations) : op =>
|
|
4001
|
+
"\${substr("TestApi-\${local.operation_slug[op]}-role", 0, 64 - length(local.operation_hash[op]) - length(random_string.suffix.result) - 2)}-\${local.operation_hash[op]}-\${random_string.suffix.result}"
|
|
4002
|
+
}
|
|
4003
|
+
|
|
4004
|
+
# A REST API needs a resource per path segment, so each operation's path is
|
|
4005
|
+
# split into the distinct path prefixes the resource tree is built from below
|
|
4006
|
+
operation_segments = { for op, details in local.operations : op => compact(split("/", details.path)) }
|
|
4007
|
+
|
|
4008
|
+
path_nodes = merge([
|
|
4009
|
+
for op, segments in local.operation_segments : {
|
|
4010
|
+
for i, segment in segments : join("/", slice(segments, 0, i + 1)) => {
|
|
4011
|
+
depth = i
|
|
4012
|
+
parent = i == 0 ? "" : join("/", slice(segments, 0, i))
|
|
4013
|
+
part = segment
|
|
4014
|
+
}
|
|
4015
|
+
}
|
|
4016
|
+
]...)
|
|
4017
|
+
|
|
4018
|
+
# Instances of a resource cannot reference one another, so each depth is a
|
|
4019
|
+
# separate resource. Deeper paths are reported by the precondition below.
|
|
4020
|
+
max_path_depth = 16
|
|
4021
|
+
path_nodes_by_depth = { for depth in range(local.max_path_depth) : depth => {
|
|
4022
|
+
for path, node in local.path_nodes : path => node if node.depth == depth
|
|
4023
|
+
} }
|
|
4024
|
+
paths_too_deep = [for path, node in local.path_nodes : path if node.depth >= local.max_path_depth]
|
|
4025
|
+
|
|
4026
|
+
resource_ids = merge(
|
|
4027
|
+
{ for path, resource in aws_api_gateway_resource.path_depth_0 : path => resource.id },
|
|
4028
|
+
{ for path, resource in aws_api_gateway_resource.path_depth_1 : path => resource.id },
|
|
4029
|
+
{ for path, resource in aws_api_gateway_resource.path_depth_2 : path => resource.id },
|
|
4030
|
+
{ for path, resource in aws_api_gateway_resource.path_depth_3 : path => resource.id },
|
|
4031
|
+
{ for path, resource in aws_api_gateway_resource.path_depth_4 : path => resource.id },
|
|
4032
|
+
{ for path, resource in aws_api_gateway_resource.path_depth_5 : path => resource.id },
|
|
4033
|
+
{ for path, resource in aws_api_gateway_resource.path_depth_6 : path => resource.id },
|
|
4034
|
+
{ for path, resource in aws_api_gateway_resource.path_depth_7 : path => resource.id },
|
|
4035
|
+
{ for path, resource in aws_api_gateway_resource.path_depth_8 : path => resource.id },
|
|
4036
|
+
{ for path, resource in aws_api_gateway_resource.path_depth_9 : path => resource.id },
|
|
4037
|
+
{ for path, resource in aws_api_gateway_resource.path_depth_10 : path => resource.id },
|
|
4038
|
+
{ for path, resource in aws_api_gateway_resource.path_depth_11 : path => resource.id },
|
|
4039
|
+
{ for path, resource in aws_api_gateway_resource.path_depth_12 : path => resource.id },
|
|
4040
|
+
{ for path, resource in aws_api_gateway_resource.path_depth_13 : path => resource.id },
|
|
4041
|
+
{ for path, resource in aws_api_gateway_resource.path_depth_14 : path => resource.id },
|
|
4042
|
+
{ for path, resource in aws_api_gateway_resource.path_depth_15 : path => resource.id },
|
|
4043
|
+
)
|
|
4044
|
+
|
|
4045
|
+
operation_resource_id = { for op, segments in local.operation_segments : op =>
|
|
4046
|
+
local.resource_ids[join("/", segments)]
|
|
4047
|
+
}
|
|
4048
|
+
|
|
4049
|
+
permission_source_suffix = { for op, details in local.operations : op =>
|
|
4050
|
+
"\${upper(details.method)}/\${replace(join("/", local.operation_segments[op]), "/{[^}]*}/", "*")}"
|
|
4051
|
+
}
|
|
4052
|
+
}
|
|
4053
|
+
|
|
4054
|
+
resource "terraform_data" "operations_metadata" {
|
|
4055
|
+
# Fails the plan when the operations metadata has not been generated
|
|
4056
|
+
input = local.operations_file
|
|
4057
|
+
|
|
4058
|
+
lifecycle {
|
|
4059
|
+
precondition {
|
|
4060
|
+
condition = fileexists(local.operations_file)
|
|
4061
|
+
error_message = "Operations metadata not found at \${local.operations_file}. Build the TestApi project to generate it."
|
|
4062
|
+
}
|
|
4063
|
+
precondition {
|
|
4064
|
+
condition = length(local.operations) > 0
|
|
4065
|
+
error_message = "No operations found in \${local.operations_file}. The TestApi API must define at least one operation."
|
|
4066
|
+
}
|
|
4067
|
+
precondition {
|
|
4068
|
+
condition = length(local.paths_too_deep) == 0
|
|
4069
|
+
error_message = "Operation paths exceed the supported depth of \${local.max_path_depth} segments: \${join(", ", local.paths_too_deep)}. Add further aws_api_gateway_resource levels to this module to support them."
|
|
4070
|
+
}
|
|
4071
|
+
}
|
|
4072
|
+
}
|
|
4073
|
+
|
|
4074
|
+
# API Gateway resources at path depth 0
|
|
4075
|
+
resource "aws_api_gateway_resource" "path_depth_0" {
|
|
4076
|
+
for_each = local.path_nodes_by_depth[0]
|
|
4077
|
+
|
|
4078
|
+
rest_api_id = module.rest_api.api_id
|
|
4079
|
+
parent_id = module.rest_api.api_root_resource_id
|
|
4080
|
+
path_part = each.value.part
|
|
4081
|
+
}
|
|
4082
|
+
|
|
4083
|
+
# API Gateway resources at path depth 1
|
|
4084
|
+
resource "aws_api_gateway_resource" "path_depth_1" {
|
|
4085
|
+
for_each = local.path_nodes_by_depth[1]
|
|
4086
|
+
|
|
4087
|
+
rest_api_id = module.rest_api.api_id
|
|
4088
|
+
parent_id = aws_api_gateway_resource.path_depth_0[each.value.parent].id
|
|
4089
|
+
path_part = each.value.part
|
|
4090
|
+
}
|
|
4091
|
+
|
|
4092
|
+
# API Gateway resources at path depth 2
|
|
4093
|
+
resource "aws_api_gateway_resource" "path_depth_2" {
|
|
4094
|
+
for_each = local.path_nodes_by_depth[2]
|
|
4095
|
+
|
|
4096
|
+
rest_api_id = module.rest_api.api_id
|
|
4097
|
+
parent_id = aws_api_gateway_resource.path_depth_1[each.value.parent].id
|
|
4098
|
+
path_part = each.value.part
|
|
4099
|
+
}
|
|
4100
|
+
|
|
4101
|
+
# API Gateway resources at path depth 3
|
|
4102
|
+
resource "aws_api_gateway_resource" "path_depth_3" {
|
|
4103
|
+
for_each = local.path_nodes_by_depth[3]
|
|
4104
|
+
|
|
4105
|
+
rest_api_id = module.rest_api.api_id
|
|
4106
|
+
parent_id = aws_api_gateway_resource.path_depth_2[each.value.parent].id
|
|
4107
|
+
path_part = each.value.part
|
|
4108
|
+
}
|
|
4109
|
+
|
|
4110
|
+
# API Gateway resources at path depth 4
|
|
4111
|
+
resource "aws_api_gateway_resource" "path_depth_4" {
|
|
4112
|
+
for_each = local.path_nodes_by_depth[4]
|
|
4113
|
+
|
|
4114
|
+
rest_api_id = module.rest_api.api_id
|
|
4115
|
+
parent_id = aws_api_gateway_resource.path_depth_3[each.value.parent].id
|
|
4116
|
+
path_part = each.value.part
|
|
4117
|
+
}
|
|
4118
|
+
|
|
4119
|
+
# API Gateway resources at path depth 5
|
|
4120
|
+
resource "aws_api_gateway_resource" "path_depth_5" {
|
|
4121
|
+
for_each = local.path_nodes_by_depth[5]
|
|
4122
|
+
|
|
4123
|
+
rest_api_id = module.rest_api.api_id
|
|
4124
|
+
parent_id = aws_api_gateway_resource.path_depth_4[each.value.parent].id
|
|
4125
|
+
path_part = each.value.part
|
|
4126
|
+
}
|
|
4127
|
+
|
|
4128
|
+
# API Gateway resources at path depth 6
|
|
4129
|
+
resource "aws_api_gateway_resource" "path_depth_6" {
|
|
4130
|
+
for_each = local.path_nodes_by_depth[6]
|
|
4131
|
+
|
|
4132
|
+
rest_api_id = module.rest_api.api_id
|
|
4133
|
+
parent_id = aws_api_gateway_resource.path_depth_5[each.value.parent].id
|
|
4134
|
+
path_part = each.value.part
|
|
4135
|
+
}
|
|
4136
|
+
|
|
4137
|
+
# API Gateway resources at path depth 7
|
|
4138
|
+
resource "aws_api_gateway_resource" "path_depth_7" {
|
|
4139
|
+
for_each = local.path_nodes_by_depth[7]
|
|
4140
|
+
|
|
4141
|
+
rest_api_id = module.rest_api.api_id
|
|
4142
|
+
parent_id = aws_api_gateway_resource.path_depth_6[each.value.parent].id
|
|
4143
|
+
path_part = each.value.part
|
|
4144
|
+
}
|
|
4145
|
+
|
|
4146
|
+
# API Gateway resources at path depth 8
|
|
4147
|
+
resource "aws_api_gateway_resource" "path_depth_8" {
|
|
4148
|
+
for_each = local.path_nodes_by_depth[8]
|
|
4149
|
+
|
|
4150
|
+
rest_api_id = module.rest_api.api_id
|
|
4151
|
+
parent_id = aws_api_gateway_resource.path_depth_7[each.value.parent].id
|
|
4152
|
+
path_part = each.value.part
|
|
4153
|
+
}
|
|
4154
|
+
|
|
4155
|
+
# API Gateway resources at path depth 9
|
|
4156
|
+
resource "aws_api_gateway_resource" "path_depth_9" {
|
|
4157
|
+
for_each = local.path_nodes_by_depth[9]
|
|
4158
|
+
|
|
4159
|
+
rest_api_id = module.rest_api.api_id
|
|
4160
|
+
parent_id = aws_api_gateway_resource.path_depth_8[each.value.parent].id
|
|
4161
|
+
path_part = each.value.part
|
|
4162
|
+
}
|
|
4163
|
+
|
|
4164
|
+
# API Gateway resources at path depth 10
|
|
4165
|
+
resource "aws_api_gateway_resource" "path_depth_10" {
|
|
4166
|
+
for_each = local.path_nodes_by_depth[10]
|
|
4167
|
+
|
|
4168
|
+
rest_api_id = module.rest_api.api_id
|
|
4169
|
+
parent_id = aws_api_gateway_resource.path_depth_9[each.value.parent].id
|
|
4170
|
+
path_part = each.value.part
|
|
4171
|
+
}
|
|
4172
|
+
|
|
4173
|
+
# API Gateway resources at path depth 11
|
|
4174
|
+
resource "aws_api_gateway_resource" "path_depth_11" {
|
|
4175
|
+
for_each = local.path_nodes_by_depth[11]
|
|
4176
|
+
|
|
4177
|
+
rest_api_id = module.rest_api.api_id
|
|
4178
|
+
parent_id = aws_api_gateway_resource.path_depth_10[each.value.parent].id
|
|
4179
|
+
path_part = each.value.part
|
|
4180
|
+
}
|
|
4181
|
+
|
|
4182
|
+
# API Gateway resources at path depth 12
|
|
4183
|
+
resource "aws_api_gateway_resource" "path_depth_12" {
|
|
4184
|
+
for_each = local.path_nodes_by_depth[12]
|
|
4185
|
+
|
|
4186
|
+
rest_api_id = module.rest_api.api_id
|
|
4187
|
+
parent_id = aws_api_gateway_resource.path_depth_11[each.value.parent].id
|
|
4188
|
+
path_part = each.value.part
|
|
4189
|
+
}
|
|
4190
|
+
|
|
4191
|
+
# API Gateway resources at path depth 13
|
|
4192
|
+
resource "aws_api_gateway_resource" "path_depth_13" {
|
|
4193
|
+
for_each = local.path_nodes_by_depth[13]
|
|
4194
|
+
|
|
4195
|
+
rest_api_id = module.rest_api.api_id
|
|
4196
|
+
parent_id = aws_api_gateway_resource.path_depth_12[each.value.parent].id
|
|
4197
|
+
path_part = each.value.part
|
|
4198
|
+
}
|
|
4199
|
+
|
|
4200
|
+
# API Gateway resources at path depth 14
|
|
4201
|
+
resource "aws_api_gateway_resource" "path_depth_14" {
|
|
4202
|
+
for_each = local.path_nodes_by_depth[14]
|
|
4203
|
+
|
|
4204
|
+
rest_api_id = module.rest_api.api_id
|
|
4205
|
+
parent_id = aws_api_gateway_resource.path_depth_13[each.value.parent].id
|
|
4206
|
+
path_part = each.value.part
|
|
4207
|
+
}
|
|
4208
|
+
|
|
4209
|
+
# API Gateway resources at path depth 15
|
|
4210
|
+
resource "aws_api_gateway_resource" "path_depth_15" {
|
|
4211
|
+
for_each = local.path_nodes_by_depth[15]
|
|
4212
|
+
|
|
4213
|
+
rest_api_id = module.rest_api.api_id
|
|
4214
|
+
parent_id = aws_api_gateway_resource.path_depth_14[each.value.parent].id
|
|
4215
|
+
path_part = each.value.part
|
|
4216
|
+
}
|
|
4217
|
+
|
|
2813
4218
|
# Resources
|
|
2814
4219
|
|
|
2815
4220
|
# Create Lambda ZIP file from the bundle directory
|
|
@@ -2828,6 +4233,11 @@ resource "aws_s3_object" "lambda_zip" {
|
|
|
2828
4233
|
}
|
|
2829
4234
|
|
|
2830
4235
|
# Use the core REST API module
|
|
4236
|
+
# Account-level CloudWatch role required for REST API access logging
|
|
4237
|
+
module "account" {
|
|
4238
|
+
source = "../../../core/api/api-gateway-account"
|
|
4239
|
+
}
|
|
4240
|
+
|
|
2831
4241
|
module "rest_api" {
|
|
2832
4242
|
source = "../../../core/api/rest-api"
|
|
2833
4243
|
|
|
@@ -2857,9 +4267,33 @@ resource "aws_wafv2_web_acl_association" "api_waf_association" {
|
|
|
2857
4267
|
depends_on = [aws_api_gateway_stage.api_stage]
|
|
2858
4268
|
}
|
|
2859
4269
|
|
|
2860
|
-
# Lambda function
|
|
4270
|
+
# Security group for the API Lambda function, used when deployed into a VPC
|
|
4271
|
+
resource "aws_security_group" "api_lambda" {
|
|
4272
|
+
count = var.enable_vpc ? 1 : 0
|
|
4273
|
+
|
|
4274
|
+
#checkov:skip=CKV2_AWS_5:Attached to api_lambda via vpc_config block; Checkov cannot resolve this reference
|
|
4275
|
+
name_prefix = "test-api-lambda-"
|
|
4276
|
+
description = "Security group for the TestApi API Lambda function"
|
|
4277
|
+
vpc_id = var.vpc_id
|
|
4278
|
+
tags = var.tags
|
|
4279
|
+
}
|
|
4280
|
+
|
|
4281
|
+
resource "aws_vpc_security_group_egress_rule" "api_lambda_https" {
|
|
4282
|
+
count = var.enable_vpc ? 1 : 0
|
|
4283
|
+
|
|
4284
|
+
security_group_id = aws_security_group.api_lambda[0].id
|
|
4285
|
+
cidr_ipv4 = "0.0.0.0/0"
|
|
4286
|
+
from_port = 443
|
|
4287
|
+
to_port = 443
|
|
4288
|
+
ip_protocol = "tcp"
|
|
4289
|
+
description = "Allow outbound HTTPS to AWS service endpoints"
|
|
4290
|
+
}
|
|
4291
|
+
|
|
2861
4292
|
resource "aws_lambda_function" "api_lambda" {
|
|
2862
|
-
#
|
|
4293
|
+
# One lambda function per operation, each serving just that operation
|
|
4294
|
+
for_each = local.operations
|
|
4295
|
+
|
|
4296
|
+
#checkov:skip=CKV_AWS_117:Lambda function is optionally deployed into a VPC via vpc_id/subnet_ids; not required for this use case
|
|
2863
4297
|
#checkov:skip=CKV_AWS_116:Dead Letter Queue not required for this simple API use case
|
|
2864
4298
|
#checkov:skip=CKV_AWS_272:Code signing not required for this use case
|
|
2865
4299
|
#checkov:skip=CKV_AWS_115:Concurrent execution limit not required for this use case
|
|
@@ -2867,10 +4301,10 @@ resource "aws_lambda_function" "api_lambda" {
|
|
|
2867
4301
|
s3_bucket = aws_s3_object.lambda_zip.bucket
|
|
2868
4302
|
s3_key = aws_s3_object.lambda_zip.key
|
|
2869
4303
|
s3_object_version = aws_s3_object.lambda_zip.version_id
|
|
2870
|
-
function_name =
|
|
2871
|
-
role = aws_iam_role.lambda_execution_role.arn
|
|
4304
|
+
function_name = local.function_name[each.key]
|
|
4305
|
+
role = aws_iam_role.lambda_execution_role[each.key].arn
|
|
2872
4306
|
handler = "index.handler"
|
|
2873
|
-
runtime = "
|
|
4307
|
+
runtime = "nodejs24.x"
|
|
2874
4308
|
timeout = 30
|
|
2875
4309
|
memory_size = 128
|
|
2876
4310
|
|
|
@@ -2881,18 +4315,32 @@ resource "aws_lambda_function" "api_lambda" {
|
|
|
2881
4315
|
mode = "Active"
|
|
2882
4316
|
}
|
|
2883
4317
|
|
|
4318
|
+
dynamic "vpc_config" {
|
|
4319
|
+
for_each = var.enable_vpc ? [1] : []
|
|
4320
|
+
content {
|
|
4321
|
+
subnet_ids = var.subnet_ids
|
|
4322
|
+
security_group_ids = [aws_security_group.api_lambda[0].id]
|
|
4323
|
+
}
|
|
4324
|
+
}
|
|
4325
|
+
|
|
2884
4326
|
|
|
2885
4327
|
environment {
|
|
2886
4328
|
variables = merge({
|
|
2887
|
-
}, var.
|
|
4329
|
+
}, var.appconfig_application_id != null ? {
|
|
4330
|
+
RUNTIME_CONFIG_APP_ID = var.appconfig_application_id
|
|
4331
|
+
} : {}, var.env)
|
|
2888
4332
|
}
|
|
2889
4333
|
|
|
2890
4334
|
tags = var.tags
|
|
4335
|
+
|
|
4336
|
+
depends_on = [aws_iam_role_policy_attachment.lambda_vpc_access]
|
|
2891
4337
|
}
|
|
2892
4338
|
|
|
2893
4339
|
# IAM role for Lambda execution
|
|
2894
4340
|
resource "aws_iam_role" "lambda_execution_role" {
|
|
2895
|
-
|
|
4341
|
+
for_each = local.operations
|
|
4342
|
+
|
|
4343
|
+
name = local.role_name[each.key]
|
|
2896
4344
|
|
|
2897
4345
|
assume_role_policy = jsonencode({
|
|
2898
4346
|
Version = "2012-10-17"
|
|
@@ -2912,90 +4360,132 @@ resource "aws_iam_role" "lambda_execution_role" {
|
|
|
2912
4360
|
|
|
2913
4361
|
# Attach basic execution policy to Lambda role
|
|
2914
4362
|
resource "aws_iam_role_policy_attachment" "lambda_basic_execution" {
|
|
4363
|
+
for_each = local.operations
|
|
4364
|
+
|
|
2915
4365
|
policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
|
|
2916
|
-
role = aws_iam_role.lambda_execution_role.name
|
|
4366
|
+
role = aws_iam_role.lambda_execution_role[each.key].name
|
|
2917
4367
|
}
|
|
2918
4368
|
|
|
2919
4369
|
# Attach X-Ray tracing policy to Lambda role
|
|
2920
4370
|
resource "aws_iam_role_policy_attachment" "lambda_xray_execution" {
|
|
4371
|
+
for_each = local.operations
|
|
4372
|
+
|
|
2921
4373
|
policy_arn = "arn:aws:iam::aws:policy/AWSXRayDaemonWriteAccess"
|
|
2922
|
-
role = aws_iam_role.lambda_execution_role.name
|
|
4374
|
+
role = aws_iam_role.lambda_execution_role[each.key].name
|
|
4375
|
+
}
|
|
4376
|
+
|
|
4377
|
+
# Attach VPC access policy to Lambda role when deployed into a VPC
|
|
4378
|
+
resource "aws_iam_role_policy_attachment" "lambda_vpc_access" {
|
|
4379
|
+
for_each = var.enable_vpc ? local.operations : {}
|
|
4380
|
+
|
|
4381
|
+
policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole"
|
|
4382
|
+
role = aws_iam_role.lambda_execution_role[each.key].name
|
|
2923
4383
|
}
|
|
2924
4384
|
|
|
2925
4385
|
# Additional IAM policies for Lambda (if provided)
|
|
2926
4386
|
resource "aws_iam_role_policy" "lambda_additional_policies" {
|
|
2927
|
-
|
|
2928
|
-
|
|
2929
|
-
|
|
4387
|
+
for_each = local.operations
|
|
4388
|
+
|
|
4389
|
+
name = "\${substr(local.function_name[each.key], 0, 55)}-policies"
|
|
4390
|
+
role = aws_iam_role.lambda_execution_role[each.key].id
|
|
2930
4391
|
|
|
2931
4392
|
policy = jsonencode({
|
|
2932
4393
|
Version = "2012-10-17"
|
|
2933
|
-
Statement =
|
|
4394
|
+
Statement = local.lambda_policy_document_statements
|
|
2934
4395
|
})
|
|
2935
4396
|
}
|
|
2936
4397
|
|
|
4398
|
+
locals {
|
|
4399
|
+
# Grant read access to the runtime-config AppConfig application when wired
|
|
4400
|
+
lambda_policy_statements = concat(var.appconfig_application_arn != null ? [
|
|
4401
|
+
{
|
|
4402
|
+
Effect = "Allow"
|
|
4403
|
+
Action = [
|
|
4404
|
+
"appconfig:StartConfigurationSession",
|
|
4405
|
+
"appconfig:GetLatestConfiguration"
|
|
4406
|
+
]
|
|
4407
|
+
Resource = ["\${var.appconfig_application_arn}/*"]
|
|
4408
|
+
}
|
|
4409
|
+
] : [], var.additional_iam_policy_statements)
|
|
4410
|
+
|
|
4411
|
+
# IAM rejects an empty statement list, so fall back to a no-op deny
|
|
4412
|
+
lambda_policy_document_statements = length(local.lambda_policy_statements) > 0 ? local.lambda_policy_statements : [
|
|
4413
|
+
{
|
|
4414
|
+
Effect = "Deny"
|
|
4415
|
+
Action = ["appconfig:GetLatestConfiguration"]
|
|
4416
|
+
Resource = ["arn:aws:appconfig:\${data.aws_region.current.region}:\${data.aws_caller_identity.current.account_id}:application/none"]
|
|
4417
|
+
}
|
|
4418
|
+
]
|
|
4419
|
+
}
|
|
4420
|
+
|
|
2937
4421
|
# CloudWatch Log Group for Lambda
|
|
2938
4422
|
resource "aws_cloudwatch_log_group" "lambda_logs" {
|
|
2939
4423
|
#checkov:skip=CKV_AWS_158:Using default CloudWatch log encryption
|
|
2940
4424
|
#checkov:skip=CKV_AWS_338:Log retention set to forever
|
|
2941
4425
|
#checkov:skip=CKV_AWS_66:Log retention set to forever
|
|
2942
|
-
|
|
2943
|
-
tags = var.tags
|
|
2944
|
-
}
|
|
4426
|
+
for_each = local.operations
|
|
2945
4427
|
|
|
2946
|
-
|
|
2947
|
-
|
|
2948
|
-
# Create proxy resource (captures all paths)
|
|
2949
|
-
resource "aws_api_gateway_resource" "proxy_resource" {
|
|
2950
|
-
rest_api_id = module.rest_api.api_id
|
|
2951
|
-
parent_id = module.rest_api.api_root_resource_id
|
|
2952
|
-
path_part = "{proxy+}"
|
|
4428
|
+
name = "/aws/lambda/\${local.function_name[each.key]}"
|
|
4429
|
+
tags = var.tags
|
|
2953
4430
|
}
|
|
2954
4431
|
|
|
2955
|
-
# Lambda integration for REST API
|
|
2956
|
-
resource "aws_api_gateway_integration" "lambda_integration" {
|
|
2957
|
-
rest_api_id = module.rest_api.api_id
|
|
2958
|
-
resource_id = aws_api_gateway_resource.proxy_resource.id
|
|
2959
|
-
http_method = aws_api_gateway_method.proxy_method.http_method
|
|
2960
4432
|
|
|
2961
|
-
integration_http_method = "POST"
|
|
2962
|
-
type = "AWS_PROXY"
|
|
2963
|
-
uri = aws_lambda_function.api_lambda.invoke_arn
|
|
2964
|
-
|
|
2965
|
-
depends_on = [aws_lambda_function.api_lambda]
|
|
2966
|
-
}
|
|
2967
4433
|
|
|
2968
|
-
# Method
|
|
2969
|
-
resource "aws_api_gateway_method" "
|
|
4434
|
+
# Method per operation
|
|
4435
|
+
resource "aws_api_gateway_method" "operation_methods" {
|
|
2970
4436
|
#checkov:skip=CKV2_AWS_53:Request validation not required for proxy integration as Lambda handles validation
|
|
4437
|
+
for_each = local.operations
|
|
4438
|
+
|
|
2971
4439
|
rest_api_id = module.rest_api.api_id
|
|
2972
|
-
resource_id =
|
|
2973
|
-
http_method =
|
|
4440
|
+
resource_id = local.operation_resource_id[each.key]
|
|
4441
|
+
http_method = upper(each.value.method)
|
|
2974
4442
|
|
|
2975
4443
|
authorization = "AWS_IAM"
|
|
2976
4444
|
|
|
4445
|
+
# Path parameters must be declared on the method
|
|
2977
4446
|
request_parameters = {
|
|
2978
|
-
|
|
4447
|
+
for segment in local.operation_segments[each.key] :
|
|
4448
|
+
"method.request.path.\${trimsuffix(trimprefix(segment, "{"), "}")}" => true
|
|
4449
|
+
if startswith(segment, "{")
|
|
2979
4450
|
}
|
|
2980
4451
|
|
|
2981
4452
|
depends_on = []
|
|
2982
4453
|
}
|
|
2983
4454
|
|
|
2984
|
-
#
|
|
4455
|
+
# Lambda integration per operation
|
|
4456
|
+
resource "aws_api_gateway_integration" "lambda_integration" {
|
|
4457
|
+
for_each = local.operations
|
|
4458
|
+
|
|
4459
|
+
rest_api_id = module.rest_api.api_id
|
|
4460
|
+
resource_id = local.operation_resource_id[each.key]
|
|
4461
|
+
http_method = aws_api_gateway_method.operation_methods[each.key].http_method
|
|
4462
|
+
|
|
4463
|
+
integration_http_method = "POST"
|
|
4464
|
+
type = "AWS_PROXY"
|
|
4465
|
+
uri = aws_lambda_function.api_lambda[each.key].invoke_arn
|
|
4466
|
+
|
|
4467
|
+
depends_on = [aws_lambda_function.api_lambda]
|
|
4468
|
+
}
|
|
4469
|
+
|
|
4470
|
+
# OPTIONS method for CORS preflight, on every resource an operation is served from
|
|
2985
4471
|
resource "aws_api_gateway_method" "options_method" {
|
|
2986
4472
|
#checkov:skip=CKV2_AWS_70:OPTIONS method must be unauthenticated for CORS preflight requests
|
|
2987
4473
|
#checkov:skip=CKV2_AWS_53:Request validation not required for OPTIONS CORS preflight method
|
|
4474
|
+
for_each = local.resource_ids
|
|
4475
|
+
|
|
2988
4476
|
rest_api_id = module.rest_api.api_id
|
|
2989
|
-
resource_id =
|
|
4477
|
+
resource_id = each.value
|
|
2990
4478
|
http_method = "OPTIONS"
|
|
2991
4479
|
authorization = "NONE"
|
|
2992
4480
|
}
|
|
2993
4481
|
|
|
2994
|
-
# CORS integration for OPTIONS
|
|
4482
|
+
# CORS integration for OPTIONS methods
|
|
2995
4483
|
resource "aws_api_gateway_integration" "options_integration" {
|
|
4484
|
+
for_each = local.resource_ids
|
|
4485
|
+
|
|
2996
4486
|
rest_api_id = module.rest_api.api_id
|
|
2997
|
-
resource_id =
|
|
2998
|
-
http_method = aws_api_gateway_method.options_method.http_method
|
|
4487
|
+
resource_id = each.value
|
|
4488
|
+
http_method = aws_api_gateway_method.options_method[each.key].http_method
|
|
2999
4489
|
|
|
3000
4490
|
type = "MOCK"
|
|
3001
4491
|
request_templates = {
|
|
@@ -3003,11 +4493,13 @@ resource "aws_api_gateway_integration" "options_integration" {
|
|
|
3003
4493
|
}
|
|
3004
4494
|
}
|
|
3005
4495
|
|
|
3006
|
-
# OPTIONS method
|
|
4496
|
+
# OPTIONS method responses
|
|
3007
4497
|
resource "aws_api_gateway_method_response" "options_response" {
|
|
4498
|
+
for_each = local.resource_ids
|
|
4499
|
+
|
|
3008
4500
|
rest_api_id = module.rest_api.api_id
|
|
3009
|
-
resource_id =
|
|
3010
|
-
http_method = aws_api_gateway_method.options_method.http_method
|
|
4501
|
+
resource_id = each.value
|
|
4502
|
+
http_method = aws_api_gateway_method.options_method[each.key].http_method
|
|
3011
4503
|
status_code = "204"
|
|
3012
4504
|
|
|
3013
4505
|
response_parameters = {
|
|
@@ -3017,18 +4509,22 @@ resource "aws_api_gateway_method_response" "options_response" {
|
|
|
3017
4509
|
}
|
|
3018
4510
|
}
|
|
3019
4511
|
|
|
3020
|
-
# OPTIONS integration
|
|
4512
|
+
# OPTIONS integration responses
|
|
3021
4513
|
resource "aws_api_gateway_integration_response" "options_integration_response" {
|
|
4514
|
+
for_each = local.resource_ids
|
|
4515
|
+
|
|
3022
4516
|
rest_api_id = module.rest_api.api_id
|
|
3023
|
-
resource_id =
|
|
3024
|
-
http_method = aws_api_gateway_method.options_method.http_method
|
|
3025
|
-
status_code = aws_api_gateway_method_response.options_response.status_code
|
|
4517
|
+
resource_id = each.value
|
|
4518
|
+
http_method = aws_api_gateway_method.options_method[each.key].http_method
|
|
4519
|
+
status_code = aws_api_gateway_method_response.options_response[each.key].status_code
|
|
3026
4520
|
|
|
3027
4521
|
response_parameters = {
|
|
3028
4522
|
"method.response.header.Access-Control-Allow-Headers" = "'\${join(",", var.cors_allow_headers)}'"
|
|
3029
4523
|
"method.response.header.Access-Control-Allow-Methods" = "'\${join(",", var.cors_allow_methods)}'"
|
|
3030
4524
|
"method.response.header.Access-Control-Allow-Origin" = "'\${join(",", var.cors_allow_origins)}'"
|
|
3031
4525
|
}
|
|
4526
|
+
|
|
4527
|
+
depends_on = [aws_api_gateway_integration.options_integration]
|
|
3032
4528
|
}
|
|
3033
4529
|
|
|
3034
4530
|
# API Gateway deployment
|
|
@@ -3036,13 +4532,28 @@ resource "aws_api_gateway_deployment" "api_deployment" {
|
|
|
3036
4532
|
rest_api_id = module.rest_api.api_id
|
|
3037
4533
|
|
|
3038
4534
|
triggers = {
|
|
3039
|
-
redeployment = sha1(jsonencode(
|
|
3040
|
-
aws_api_gateway_resource.
|
|
3041
|
-
|
|
3042
|
-
|
|
3043
|
-
|
|
3044
|
-
|
|
3045
|
-
|
|
4535
|
+
redeployment = sha1(jsonencode(concat(
|
|
4536
|
+
[for r in aws_api_gateway_resource.path_depth_0 : r.id],
|
|
4537
|
+
[for r in aws_api_gateway_resource.path_depth_1 : r.id],
|
|
4538
|
+
[for r in aws_api_gateway_resource.path_depth_2 : r.id],
|
|
4539
|
+
[for r in aws_api_gateway_resource.path_depth_3 : r.id],
|
|
4540
|
+
[for r in aws_api_gateway_resource.path_depth_4 : r.id],
|
|
4541
|
+
[for r in aws_api_gateway_resource.path_depth_5 : r.id],
|
|
4542
|
+
[for r in aws_api_gateway_resource.path_depth_6 : r.id],
|
|
4543
|
+
[for r in aws_api_gateway_resource.path_depth_7 : r.id],
|
|
4544
|
+
[for r in aws_api_gateway_resource.path_depth_8 : r.id],
|
|
4545
|
+
[for r in aws_api_gateway_resource.path_depth_9 : r.id],
|
|
4546
|
+
[for r in aws_api_gateway_resource.path_depth_10 : r.id],
|
|
4547
|
+
[for r in aws_api_gateway_resource.path_depth_11 : r.id],
|
|
4548
|
+
[for r in aws_api_gateway_resource.path_depth_12 : r.id],
|
|
4549
|
+
[for r in aws_api_gateway_resource.path_depth_13 : r.id],
|
|
4550
|
+
[for r in aws_api_gateway_resource.path_depth_14 : r.id],
|
|
4551
|
+
[for r in aws_api_gateway_resource.path_depth_15 : r.id],
|
|
4552
|
+
[for m in aws_api_gateway_method.operation_methods : m.id],
|
|
4553
|
+
[for i in aws_api_gateway_integration.lambda_integration : i.id],
|
|
4554
|
+
[for m in aws_api_gateway_method.options_method : m.id],
|
|
4555
|
+
[for i in aws_api_gateway_integration.options_integration : i.id],
|
|
4556
|
+
)))
|
|
3046
4557
|
}
|
|
3047
4558
|
|
|
3048
4559
|
lifecycle {
|
|
@@ -3050,7 +4561,7 @@ resource "aws_api_gateway_deployment" "api_deployment" {
|
|
|
3050
4561
|
}
|
|
3051
4562
|
|
|
3052
4563
|
depends_on = [
|
|
3053
|
-
aws_api_gateway_method.
|
|
4564
|
+
aws_api_gateway_method.operation_methods,
|
|
3054
4565
|
aws_api_gateway_integration.lambda_integration,
|
|
3055
4566
|
aws_api_gateway_method.options_method,
|
|
3056
4567
|
aws_api_gateway_integration.options_integration,
|
|
@@ -3059,11 +4570,63 @@ resource "aws_api_gateway_deployment" "api_deployment" {
|
|
|
3059
4570
|
]
|
|
3060
4571
|
}
|
|
3061
4572
|
|
|
4573
|
+
# KMS key for encrypting access logs at rest
|
|
4574
|
+
resource "aws_kms_key" "access_logs" {
|
|
4575
|
+
description = "TestApi API access log encryption"
|
|
4576
|
+
deletion_window_in_days = 7
|
|
4577
|
+
enable_key_rotation = true
|
|
4578
|
+
|
|
4579
|
+
policy = jsonencode({
|
|
4580
|
+
Version = "2012-10-17"
|
|
4581
|
+
Statement = [
|
|
4582
|
+
{
|
|
4583
|
+
Sid = "Enable IAM User Permissions"
|
|
4584
|
+
Effect = "Allow"
|
|
4585
|
+
Principal = { AWS = "arn:aws:iam::\${data.aws_caller_identity.current.account_id}:root" }
|
|
4586
|
+
Action = "kms:*"
|
|
4587
|
+
Resource = "*"
|
|
4588
|
+
},
|
|
4589
|
+
{
|
|
4590
|
+
Sid = "Allow CloudWatch Logs"
|
|
4591
|
+
Effect = "Allow"
|
|
4592
|
+
Principal = { Service = "logs.\${data.aws_region.current.region}.amazonaws.com" }
|
|
4593
|
+
Action = [
|
|
4594
|
+
"kms:Encrypt",
|
|
4595
|
+
"kms:Decrypt",
|
|
4596
|
+
"kms:ReEncrypt*",
|
|
4597
|
+
"kms:GenerateDataKey*",
|
|
4598
|
+
"kms:DescribeKey"
|
|
4599
|
+
]
|
|
4600
|
+
Resource = "*"
|
|
4601
|
+
Condition = {
|
|
4602
|
+
ArnEquals = {
|
|
4603
|
+
"kms:EncryptionContext:aws:logs:arn" = "arn:aws:logs:\${data.aws_region.current.region}:\${data.aws_caller_identity.current.account_id}:log-group:/aws/apigateway/test-api-\${random_string.suffix.result}/access"
|
|
4604
|
+
}
|
|
4605
|
+
}
|
|
4606
|
+
}
|
|
4607
|
+
]
|
|
4608
|
+
})
|
|
4609
|
+
|
|
4610
|
+
tags = var.tags
|
|
4611
|
+
}
|
|
4612
|
+
|
|
4613
|
+
resource "aws_kms_alias" "access_logs" {
|
|
4614
|
+
name = "alias/test-api-\${random_string.suffix.result}-access-logs"
|
|
4615
|
+
target_key_id = aws_kms_key.access_logs.key_id
|
|
4616
|
+
}
|
|
4617
|
+
|
|
4618
|
+
# Access logs for the API Gateway stage
|
|
4619
|
+
resource "aws_cloudwatch_log_group" "access_logs" {
|
|
4620
|
+
name = "/aws/apigateway/test-api-\${random_string.suffix.result}/access"
|
|
4621
|
+
retention_in_days = 365
|
|
4622
|
+
kms_key_id = aws_kms_key.access_logs.arn
|
|
4623
|
+
tags = var.tags
|
|
4624
|
+
}
|
|
4625
|
+
|
|
3062
4626
|
# API Gateway stage
|
|
3063
4627
|
resource "aws_api_gateway_stage" "api_stage" {
|
|
3064
4628
|
#checkov:skip=CKV_AWS_120:API Gateway caching not required for this use case
|
|
3065
|
-
#checkov:skip=
|
|
3066
|
-
#checkov:skip=CKV2_AWS_4:API Gateway logging level not applicable as access logging is disabled
|
|
4629
|
+
#checkov:skip=CKV2_AWS_4:Access logging is enabled below; verbose execution logging is intentionally not enabled
|
|
3067
4630
|
#checkov:skip=CKV2_AWS_51:Client certificate authentication not required for this use case
|
|
3068
4631
|
#checkov:skip=CKV2_AWS_77:WAFv2 Web ACL is attached via aws_wafv2_web_acl_association when var.enable_waf is true (default) and includes AWSManagedRulesKnownBadInputsRuleSet for Log4j protection; Checkov does not track the association across modules
|
|
3069
4632
|
deployment_id = aws_api_gateway_deployment.api_deployment.id
|
|
@@ -3071,9 +4634,39 @@ resource "aws_api_gateway_stage" "api_stage" {
|
|
|
3071
4634
|
stage_name = "prod"
|
|
3072
4635
|
xray_tracing_enabled = true
|
|
3073
4636
|
|
|
4637
|
+
access_log_settings {
|
|
4638
|
+
destination_arn = aws_cloudwatch_log_group.access_logs.arn
|
|
4639
|
+
format = jsonencode({
|
|
4640
|
+
requestId = "$context.requestId"
|
|
4641
|
+
ip = "$context.identity.sourceIp"
|
|
4642
|
+
caller = "$context.identity.caller"
|
|
4643
|
+
user = "$context.identity.user"
|
|
4644
|
+
requestTime = "$context.requestTime"
|
|
4645
|
+
httpMethod = "$context.httpMethod"
|
|
4646
|
+
resourcePath = "$context.resourcePath"
|
|
4647
|
+
status = "$context.status"
|
|
4648
|
+
protocol = "$context.protocol"
|
|
4649
|
+
responseLength = "$context.responseLength"
|
|
4650
|
+
})
|
|
4651
|
+
}
|
|
4652
|
+
|
|
3074
4653
|
tags = var.tags
|
|
3075
4654
|
|
|
3076
|
-
|
|
4655
|
+
# Ensure the account-level role is configured before the stage is created
|
|
4656
|
+
depends_on = [aws_api_gateway_deployment.api_deployment, module.account]
|
|
4657
|
+
}
|
|
4658
|
+
|
|
4659
|
+
# Default throttling applied to all resource paths and methods
|
|
4660
|
+
resource "aws_api_gateway_method_settings" "throttling" {
|
|
4661
|
+
#checkov:skip=CKV_AWS_225:API Gateway caching not required for this use case
|
|
4662
|
+
rest_api_id = module.rest_api.api_id
|
|
4663
|
+
stage_name = aws_api_gateway_stage.api_stage.stage_name
|
|
4664
|
+
method_path = "*/*"
|
|
4665
|
+
|
|
4666
|
+
settings {
|
|
4667
|
+
throttling_rate_limit = 10000
|
|
4668
|
+
throttling_burst_limit = 5000
|
|
4669
|
+
}
|
|
3077
4670
|
}
|
|
3078
4671
|
|
|
3079
4672
|
# API Gateway Resource Policy
|
|
@@ -3107,11 +4700,13 @@ resource "aws_api_gateway_rest_api_policy" "api_policy" {
|
|
|
3107
4700
|
|
|
3108
4701
|
# Lambda permission for API Gateway to invoke the function
|
|
3109
4702
|
resource "aws_lambda_permission" "api_gateway_invoke" {
|
|
4703
|
+
for_each = local.operations
|
|
4704
|
+
|
|
3110
4705
|
statement_id = "AllowExecutionFromAPIGateway"
|
|
3111
4706
|
action = "lambda:InvokeFunction"
|
|
3112
|
-
function_name = aws_lambda_function.api_lambda.function_name
|
|
4707
|
+
function_name = aws_lambda_function.api_lambda[each.key].function_name
|
|
3113
4708
|
principal = "apigateway.amazonaws.com"
|
|
3114
|
-
source_arn = "\${module.rest_api.api_execution_arn}
|
|
4709
|
+
source_arn = "\${module.rest_api.api_execution_arn}/*/\${local.permission_source_suffix[each.key]}"
|
|
3115
4710
|
|
|
3116
4711
|
depends_on = [module.rest_api, aws_lambda_function.api_lambda]
|
|
3117
4712
|
}
|
|
@@ -3123,7 +4718,7 @@ module "add_url_to_runtime_config" {
|
|
|
3123
4718
|
|
|
3124
4719
|
namespace = "connection"
|
|
3125
4720
|
key = "apis"
|
|
3126
|
-
value = { "TestApi" = aws_api_gateway_stage.api_stage.invoke_url }
|
|
4721
|
+
value = { "TestApi" = "\${aws_api_gateway_stage.api_stage.invoke_url}/" }
|
|
3127
4722
|
|
|
3128
4723
|
depends_on = [aws_api_gateway_stage.api_stage]
|
|
3129
4724
|
}
|
|
@@ -3176,78 +4771,83 @@ output "stage_id" {
|
|
|
3176
4771
|
value = aws_api_gateway_stage.api_stage.id
|
|
3177
4772
|
}
|
|
3178
4773
|
|
|
3179
|
-
# Lambda Function Outputs
|
|
3180
|
-
output "
|
|
3181
|
-
description = "
|
|
3182
|
-
value =
|
|
4774
|
+
# Lambda Function Outputs, keyed by operation name
|
|
4775
|
+
output "operations" {
|
|
4776
|
+
description = "Names of the API operations, each with its own Lambda function"
|
|
4777
|
+
value = keys(local.operations)
|
|
3183
4778
|
}
|
|
3184
4779
|
|
|
3185
|
-
output "
|
|
3186
|
-
description = "
|
|
3187
|
-
value = aws_lambda_function.api_lambda.
|
|
4780
|
+
output "lambda_function_names" {
|
|
4781
|
+
description = "Name of each operation's Lambda function, keyed by operation name"
|
|
4782
|
+
value = { for op, fn in aws_lambda_function.api_lambda : op => fn.function_name }
|
|
3188
4783
|
}
|
|
3189
4784
|
|
|
3190
|
-
output "
|
|
3191
|
-
description = "
|
|
3192
|
-
value = aws_lambda_function.api_lambda.
|
|
4785
|
+
output "lambda_function_arns" {
|
|
4786
|
+
description = "ARN of each operation's Lambda function, keyed by operation name"
|
|
4787
|
+
value = { for op, fn in aws_lambda_function.api_lambda : op => fn.arn }
|
|
3193
4788
|
}
|
|
3194
4789
|
|
|
3195
|
-
output "
|
|
3196
|
-
description = "
|
|
3197
|
-
value = aws_lambda_function.api_lambda.
|
|
4790
|
+
output "lambda_invoke_arns" {
|
|
4791
|
+
description = "Invoke ARN of each operation's Lambda function, keyed by operation name"
|
|
4792
|
+
value = { for op, fn in aws_lambda_function.api_lambda : op => fn.invoke_arn }
|
|
3198
4793
|
}
|
|
3199
4794
|
|
|
3200
|
-
output "
|
|
3201
|
-
description = "
|
|
3202
|
-
value = aws_lambda_function.api_lambda.
|
|
4795
|
+
output "lambda_qualified_arns" {
|
|
4796
|
+
description = "Qualified ARN of each operation's Lambda function, keyed by operation name"
|
|
4797
|
+
value = { for op, fn in aws_lambda_function.api_lambda : op => fn.qualified_arn }
|
|
4798
|
+
}
|
|
4799
|
+
|
|
4800
|
+
output "lambda_versions" {
|
|
4801
|
+
description = "Version of each operation's Lambda function, keyed by operation name"
|
|
4802
|
+
value = { for op, fn in aws_lambda_function.api_lambda : op => fn.version }
|
|
3203
4803
|
}
|
|
3204
4804
|
|
|
3205
4805
|
output "lambda_source_code_hash" {
|
|
3206
|
-
description = "Base64-encoded SHA256 hash of the Lambda deployment package"
|
|
3207
|
-
value =
|
|
4806
|
+
description = "Base64-encoded SHA256 hash of the Lambda deployment package, shared by every operation"
|
|
4807
|
+
value = data.archive_file.lambda_zip.output_base64sha256
|
|
3208
4808
|
}
|
|
3209
4809
|
|
|
3210
|
-
|
|
3211
|
-
|
|
3212
|
-
|
|
4810
|
+
# IAM Role Outputs, keyed by operation name
|
|
4811
|
+
output "lambda_execution_role_arns" {
|
|
4812
|
+
description = "ARN of each operation's Lambda execution role, keyed by operation name"
|
|
4813
|
+
value = { for op, role in aws_iam_role.lambda_execution_role : op => role.arn }
|
|
3213
4814
|
}
|
|
3214
4815
|
|
|
3215
|
-
|
|
3216
|
-
|
|
3217
|
-
|
|
3218
|
-
value = aws_iam_role.lambda_execution_role.arn
|
|
4816
|
+
output "lambda_execution_role_names" {
|
|
4817
|
+
description = "Name of each operation's Lambda execution role, keyed by operation name. Attach additional policies to a specific operation's role by name."
|
|
4818
|
+
value = { for op, role in aws_iam_role.lambda_execution_role : op => role.name }
|
|
3219
4819
|
}
|
|
3220
4820
|
|
|
3221
|
-
output "
|
|
3222
|
-
description = "
|
|
3223
|
-
value =
|
|
4821
|
+
output "security_group_id" {
|
|
4822
|
+
description = "Security group ID shared by the API Lambda functions, for use in ingress rules on resources they must reach (e.g. a database). Null unless enable_vpc is true."
|
|
4823
|
+
value = var.enable_vpc ? aws_security_group.api_lambda[0].id : null
|
|
3224
4824
|
}
|
|
3225
4825
|
|
|
3226
|
-
# Integration Outputs
|
|
3227
|
-
output "
|
|
3228
|
-
description = "ID of
|
|
3229
|
-
value = aws_api_gateway_integration.lambda_integration.id
|
|
4826
|
+
# Integration Outputs, keyed by operation name
|
|
4827
|
+
output "integration_ids" {
|
|
4828
|
+
description = "ID of each operation's Lambda integration, keyed by operation name"
|
|
4829
|
+
value = { for op, i in aws_api_gateway_integration.lambda_integration : op => i.id }
|
|
3230
4830
|
}
|
|
3231
4831
|
|
|
3232
|
-
output "
|
|
3233
|
-
description = "ID of
|
|
3234
|
-
value =
|
|
4832
|
+
output "method_ids" {
|
|
4833
|
+
description = "ID of each operation's API Gateway method, keyed by operation name"
|
|
4834
|
+
value = { for op, m in aws_api_gateway_method.operation_methods : op => m.id }
|
|
3235
4835
|
}
|
|
3236
4836
|
|
|
3237
|
-
output "
|
|
3238
|
-
description = "ID of
|
|
3239
|
-
value =
|
|
4837
|
+
output "resource_ids" {
|
|
4838
|
+
description = "ID of each API Gateway resource, keyed by its path"
|
|
4839
|
+
value = local.resource_ids
|
|
3240
4840
|
}
|
|
3241
4841
|
|
|
3242
|
-
# CloudWatch Log Groups
|
|
3243
|
-
output "
|
|
3244
|
-
description = "Name of
|
|
3245
|
-
value = aws_cloudwatch_log_group.lambda_logs.name
|
|
4842
|
+
# CloudWatch Log Groups, keyed by operation name
|
|
4843
|
+
output "lambda_log_group_names" {
|
|
4844
|
+
description = "Name of each operation's Lambda CloudWatch log group, keyed by operation name"
|
|
4845
|
+
value = { for op, lg in aws_cloudwatch_log_group.lambda_logs : op => lg.name }
|
|
3246
4846
|
}
|
|
3247
4847
|
|
|
3248
|
-
output "
|
|
3249
|
-
description = "ARN of
|
|
3250
|
-
value = aws_cloudwatch_log_group.lambda_logs.arn
|
|
4848
|
+
output "lambda_log_group_arns" {
|
|
4849
|
+
description = "ARN of each operation's Lambda CloudWatch log group, keyed by operation name"
|
|
4850
|
+
value = { for op, lg in aws_cloudwatch_log_group.lambda_logs : op => lg.arn }
|
|
3251
4851
|
}
|
|
3252
4852
|
",
|
|
3253
4853
|
}
|
|
@@ -3258,9 +4858,17 @@ exports[`tsSmithyApiGenerator > terraform iac > should generate terraform with c
|
|
|
3258
4858
|
required_version = ">= 1.0"
|
|
3259
4859
|
|
|
3260
4860
|
required_providers {
|
|
4861
|
+
archive = {
|
|
4862
|
+
source = "hashicorp/archive"
|
|
4863
|
+
version = "2.8.0"
|
|
4864
|
+
}
|
|
3261
4865
|
aws = {
|
|
3262
4866
|
source = "hashicorp/aws"
|
|
3263
|
-
version = "
|
|
4867
|
+
version = "6.62.0"
|
|
4868
|
+
}
|
|
4869
|
+
random = {
|
|
4870
|
+
source = "hashicorp/random"
|
|
4871
|
+
version = "3.9.0"
|
|
3264
4872
|
}
|
|
3265
4873
|
}
|
|
3266
4874
|
}
|
|
@@ -3282,11 +4890,47 @@ variable "additional_iam_policy_statements" {
|
|
|
3282
4890
|
default = []
|
|
3283
4891
|
}
|
|
3284
4892
|
|
|
4893
|
+
variable "appconfig_application_id" {
|
|
4894
|
+
description = "ID of the shared runtime-config AppConfig application (from \`core/runtime-config/appconfig.application_id\`). When set, the Lambda functions receive \`RUNTIME_CONFIG_APP_ID\` and read access to the application."
|
|
4895
|
+
type = string
|
|
4896
|
+
default = null
|
|
4897
|
+
}
|
|
4898
|
+
|
|
4899
|
+
variable "appconfig_application_arn" {
|
|
4900
|
+
description = "ARN of the shared runtime-config AppConfig application (from \`core/runtime-config/appconfig.application_arn\`). Used to scope the IAM read permission granted to the Lambda functions."
|
|
4901
|
+
type = string
|
|
4902
|
+
default = null
|
|
4903
|
+
}
|
|
4904
|
+
|
|
3285
4905
|
variable "asset_bucket_name" {
|
|
3286
4906
|
description = "Name of the shared asset S3 bucket used to stage the Lambda deployment zip. Instantiate the \`core/asset-bucket\` module once per deployment and pass its \`bucket_name\` output here."
|
|
3287
4907
|
type = string
|
|
3288
4908
|
}
|
|
3289
4909
|
|
|
4910
|
+
# VPC Configuration (optional)
|
|
4911
|
+
variable "enable_vpc" {
|
|
4912
|
+
description = "Deploy the Lambda function into a VPC. Set alongside vpc_id/subnet_ids."
|
|
4913
|
+
type = bool
|
|
4914
|
+
default = false
|
|
4915
|
+
}
|
|
4916
|
+
|
|
4917
|
+
variable "vpc_id" {
|
|
4918
|
+
description = "VPC ID to deploy the Lambda function into. Required when enable_vpc is true."
|
|
4919
|
+
type = string
|
|
4920
|
+
default = null
|
|
4921
|
+
|
|
4922
|
+
validation {
|
|
4923
|
+
condition = !var.enable_vpc || (var.vpc_id != null && var.subnet_ids != null)
|
|
4924
|
+
error_message = "vpc_id and subnet_ids must be set when enable_vpc is true."
|
|
4925
|
+
}
|
|
4926
|
+
}
|
|
4927
|
+
|
|
4928
|
+
variable "subnet_ids" {
|
|
4929
|
+
description = "Subnet IDs to deploy the Lambda function into. Required when enable_vpc is true."
|
|
4930
|
+
type = list(string)
|
|
4931
|
+
default = null
|
|
4932
|
+
}
|
|
4933
|
+
|
|
3290
4934
|
# CORS Configuration (passed to core module)
|
|
3291
4935
|
|
|
3292
4936
|
variable "cors_allow_headers" {
|
|
@@ -3331,6 +4975,235 @@ resource "random_string" "suffix" {
|
|
|
3331
4975
|
upper = false
|
|
3332
4976
|
}
|
|
3333
4977
|
|
|
4978
|
+
locals {
|
|
4979
|
+
# Generated at build time from the API definition
|
|
4980
|
+
operations_file = "\${path.module}/../../../generated/custom-api/operations.json"
|
|
4981
|
+
operations = fileexists(local.operations_file) ? jsondecode(file(local.operations_file)) : {}
|
|
4982
|
+
|
|
4983
|
+
operation_slug = { for op in keys(local.operations) : op => replace(op, "/[^a-zA-Z0-9-_]/", "-") }
|
|
4984
|
+
operation_hash = { for op in keys(local.operations) : op => substr(sha256(op), 0, 8) }
|
|
4985
|
+
|
|
4986
|
+
function_name = { for op in keys(local.operations) : op =>
|
|
4987
|
+
"\${substr("CustomApi-\${local.operation_slug[op]}", 0, 64 - length(local.operation_hash[op]) - length(random_string.suffix.result) - 2)}-\${local.operation_hash[op]}-\${random_string.suffix.result}"
|
|
4988
|
+
}
|
|
4989
|
+
role_name = { for op in keys(local.operations) : op =>
|
|
4990
|
+
"\${substr("CustomApi-\${local.operation_slug[op]}-role", 0, 64 - length(local.operation_hash[op]) - length(random_string.suffix.result) - 2)}-\${local.operation_hash[op]}-\${random_string.suffix.result}"
|
|
4991
|
+
}
|
|
4992
|
+
|
|
4993
|
+
# A REST API needs a resource per path segment, so each operation's path is
|
|
4994
|
+
# split into the distinct path prefixes the resource tree is built from below
|
|
4995
|
+
operation_segments = { for op, details in local.operations : op => compact(split("/", details.path)) }
|
|
4996
|
+
|
|
4997
|
+
path_nodes = merge([
|
|
4998
|
+
for op, segments in local.operation_segments : {
|
|
4999
|
+
for i, segment in segments : join("/", slice(segments, 0, i + 1)) => {
|
|
5000
|
+
depth = i
|
|
5001
|
+
parent = i == 0 ? "" : join("/", slice(segments, 0, i))
|
|
5002
|
+
part = segment
|
|
5003
|
+
}
|
|
5004
|
+
}
|
|
5005
|
+
]...)
|
|
5006
|
+
|
|
5007
|
+
# Instances of a resource cannot reference one another, so each depth is a
|
|
5008
|
+
# separate resource. Deeper paths are reported by the precondition below.
|
|
5009
|
+
max_path_depth = 16
|
|
5010
|
+
path_nodes_by_depth = { for depth in range(local.max_path_depth) : depth => {
|
|
5011
|
+
for path, node in local.path_nodes : path => node if node.depth == depth
|
|
5012
|
+
} }
|
|
5013
|
+
paths_too_deep = [for path, node in local.path_nodes : path if node.depth >= local.max_path_depth]
|
|
5014
|
+
|
|
5015
|
+
resource_ids = merge(
|
|
5016
|
+
{ for path, resource in aws_api_gateway_resource.path_depth_0 : path => resource.id },
|
|
5017
|
+
{ for path, resource in aws_api_gateway_resource.path_depth_1 : path => resource.id },
|
|
5018
|
+
{ for path, resource in aws_api_gateway_resource.path_depth_2 : path => resource.id },
|
|
5019
|
+
{ for path, resource in aws_api_gateway_resource.path_depth_3 : path => resource.id },
|
|
5020
|
+
{ for path, resource in aws_api_gateway_resource.path_depth_4 : path => resource.id },
|
|
5021
|
+
{ for path, resource in aws_api_gateway_resource.path_depth_5 : path => resource.id },
|
|
5022
|
+
{ for path, resource in aws_api_gateway_resource.path_depth_6 : path => resource.id },
|
|
5023
|
+
{ for path, resource in aws_api_gateway_resource.path_depth_7 : path => resource.id },
|
|
5024
|
+
{ for path, resource in aws_api_gateway_resource.path_depth_8 : path => resource.id },
|
|
5025
|
+
{ for path, resource in aws_api_gateway_resource.path_depth_9 : path => resource.id },
|
|
5026
|
+
{ for path, resource in aws_api_gateway_resource.path_depth_10 : path => resource.id },
|
|
5027
|
+
{ for path, resource in aws_api_gateway_resource.path_depth_11 : path => resource.id },
|
|
5028
|
+
{ for path, resource in aws_api_gateway_resource.path_depth_12 : path => resource.id },
|
|
5029
|
+
{ for path, resource in aws_api_gateway_resource.path_depth_13 : path => resource.id },
|
|
5030
|
+
{ for path, resource in aws_api_gateway_resource.path_depth_14 : path => resource.id },
|
|
5031
|
+
{ for path, resource in aws_api_gateway_resource.path_depth_15 : path => resource.id },
|
|
5032
|
+
)
|
|
5033
|
+
|
|
5034
|
+
operation_resource_id = { for op, segments in local.operation_segments : op =>
|
|
5035
|
+
local.resource_ids[join("/", segments)]
|
|
5036
|
+
}
|
|
5037
|
+
|
|
5038
|
+
permission_source_suffix = { for op, details in local.operations : op =>
|
|
5039
|
+
"\${upper(details.method)}/\${replace(join("/", local.operation_segments[op]), "/{[^}]*}/", "*")}"
|
|
5040
|
+
}
|
|
5041
|
+
}
|
|
5042
|
+
|
|
5043
|
+
resource "terraform_data" "operations_metadata" {
|
|
5044
|
+
# Fails the plan when the operations metadata has not been generated
|
|
5045
|
+
input = local.operations_file
|
|
5046
|
+
|
|
5047
|
+
lifecycle {
|
|
5048
|
+
precondition {
|
|
5049
|
+
condition = fileexists(local.operations_file)
|
|
5050
|
+
error_message = "Operations metadata not found at \${local.operations_file}. Build the CustomApi project to generate it."
|
|
5051
|
+
}
|
|
5052
|
+
precondition {
|
|
5053
|
+
condition = length(local.operations) > 0
|
|
5054
|
+
error_message = "No operations found in \${local.operations_file}. The CustomApi API must define at least one operation."
|
|
5055
|
+
}
|
|
5056
|
+
precondition {
|
|
5057
|
+
condition = length(local.paths_too_deep) == 0
|
|
5058
|
+
error_message = "Operation paths exceed the supported depth of \${local.max_path_depth} segments: \${join(", ", local.paths_too_deep)}. Add further aws_api_gateway_resource levels to this module to support them."
|
|
5059
|
+
}
|
|
5060
|
+
}
|
|
5061
|
+
}
|
|
5062
|
+
|
|
5063
|
+
# API Gateway resources at path depth 0
|
|
5064
|
+
resource "aws_api_gateway_resource" "path_depth_0" {
|
|
5065
|
+
for_each = local.path_nodes_by_depth[0]
|
|
5066
|
+
|
|
5067
|
+
rest_api_id = module.rest_api.api_id
|
|
5068
|
+
parent_id = module.rest_api.api_root_resource_id
|
|
5069
|
+
path_part = each.value.part
|
|
5070
|
+
}
|
|
5071
|
+
|
|
5072
|
+
# API Gateway resources at path depth 1
|
|
5073
|
+
resource "aws_api_gateway_resource" "path_depth_1" {
|
|
5074
|
+
for_each = local.path_nodes_by_depth[1]
|
|
5075
|
+
|
|
5076
|
+
rest_api_id = module.rest_api.api_id
|
|
5077
|
+
parent_id = aws_api_gateway_resource.path_depth_0[each.value.parent].id
|
|
5078
|
+
path_part = each.value.part
|
|
5079
|
+
}
|
|
5080
|
+
|
|
5081
|
+
# API Gateway resources at path depth 2
|
|
5082
|
+
resource "aws_api_gateway_resource" "path_depth_2" {
|
|
5083
|
+
for_each = local.path_nodes_by_depth[2]
|
|
5084
|
+
|
|
5085
|
+
rest_api_id = module.rest_api.api_id
|
|
5086
|
+
parent_id = aws_api_gateway_resource.path_depth_1[each.value.parent].id
|
|
5087
|
+
path_part = each.value.part
|
|
5088
|
+
}
|
|
5089
|
+
|
|
5090
|
+
# API Gateway resources at path depth 3
|
|
5091
|
+
resource "aws_api_gateway_resource" "path_depth_3" {
|
|
5092
|
+
for_each = local.path_nodes_by_depth[3]
|
|
5093
|
+
|
|
5094
|
+
rest_api_id = module.rest_api.api_id
|
|
5095
|
+
parent_id = aws_api_gateway_resource.path_depth_2[each.value.parent].id
|
|
5096
|
+
path_part = each.value.part
|
|
5097
|
+
}
|
|
5098
|
+
|
|
5099
|
+
# API Gateway resources at path depth 4
|
|
5100
|
+
resource "aws_api_gateway_resource" "path_depth_4" {
|
|
5101
|
+
for_each = local.path_nodes_by_depth[4]
|
|
5102
|
+
|
|
5103
|
+
rest_api_id = module.rest_api.api_id
|
|
5104
|
+
parent_id = aws_api_gateway_resource.path_depth_3[each.value.parent].id
|
|
5105
|
+
path_part = each.value.part
|
|
5106
|
+
}
|
|
5107
|
+
|
|
5108
|
+
# API Gateway resources at path depth 5
|
|
5109
|
+
resource "aws_api_gateway_resource" "path_depth_5" {
|
|
5110
|
+
for_each = local.path_nodes_by_depth[5]
|
|
5111
|
+
|
|
5112
|
+
rest_api_id = module.rest_api.api_id
|
|
5113
|
+
parent_id = aws_api_gateway_resource.path_depth_4[each.value.parent].id
|
|
5114
|
+
path_part = each.value.part
|
|
5115
|
+
}
|
|
5116
|
+
|
|
5117
|
+
# API Gateway resources at path depth 6
|
|
5118
|
+
resource "aws_api_gateway_resource" "path_depth_6" {
|
|
5119
|
+
for_each = local.path_nodes_by_depth[6]
|
|
5120
|
+
|
|
5121
|
+
rest_api_id = module.rest_api.api_id
|
|
5122
|
+
parent_id = aws_api_gateway_resource.path_depth_5[each.value.parent].id
|
|
5123
|
+
path_part = each.value.part
|
|
5124
|
+
}
|
|
5125
|
+
|
|
5126
|
+
# API Gateway resources at path depth 7
|
|
5127
|
+
resource "aws_api_gateway_resource" "path_depth_7" {
|
|
5128
|
+
for_each = local.path_nodes_by_depth[7]
|
|
5129
|
+
|
|
5130
|
+
rest_api_id = module.rest_api.api_id
|
|
5131
|
+
parent_id = aws_api_gateway_resource.path_depth_6[each.value.parent].id
|
|
5132
|
+
path_part = each.value.part
|
|
5133
|
+
}
|
|
5134
|
+
|
|
5135
|
+
# API Gateway resources at path depth 8
|
|
5136
|
+
resource "aws_api_gateway_resource" "path_depth_8" {
|
|
5137
|
+
for_each = local.path_nodes_by_depth[8]
|
|
5138
|
+
|
|
5139
|
+
rest_api_id = module.rest_api.api_id
|
|
5140
|
+
parent_id = aws_api_gateway_resource.path_depth_7[each.value.parent].id
|
|
5141
|
+
path_part = each.value.part
|
|
5142
|
+
}
|
|
5143
|
+
|
|
5144
|
+
# API Gateway resources at path depth 9
|
|
5145
|
+
resource "aws_api_gateway_resource" "path_depth_9" {
|
|
5146
|
+
for_each = local.path_nodes_by_depth[9]
|
|
5147
|
+
|
|
5148
|
+
rest_api_id = module.rest_api.api_id
|
|
5149
|
+
parent_id = aws_api_gateway_resource.path_depth_8[each.value.parent].id
|
|
5150
|
+
path_part = each.value.part
|
|
5151
|
+
}
|
|
5152
|
+
|
|
5153
|
+
# API Gateway resources at path depth 10
|
|
5154
|
+
resource "aws_api_gateway_resource" "path_depth_10" {
|
|
5155
|
+
for_each = local.path_nodes_by_depth[10]
|
|
5156
|
+
|
|
5157
|
+
rest_api_id = module.rest_api.api_id
|
|
5158
|
+
parent_id = aws_api_gateway_resource.path_depth_9[each.value.parent].id
|
|
5159
|
+
path_part = each.value.part
|
|
5160
|
+
}
|
|
5161
|
+
|
|
5162
|
+
# API Gateway resources at path depth 11
|
|
5163
|
+
resource "aws_api_gateway_resource" "path_depth_11" {
|
|
5164
|
+
for_each = local.path_nodes_by_depth[11]
|
|
5165
|
+
|
|
5166
|
+
rest_api_id = module.rest_api.api_id
|
|
5167
|
+
parent_id = aws_api_gateway_resource.path_depth_10[each.value.parent].id
|
|
5168
|
+
path_part = each.value.part
|
|
5169
|
+
}
|
|
5170
|
+
|
|
5171
|
+
# API Gateway resources at path depth 12
|
|
5172
|
+
resource "aws_api_gateway_resource" "path_depth_12" {
|
|
5173
|
+
for_each = local.path_nodes_by_depth[12]
|
|
5174
|
+
|
|
5175
|
+
rest_api_id = module.rest_api.api_id
|
|
5176
|
+
parent_id = aws_api_gateway_resource.path_depth_11[each.value.parent].id
|
|
5177
|
+
path_part = each.value.part
|
|
5178
|
+
}
|
|
5179
|
+
|
|
5180
|
+
# API Gateway resources at path depth 13
|
|
5181
|
+
resource "aws_api_gateway_resource" "path_depth_13" {
|
|
5182
|
+
for_each = local.path_nodes_by_depth[13]
|
|
5183
|
+
|
|
5184
|
+
rest_api_id = module.rest_api.api_id
|
|
5185
|
+
parent_id = aws_api_gateway_resource.path_depth_12[each.value.parent].id
|
|
5186
|
+
path_part = each.value.part
|
|
5187
|
+
}
|
|
5188
|
+
|
|
5189
|
+
# API Gateway resources at path depth 14
|
|
5190
|
+
resource "aws_api_gateway_resource" "path_depth_14" {
|
|
5191
|
+
for_each = local.path_nodes_by_depth[14]
|
|
5192
|
+
|
|
5193
|
+
rest_api_id = module.rest_api.api_id
|
|
5194
|
+
parent_id = aws_api_gateway_resource.path_depth_13[each.value.parent].id
|
|
5195
|
+
path_part = each.value.part
|
|
5196
|
+
}
|
|
5197
|
+
|
|
5198
|
+
# API Gateway resources at path depth 15
|
|
5199
|
+
resource "aws_api_gateway_resource" "path_depth_15" {
|
|
5200
|
+
for_each = local.path_nodes_by_depth[15]
|
|
5201
|
+
|
|
5202
|
+
rest_api_id = module.rest_api.api_id
|
|
5203
|
+
parent_id = aws_api_gateway_resource.path_depth_14[each.value.parent].id
|
|
5204
|
+
path_part = each.value.part
|
|
5205
|
+
}
|
|
5206
|
+
|
|
3334
5207
|
# Resources
|
|
3335
5208
|
|
|
3336
5209
|
# Create Lambda ZIP file from the bundle directory
|
|
@@ -3349,6 +5222,11 @@ resource "aws_s3_object" "lambda_zip" {
|
|
|
3349
5222
|
}
|
|
3350
5223
|
|
|
3351
5224
|
# Use the core REST API module
|
|
5225
|
+
# Account-level CloudWatch role required for REST API access logging
|
|
5226
|
+
module "account" {
|
|
5227
|
+
source = "../../../core/api/api-gateway-account"
|
|
5228
|
+
}
|
|
5229
|
+
|
|
3352
5230
|
module "rest_api" {
|
|
3353
5231
|
source = "../../../core/api/rest-api"
|
|
3354
5232
|
|
|
@@ -3378,9 +5256,33 @@ resource "aws_wafv2_web_acl_association" "api_waf_association" {
|
|
|
3378
5256
|
depends_on = [aws_api_gateway_stage.api_stage]
|
|
3379
5257
|
}
|
|
3380
5258
|
|
|
3381
|
-
# Lambda function
|
|
5259
|
+
# Security group for the API Lambda function, used when deployed into a VPC
|
|
5260
|
+
resource "aws_security_group" "api_lambda" {
|
|
5261
|
+
count = var.enable_vpc ? 1 : 0
|
|
5262
|
+
|
|
5263
|
+
#checkov:skip=CKV2_AWS_5:Attached to api_lambda via vpc_config block; Checkov cannot resolve this reference
|
|
5264
|
+
name_prefix = "custom-api-lambda-"
|
|
5265
|
+
description = "Security group for the CustomApi API Lambda function"
|
|
5266
|
+
vpc_id = var.vpc_id
|
|
5267
|
+
tags = var.tags
|
|
5268
|
+
}
|
|
5269
|
+
|
|
5270
|
+
resource "aws_vpc_security_group_egress_rule" "api_lambda_https" {
|
|
5271
|
+
count = var.enable_vpc ? 1 : 0
|
|
5272
|
+
|
|
5273
|
+
security_group_id = aws_security_group.api_lambda[0].id
|
|
5274
|
+
cidr_ipv4 = "0.0.0.0/0"
|
|
5275
|
+
from_port = 443
|
|
5276
|
+
to_port = 443
|
|
5277
|
+
ip_protocol = "tcp"
|
|
5278
|
+
description = "Allow outbound HTTPS to AWS service endpoints"
|
|
5279
|
+
}
|
|
5280
|
+
|
|
3382
5281
|
resource "aws_lambda_function" "api_lambda" {
|
|
3383
|
-
#
|
|
5282
|
+
# One lambda function per operation, each serving just that operation
|
|
5283
|
+
for_each = local.operations
|
|
5284
|
+
|
|
5285
|
+
#checkov:skip=CKV_AWS_117:Lambda function is optionally deployed into a VPC via vpc_id/subnet_ids; not required for this use case
|
|
3384
5286
|
#checkov:skip=CKV_AWS_116:Dead Letter Queue not required for this simple API use case
|
|
3385
5287
|
#checkov:skip=CKV_AWS_272:Code signing not required for this use case
|
|
3386
5288
|
#checkov:skip=CKV_AWS_115:Concurrent execution limit not required for this use case
|
|
@@ -3388,10 +5290,10 @@ resource "aws_lambda_function" "api_lambda" {
|
|
|
3388
5290
|
s3_bucket = aws_s3_object.lambda_zip.bucket
|
|
3389
5291
|
s3_key = aws_s3_object.lambda_zip.key
|
|
3390
5292
|
s3_object_version = aws_s3_object.lambda_zip.version_id
|
|
3391
|
-
function_name =
|
|
3392
|
-
role = aws_iam_role.lambda_execution_role.arn
|
|
5293
|
+
function_name = local.function_name[each.key]
|
|
5294
|
+
role = aws_iam_role.lambda_execution_role[each.key].arn
|
|
3393
5295
|
handler = "index.handler"
|
|
3394
|
-
runtime = "
|
|
5296
|
+
runtime = "nodejs24.x"
|
|
3395
5297
|
timeout = 30
|
|
3396
5298
|
memory_size = 128
|
|
3397
5299
|
|
|
@@ -3402,18 +5304,32 @@ resource "aws_lambda_function" "api_lambda" {
|
|
|
3402
5304
|
mode = "Active"
|
|
3403
5305
|
}
|
|
3404
5306
|
|
|
5307
|
+
dynamic "vpc_config" {
|
|
5308
|
+
for_each = var.enable_vpc ? [1] : []
|
|
5309
|
+
content {
|
|
5310
|
+
subnet_ids = var.subnet_ids
|
|
5311
|
+
security_group_ids = [aws_security_group.api_lambda[0].id]
|
|
5312
|
+
}
|
|
5313
|
+
}
|
|
5314
|
+
|
|
3405
5315
|
|
|
3406
5316
|
environment {
|
|
3407
5317
|
variables = merge({
|
|
3408
|
-
}, var.
|
|
5318
|
+
}, var.appconfig_application_id != null ? {
|
|
5319
|
+
RUNTIME_CONFIG_APP_ID = var.appconfig_application_id
|
|
5320
|
+
} : {}, var.env)
|
|
3409
5321
|
}
|
|
3410
5322
|
|
|
3411
5323
|
tags = var.tags
|
|
5324
|
+
|
|
5325
|
+
depends_on = [aws_iam_role_policy_attachment.lambda_vpc_access]
|
|
3412
5326
|
}
|
|
3413
5327
|
|
|
3414
5328
|
# IAM role for Lambda execution
|
|
3415
5329
|
resource "aws_iam_role" "lambda_execution_role" {
|
|
3416
|
-
|
|
5330
|
+
for_each = local.operations
|
|
5331
|
+
|
|
5332
|
+
name = local.role_name[each.key]
|
|
3417
5333
|
|
|
3418
5334
|
assume_role_policy = jsonencode({
|
|
3419
5335
|
Version = "2012-10-17"
|
|
@@ -3433,35 +5349,73 @@ resource "aws_iam_role" "lambda_execution_role" {
|
|
|
3433
5349
|
|
|
3434
5350
|
# Attach basic execution policy to Lambda role
|
|
3435
5351
|
resource "aws_iam_role_policy_attachment" "lambda_basic_execution" {
|
|
5352
|
+
for_each = local.operations
|
|
5353
|
+
|
|
3436
5354
|
policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
|
|
3437
|
-
role = aws_iam_role.lambda_execution_role.name
|
|
5355
|
+
role = aws_iam_role.lambda_execution_role[each.key].name
|
|
3438
5356
|
}
|
|
3439
5357
|
|
|
3440
5358
|
# Attach X-Ray tracing policy to Lambda role
|
|
3441
5359
|
resource "aws_iam_role_policy_attachment" "lambda_xray_execution" {
|
|
5360
|
+
for_each = local.operations
|
|
5361
|
+
|
|
3442
5362
|
policy_arn = "arn:aws:iam::aws:policy/AWSXRayDaemonWriteAccess"
|
|
3443
|
-
role = aws_iam_role.lambda_execution_role.name
|
|
5363
|
+
role = aws_iam_role.lambda_execution_role[each.key].name
|
|
5364
|
+
}
|
|
5365
|
+
|
|
5366
|
+
# Attach VPC access policy to Lambda role when deployed into a VPC
|
|
5367
|
+
resource "aws_iam_role_policy_attachment" "lambda_vpc_access" {
|
|
5368
|
+
for_each = var.enable_vpc ? local.operations : {}
|
|
5369
|
+
|
|
5370
|
+
policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole"
|
|
5371
|
+
role = aws_iam_role.lambda_execution_role[each.key].name
|
|
3444
5372
|
}
|
|
3445
5373
|
|
|
3446
5374
|
# Additional IAM policies for Lambda (if provided)
|
|
3447
5375
|
resource "aws_iam_role_policy" "lambda_additional_policies" {
|
|
3448
|
-
|
|
3449
|
-
|
|
3450
|
-
|
|
5376
|
+
for_each = local.operations
|
|
5377
|
+
|
|
5378
|
+
name = "\${substr(local.function_name[each.key], 0, 55)}-policies"
|
|
5379
|
+
role = aws_iam_role.lambda_execution_role[each.key].id
|
|
3451
5380
|
|
|
3452
5381
|
policy = jsonencode({
|
|
3453
5382
|
Version = "2012-10-17"
|
|
3454
|
-
Statement =
|
|
5383
|
+
Statement = local.lambda_policy_document_statements
|
|
3455
5384
|
})
|
|
3456
5385
|
}
|
|
3457
5386
|
|
|
5387
|
+
locals {
|
|
5388
|
+
# Grant read access to the runtime-config AppConfig application when wired
|
|
5389
|
+
lambda_policy_statements = concat(var.appconfig_application_arn != null ? [
|
|
5390
|
+
{
|
|
5391
|
+
Effect = "Allow"
|
|
5392
|
+
Action = [
|
|
5393
|
+
"appconfig:StartConfigurationSession",
|
|
5394
|
+
"appconfig:GetLatestConfiguration"
|
|
5395
|
+
]
|
|
5396
|
+
Resource = ["\${var.appconfig_application_arn}/*"]
|
|
5397
|
+
}
|
|
5398
|
+
] : [], var.additional_iam_policy_statements)
|
|
5399
|
+
|
|
5400
|
+
# IAM rejects an empty statement list, so fall back to a no-op deny
|
|
5401
|
+
lambda_policy_document_statements = length(local.lambda_policy_statements) > 0 ? local.lambda_policy_statements : [
|
|
5402
|
+
{
|
|
5403
|
+
Effect = "Deny"
|
|
5404
|
+
Action = ["appconfig:GetLatestConfiguration"]
|
|
5405
|
+
Resource = ["arn:aws:appconfig:\${data.aws_region.current.region}:\${data.aws_caller_identity.current.account_id}:application/none"]
|
|
5406
|
+
}
|
|
5407
|
+
]
|
|
5408
|
+
}
|
|
5409
|
+
|
|
3458
5410
|
# CloudWatch Log Group for Lambda
|
|
3459
5411
|
resource "aws_cloudwatch_log_group" "lambda_logs" {
|
|
3460
5412
|
#checkov:skip=CKV_AWS_158:Using default CloudWatch log encryption
|
|
3461
5413
|
#checkov:skip=CKV_AWS_338:Log retention set to forever
|
|
3462
5414
|
#checkov:skip=CKV_AWS_66:Log retention set to forever
|
|
3463
|
-
|
|
3464
|
-
|
|
5415
|
+
for_each = local.operations
|
|
5416
|
+
|
|
5417
|
+
name = "/aws/lambda/\${local.function_name[each.key]}"
|
|
5418
|
+
tags = var.tags
|
|
3465
5419
|
}
|
|
3466
5420
|
|
|
3467
5421
|
|
|
@@ -3478,7 +5432,7 @@ resource "aws_lambda_function" "authorizer_lambda" {
|
|
|
3478
5432
|
function_name = "CustomApiAuthorizer-\${random_string.suffix.result}"
|
|
3479
5433
|
role = aws_iam_role.authorizer_execution_role.arn
|
|
3480
5434
|
handler = "index.handler"
|
|
3481
|
-
runtime = "
|
|
5435
|
+
runtime = "nodejs24.x"
|
|
3482
5436
|
timeout = 10
|
|
3483
5437
|
memory_size = 128
|
|
3484
5438
|
|
|
@@ -3558,58 +5512,62 @@ resource "aws_lambda_permission" "authorizer_invoke" {
|
|
|
3558
5512
|
source_arn = "\${module.rest_api.api_execution_arn}/authorizers/\${aws_api_gateway_authorizer.custom_authorizer.id}"
|
|
3559
5513
|
}
|
|
3560
5514
|
|
|
3561
|
-
#
|
|
3562
|
-
resource "
|
|
3563
|
-
rest_api_id = module.rest_api.api_id
|
|
3564
|
-
parent_id = module.rest_api.api_root_resource_id
|
|
3565
|
-
path_part = "{proxy+}"
|
|
3566
|
-
}
|
|
3567
|
-
|
|
3568
|
-
# Lambda integration for REST API
|
|
3569
|
-
resource "aws_api_gateway_integration" "lambda_integration" {
|
|
3570
|
-
rest_api_id = module.rest_api.api_id
|
|
3571
|
-
resource_id = aws_api_gateway_resource.proxy_resource.id
|
|
3572
|
-
http_method = aws_api_gateway_method.proxy_method.http_method
|
|
3573
|
-
|
|
3574
|
-
integration_http_method = "POST"
|
|
3575
|
-
type = "AWS_PROXY"
|
|
3576
|
-
uri = aws_lambda_function.api_lambda.invoke_arn
|
|
3577
|
-
|
|
3578
|
-
depends_on = [aws_lambda_function.api_lambda]
|
|
3579
|
-
}
|
|
3580
|
-
|
|
3581
|
-
# Method for proxy integration
|
|
3582
|
-
resource "aws_api_gateway_method" "proxy_method" {
|
|
5515
|
+
# Method per operation
|
|
5516
|
+
resource "aws_api_gateway_method" "operation_methods" {
|
|
3583
5517
|
#checkov:skip=CKV2_AWS_53:Request validation not required for proxy integration as Lambda handles validation
|
|
5518
|
+
for_each = local.operations
|
|
5519
|
+
|
|
3584
5520
|
rest_api_id = module.rest_api.api_id
|
|
3585
|
-
resource_id =
|
|
3586
|
-
http_method =
|
|
5521
|
+
resource_id = local.operation_resource_id[each.key]
|
|
5522
|
+
http_method = upper(each.value.method)
|
|
3587
5523
|
|
|
3588
5524
|
authorization = "CUSTOM"
|
|
3589
5525
|
authorizer_id = aws_api_gateway_authorizer.custom_authorizer.id
|
|
3590
5526
|
|
|
5527
|
+
# Path parameters must be declared on the method
|
|
3591
5528
|
request_parameters = {
|
|
3592
|
-
|
|
5529
|
+
for segment in local.operation_segments[each.key] :
|
|
5530
|
+
"method.request.path.\${trimsuffix(trimprefix(segment, "{"), "}")}" => true
|
|
5531
|
+
if startswith(segment, "{")
|
|
3593
5532
|
}
|
|
3594
5533
|
|
|
3595
5534
|
depends_on = [aws_api_gateway_authorizer.custom_authorizer]
|
|
3596
5535
|
}
|
|
3597
5536
|
|
|
3598
|
-
#
|
|
5537
|
+
# Lambda integration per operation
|
|
5538
|
+
resource "aws_api_gateway_integration" "lambda_integration" {
|
|
5539
|
+
for_each = local.operations
|
|
5540
|
+
|
|
5541
|
+
rest_api_id = module.rest_api.api_id
|
|
5542
|
+
resource_id = local.operation_resource_id[each.key]
|
|
5543
|
+
http_method = aws_api_gateway_method.operation_methods[each.key].http_method
|
|
5544
|
+
|
|
5545
|
+
integration_http_method = "POST"
|
|
5546
|
+
type = "AWS_PROXY"
|
|
5547
|
+
uri = aws_lambda_function.api_lambda[each.key].invoke_arn
|
|
5548
|
+
|
|
5549
|
+
depends_on = [aws_lambda_function.api_lambda]
|
|
5550
|
+
}
|
|
5551
|
+
|
|
5552
|
+
# OPTIONS method for CORS preflight, on every resource an operation is served from
|
|
3599
5553
|
resource "aws_api_gateway_method" "options_method" {
|
|
3600
5554
|
#checkov:skip=CKV2_AWS_70:OPTIONS method must be unauthenticated for CORS preflight requests
|
|
3601
5555
|
#checkov:skip=CKV2_AWS_53:Request validation not required for OPTIONS CORS preflight method
|
|
5556
|
+
for_each = local.resource_ids
|
|
5557
|
+
|
|
3602
5558
|
rest_api_id = module.rest_api.api_id
|
|
3603
|
-
resource_id =
|
|
5559
|
+
resource_id = each.value
|
|
3604
5560
|
http_method = "OPTIONS"
|
|
3605
5561
|
authorization = "NONE"
|
|
3606
5562
|
}
|
|
3607
5563
|
|
|
3608
|
-
# CORS integration for OPTIONS
|
|
5564
|
+
# CORS integration for OPTIONS methods
|
|
3609
5565
|
resource "aws_api_gateway_integration" "options_integration" {
|
|
5566
|
+
for_each = local.resource_ids
|
|
5567
|
+
|
|
3610
5568
|
rest_api_id = module.rest_api.api_id
|
|
3611
|
-
resource_id =
|
|
3612
|
-
http_method = aws_api_gateway_method.options_method.http_method
|
|
5569
|
+
resource_id = each.value
|
|
5570
|
+
http_method = aws_api_gateway_method.options_method[each.key].http_method
|
|
3613
5571
|
|
|
3614
5572
|
type = "MOCK"
|
|
3615
5573
|
request_templates = {
|
|
@@ -3617,11 +5575,13 @@ resource "aws_api_gateway_integration" "options_integration" {
|
|
|
3617
5575
|
}
|
|
3618
5576
|
}
|
|
3619
5577
|
|
|
3620
|
-
# OPTIONS method
|
|
5578
|
+
# OPTIONS method responses
|
|
3621
5579
|
resource "aws_api_gateway_method_response" "options_response" {
|
|
5580
|
+
for_each = local.resource_ids
|
|
5581
|
+
|
|
3622
5582
|
rest_api_id = module.rest_api.api_id
|
|
3623
|
-
resource_id =
|
|
3624
|
-
http_method = aws_api_gateway_method.options_method.http_method
|
|
5583
|
+
resource_id = each.value
|
|
5584
|
+
http_method = aws_api_gateway_method.options_method[each.key].http_method
|
|
3625
5585
|
status_code = "204"
|
|
3626
5586
|
|
|
3627
5587
|
response_parameters = {
|
|
@@ -3631,18 +5591,22 @@ resource "aws_api_gateway_method_response" "options_response" {
|
|
|
3631
5591
|
}
|
|
3632
5592
|
}
|
|
3633
5593
|
|
|
3634
|
-
# OPTIONS integration
|
|
5594
|
+
# OPTIONS integration responses
|
|
3635
5595
|
resource "aws_api_gateway_integration_response" "options_integration_response" {
|
|
5596
|
+
for_each = local.resource_ids
|
|
5597
|
+
|
|
3636
5598
|
rest_api_id = module.rest_api.api_id
|
|
3637
|
-
resource_id =
|
|
3638
|
-
http_method = aws_api_gateway_method.options_method.http_method
|
|
3639
|
-
status_code = aws_api_gateway_method_response.options_response.status_code
|
|
5599
|
+
resource_id = each.value
|
|
5600
|
+
http_method = aws_api_gateway_method.options_method[each.key].http_method
|
|
5601
|
+
status_code = aws_api_gateway_method_response.options_response[each.key].status_code
|
|
3640
5602
|
|
|
3641
5603
|
response_parameters = {
|
|
3642
5604
|
"method.response.header.Access-Control-Allow-Headers" = "'\${join(",", var.cors_allow_headers)}'"
|
|
3643
5605
|
"method.response.header.Access-Control-Allow-Methods" = "'\${join(",", var.cors_allow_methods)}'"
|
|
3644
5606
|
"method.response.header.Access-Control-Allow-Origin" = "'\${join(",", var.cors_allow_origins)}'"
|
|
3645
5607
|
}
|
|
5608
|
+
|
|
5609
|
+
depends_on = [aws_api_gateway_integration.options_integration]
|
|
3646
5610
|
}
|
|
3647
5611
|
|
|
3648
5612
|
# API Gateway deployment
|
|
@@ -3650,13 +5614,28 @@ resource "aws_api_gateway_deployment" "api_deployment" {
|
|
|
3650
5614
|
rest_api_id = module.rest_api.api_id
|
|
3651
5615
|
|
|
3652
5616
|
triggers = {
|
|
3653
|
-
redeployment = sha1(jsonencode(
|
|
3654
|
-
aws_api_gateway_resource.
|
|
3655
|
-
|
|
3656
|
-
|
|
3657
|
-
|
|
3658
|
-
|
|
3659
|
-
|
|
5617
|
+
redeployment = sha1(jsonencode(concat(
|
|
5618
|
+
[for r in aws_api_gateway_resource.path_depth_0 : r.id],
|
|
5619
|
+
[for r in aws_api_gateway_resource.path_depth_1 : r.id],
|
|
5620
|
+
[for r in aws_api_gateway_resource.path_depth_2 : r.id],
|
|
5621
|
+
[for r in aws_api_gateway_resource.path_depth_3 : r.id],
|
|
5622
|
+
[for r in aws_api_gateway_resource.path_depth_4 : r.id],
|
|
5623
|
+
[for r in aws_api_gateway_resource.path_depth_5 : r.id],
|
|
5624
|
+
[for r in aws_api_gateway_resource.path_depth_6 : r.id],
|
|
5625
|
+
[for r in aws_api_gateway_resource.path_depth_7 : r.id],
|
|
5626
|
+
[for r in aws_api_gateway_resource.path_depth_8 : r.id],
|
|
5627
|
+
[for r in aws_api_gateway_resource.path_depth_9 : r.id],
|
|
5628
|
+
[for r in aws_api_gateway_resource.path_depth_10 : r.id],
|
|
5629
|
+
[for r in aws_api_gateway_resource.path_depth_11 : r.id],
|
|
5630
|
+
[for r in aws_api_gateway_resource.path_depth_12 : r.id],
|
|
5631
|
+
[for r in aws_api_gateway_resource.path_depth_13 : r.id],
|
|
5632
|
+
[for r in aws_api_gateway_resource.path_depth_14 : r.id],
|
|
5633
|
+
[for r in aws_api_gateway_resource.path_depth_15 : r.id],
|
|
5634
|
+
[for m in aws_api_gateway_method.operation_methods : m.id],
|
|
5635
|
+
[for i in aws_api_gateway_integration.lambda_integration : i.id],
|
|
5636
|
+
[for m in aws_api_gateway_method.options_method : m.id],
|
|
5637
|
+
[for i in aws_api_gateway_integration.options_integration : i.id],
|
|
5638
|
+
)))
|
|
3660
5639
|
}
|
|
3661
5640
|
|
|
3662
5641
|
lifecycle {
|
|
@@ -3664,7 +5643,7 @@ resource "aws_api_gateway_deployment" "api_deployment" {
|
|
|
3664
5643
|
}
|
|
3665
5644
|
|
|
3666
5645
|
depends_on = [
|
|
3667
|
-
aws_api_gateway_method.
|
|
5646
|
+
aws_api_gateway_method.operation_methods,
|
|
3668
5647
|
aws_api_gateway_integration.lambda_integration,
|
|
3669
5648
|
aws_api_gateway_method.options_method,
|
|
3670
5649
|
aws_api_gateway_integration.options_integration,
|
|
@@ -3674,11 +5653,63 @@ resource "aws_api_gateway_deployment" "api_deployment" {
|
|
|
3674
5653
|
]
|
|
3675
5654
|
}
|
|
3676
5655
|
|
|
5656
|
+
# KMS key for encrypting access logs at rest
|
|
5657
|
+
resource "aws_kms_key" "access_logs" {
|
|
5658
|
+
description = "CustomApi API access log encryption"
|
|
5659
|
+
deletion_window_in_days = 7
|
|
5660
|
+
enable_key_rotation = true
|
|
5661
|
+
|
|
5662
|
+
policy = jsonencode({
|
|
5663
|
+
Version = "2012-10-17"
|
|
5664
|
+
Statement = [
|
|
5665
|
+
{
|
|
5666
|
+
Sid = "Enable IAM User Permissions"
|
|
5667
|
+
Effect = "Allow"
|
|
5668
|
+
Principal = { AWS = "arn:aws:iam::\${data.aws_caller_identity.current.account_id}:root" }
|
|
5669
|
+
Action = "kms:*"
|
|
5670
|
+
Resource = "*"
|
|
5671
|
+
},
|
|
5672
|
+
{
|
|
5673
|
+
Sid = "Allow CloudWatch Logs"
|
|
5674
|
+
Effect = "Allow"
|
|
5675
|
+
Principal = { Service = "logs.\${data.aws_region.current.region}.amazonaws.com" }
|
|
5676
|
+
Action = [
|
|
5677
|
+
"kms:Encrypt",
|
|
5678
|
+
"kms:Decrypt",
|
|
5679
|
+
"kms:ReEncrypt*",
|
|
5680
|
+
"kms:GenerateDataKey*",
|
|
5681
|
+
"kms:DescribeKey"
|
|
5682
|
+
]
|
|
5683
|
+
Resource = "*"
|
|
5684
|
+
Condition = {
|
|
5685
|
+
ArnEquals = {
|
|
5686
|
+
"kms:EncryptionContext:aws:logs:arn" = "arn:aws:logs:\${data.aws_region.current.region}:\${data.aws_caller_identity.current.account_id}:log-group:/aws/apigateway/custom-api-\${random_string.suffix.result}/access"
|
|
5687
|
+
}
|
|
5688
|
+
}
|
|
5689
|
+
}
|
|
5690
|
+
]
|
|
5691
|
+
})
|
|
5692
|
+
|
|
5693
|
+
tags = var.tags
|
|
5694
|
+
}
|
|
5695
|
+
|
|
5696
|
+
resource "aws_kms_alias" "access_logs" {
|
|
5697
|
+
name = "alias/custom-api-\${random_string.suffix.result}-access-logs"
|
|
5698
|
+
target_key_id = aws_kms_key.access_logs.key_id
|
|
5699
|
+
}
|
|
5700
|
+
|
|
5701
|
+
# Access logs for the API Gateway stage
|
|
5702
|
+
resource "aws_cloudwatch_log_group" "access_logs" {
|
|
5703
|
+
name = "/aws/apigateway/custom-api-\${random_string.suffix.result}/access"
|
|
5704
|
+
retention_in_days = 365
|
|
5705
|
+
kms_key_id = aws_kms_key.access_logs.arn
|
|
5706
|
+
tags = var.tags
|
|
5707
|
+
}
|
|
5708
|
+
|
|
3677
5709
|
# API Gateway stage
|
|
3678
5710
|
resource "aws_api_gateway_stage" "api_stage" {
|
|
3679
5711
|
#checkov:skip=CKV_AWS_120:API Gateway caching not required for this use case
|
|
3680
|
-
#checkov:skip=
|
|
3681
|
-
#checkov:skip=CKV2_AWS_4:API Gateway logging level not applicable as access logging is disabled
|
|
5712
|
+
#checkov:skip=CKV2_AWS_4:Access logging is enabled below; verbose execution logging is intentionally not enabled
|
|
3682
5713
|
#checkov:skip=CKV2_AWS_51:Client certificate authentication not required for this use case
|
|
3683
5714
|
#checkov:skip=CKV2_AWS_77:WAFv2 Web ACL is attached via aws_wafv2_web_acl_association when var.enable_waf is true (default) and includes AWSManagedRulesKnownBadInputsRuleSet for Log4j protection; Checkov does not track the association across modules
|
|
3684
5715
|
deployment_id = aws_api_gateway_deployment.api_deployment.id
|
|
@@ -3686,9 +5717,39 @@ resource "aws_api_gateway_stage" "api_stage" {
|
|
|
3686
5717
|
stage_name = "prod"
|
|
3687
5718
|
xray_tracing_enabled = true
|
|
3688
5719
|
|
|
5720
|
+
access_log_settings {
|
|
5721
|
+
destination_arn = aws_cloudwatch_log_group.access_logs.arn
|
|
5722
|
+
format = jsonencode({
|
|
5723
|
+
requestId = "$context.requestId"
|
|
5724
|
+
ip = "$context.identity.sourceIp"
|
|
5725
|
+
caller = "$context.identity.caller"
|
|
5726
|
+
user = "$context.identity.user"
|
|
5727
|
+
requestTime = "$context.requestTime"
|
|
5728
|
+
httpMethod = "$context.httpMethod"
|
|
5729
|
+
resourcePath = "$context.resourcePath"
|
|
5730
|
+
status = "$context.status"
|
|
5731
|
+
protocol = "$context.protocol"
|
|
5732
|
+
responseLength = "$context.responseLength"
|
|
5733
|
+
})
|
|
5734
|
+
}
|
|
5735
|
+
|
|
3689
5736
|
tags = var.tags
|
|
3690
5737
|
|
|
3691
|
-
|
|
5738
|
+
# Ensure the account-level role is configured before the stage is created
|
|
5739
|
+
depends_on = [aws_api_gateway_deployment.api_deployment, module.account]
|
|
5740
|
+
}
|
|
5741
|
+
|
|
5742
|
+
# Default throttling applied to all resource paths and methods
|
|
5743
|
+
resource "aws_api_gateway_method_settings" "throttling" {
|
|
5744
|
+
#checkov:skip=CKV_AWS_225:API Gateway caching not required for this use case
|
|
5745
|
+
rest_api_id = module.rest_api.api_id
|
|
5746
|
+
stage_name = aws_api_gateway_stage.api_stage.stage_name
|
|
5747
|
+
method_path = "*/*"
|
|
5748
|
+
|
|
5749
|
+
settings {
|
|
5750
|
+
throttling_rate_limit = 10000
|
|
5751
|
+
throttling_burst_limit = 5000
|
|
5752
|
+
}
|
|
3692
5753
|
}
|
|
3693
5754
|
|
|
3694
5755
|
# API Gateway Resource Policy
|
|
@@ -3711,11 +5772,13 @@ resource "aws_api_gateway_rest_api_policy" "api_policy" {
|
|
|
3711
5772
|
|
|
3712
5773
|
# Lambda permission for API Gateway to invoke the function
|
|
3713
5774
|
resource "aws_lambda_permission" "api_gateway_invoke" {
|
|
5775
|
+
for_each = local.operations
|
|
5776
|
+
|
|
3714
5777
|
statement_id = "AllowExecutionFromAPIGateway"
|
|
3715
5778
|
action = "lambda:InvokeFunction"
|
|
3716
|
-
function_name = aws_lambda_function.api_lambda.function_name
|
|
5779
|
+
function_name = aws_lambda_function.api_lambda[each.key].function_name
|
|
3717
5780
|
principal = "apigateway.amazonaws.com"
|
|
3718
|
-
source_arn = "\${module.rest_api.api_execution_arn}
|
|
5781
|
+
source_arn = "\${module.rest_api.api_execution_arn}/*/\${local.permission_source_suffix[each.key]}"
|
|
3719
5782
|
|
|
3720
5783
|
depends_on = [module.rest_api, aws_lambda_function.api_lambda]
|
|
3721
5784
|
}
|
|
@@ -3727,7 +5790,7 @@ module "add_url_to_runtime_config" {
|
|
|
3727
5790
|
|
|
3728
5791
|
namespace = "connection"
|
|
3729
5792
|
key = "apis"
|
|
3730
|
-
value = { "CustomApi" = aws_api_gateway_stage.api_stage.invoke_url }
|
|
5793
|
+
value = { "CustomApi" = "\${aws_api_gateway_stage.api_stage.invoke_url}/" }
|
|
3731
5794
|
|
|
3732
5795
|
depends_on = [aws_api_gateway_stage.api_stage]
|
|
3733
5796
|
}
|
|
@@ -3780,78 +5843,83 @@ output "stage_id" {
|
|
|
3780
5843
|
value = aws_api_gateway_stage.api_stage.id
|
|
3781
5844
|
}
|
|
3782
5845
|
|
|
3783
|
-
# Lambda Function Outputs
|
|
3784
|
-
output "
|
|
3785
|
-
description = "
|
|
3786
|
-
value =
|
|
5846
|
+
# Lambda Function Outputs, keyed by operation name
|
|
5847
|
+
output "operations" {
|
|
5848
|
+
description = "Names of the API operations, each with its own Lambda function"
|
|
5849
|
+
value = keys(local.operations)
|
|
5850
|
+
}
|
|
5851
|
+
|
|
5852
|
+
output "lambda_function_names" {
|
|
5853
|
+
description = "Name of each operation's Lambda function, keyed by operation name"
|
|
5854
|
+
value = { for op, fn in aws_lambda_function.api_lambda : op => fn.function_name }
|
|
3787
5855
|
}
|
|
3788
5856
|
|
|
3789
|
-
output "
|
|
3790
|
-
description = "ARN of
|
|
3791
|
-
value = aws_lambda_function.api_lambda.arn
|
|
5857
|
+
output "lambda_function_arns" {
|
|
5858
|
+
description = "ARN of each operation's Lambda function, keyed by operation name"
|
|
5859
|
+
value = { for op, fn in aws_lambda_function.api_lambda : op => fn.arn }
|
|
3792
5860
|
}
|
|
3793
5861
|
|
|
3794
|
-
output "
|
|
3795
|
-
description = "Invoke ARN of
|
|
3796
|
-
value = aws_lambda_function.api_lambda.invoke_arn
|
|
5862
|
+
output "lambda_invoke_arns" {
|
|
5863
|
+
description = "Invoke ARN of each operation's Lambda function, keyed by operation name"
|
|
5864
|
+
value = { for op, fn in aws_lambda_function.api_lambda : op => fn.invoke_arn }
|
|
3797
5865
|
}
|
|
3798
5866
|
|
|
3799
|
-
output "
|
|
3800
|
-
description = "Qualified ARN of
|
|
3801
|
-
value = aws_lambda_function.api_lambda.qualified_arn
|
|
5867
|
+
output "lambda_qualified_arns" {
|
|
5868
|
+
description = "Qualified ARN of each operation's Lambda function, keyed by operation name"
|
|
5869
|
+
value = { for op, fn in aws_lambda_function.api_lambda : op => fn.qualified_arn }
|
|
3802
5870
|
}
|
|
3803
5871
|
|
|
3804
|
-
output "
|
|
3805
|
-
description = "Version of
|
|
3806
|
-
value = aws_lambda_function.api_lambda.version
|
|
5872
|
+
output "lambda_versions" {
|
|
5873
|
+
description = "Version of each operation's Lambda function, keyed by operation name"
|
|
5874
|
+
value = { for op, fn in aws_lambda_function.api_lambda : op => fn.version }
|
|
3807
5875
|
}
|
|
3808
5876
|
|
|
3809
5877
|
output "lambda_source_code_hash" {
|
|
3810
|
-
description = "Base64-encoded SHA256 hash of the Lambda deployment package"
|
|
3811
|
-
value =
|
|
5878
|
+
description = "Base64-encoded SHA256 hash of the Lambda deployment package, shared by every operation"
|
|
5879
|
+
value = data.archive_file.lambda_zip.output_base64sha256
|
|
3812
5880
|
}
|
|
3813
5881
|
|
|
3814
|
-
|
|
3815
|
-
|
|
3816
|
-
|
|
5882
|
+
# IAM Role Outputs, keyed by operation name
|
|
5883
|
+
output "lambda_execution_role_arns" {
|
|
5884
|
+
description = "ARN of each operation's Lambda execution role, keyed by operation name"
|
|
5885
|
+
value = { for op, role in aws_iam_role.lambda_execution_role : op => role.arn }
|
|
3817
5886
|
}
|
|
3818
5887
|
|
|
3819
|
-
|
|
3820
|
-
|
|
3821
|
-
|
|
3822
|
-
value = aws_iam_role.lambda_execution_role.arn
|
|
5888
|
+
output "lambda_execution_role_names" {
|
|
5889
|
+
description = "Name of each operation's Lambda execution role, keyed by operation name. Attach additional policies to a specific operation's role by name."
|
|
5890
|
+
value = { for op, role in aws_iam_role.lambda_execution_role : op => role.name }
|
|
3823
5891
|
}
|
|
3824
5892
|
|
|
3825
|
-
output "
|
|
3826
|
-
description = "
|
|
3827
|
-
value =
|
|
5893
|
+
output "security_group_id" {
|
|
5894
|
+
description = "Security group ID shared by the API Lambda functions, for use in ingress rules on resources they must reach (e.g. a database). Null unless enable_vpc is true."
|
|
5895
|
+
value = var.enable_vpc ? aws_security_group.api_lambda[0].id : null
|
|
3828
5896
|
}
|
|
3829
5897
|
|
|
3830
|
-
# Integration Outputs
|
|
3831
|
-
output "
|
|
3832
|
-
description = "ID of
|
|
3833
|
-
value = aws_api_gateway_integration.lambda_integration.id
|
|
5898
|
+
# Integration Outputs, keyed by operation name
|
|
5899
|
+
output "integration_ids" {
|
|
5900
|
+
description = "ID of each operation's Lambda integration, keyed by operation name"
|
|
5901
|
+
value = { for op, i in aws_api_gateway_integration.lambda_integration : op => i.id }
|
|
3834
5902
|
}
|
|
3835
5903
|
|
|
3836
|
-
output "
|
|
3837
|
-
description = "ID of
|
|
3838
|
-
value =
|
|
5904
|
+
output "method_ids" {
|
|
5905
|
+
description = "ID of each operation's API Gateway method, keyed by operation name"
|
|
5906
|
+
value = { for op, m in aws_api_gateway_method.operation_methods : op => m.id }
|
|
3839
5907
|
}
|
|
3840
5908
|
|
|
3841
|
-
output "
|
|
3842
|
-
description = "ID of
|
|
3843
|
-
value =
|
|
5909
|
+
output "resource_ids" {
|
|
5910
|
+
description = "ID of each API Gateway resource, keyed by its path"
|
|
5911
|
+
value = local.resource_ids
|
|
3844
5912
|
}
|
|
3845
5913
|
|
|
3846
|
-
# CloudWatch Log Groups
|
|
3847
|
-
output "
|
|
3848
|
-
description = "Name of
|
|
3849
|
-
value = aws_cloudwatch_log_group.lambda_logs.name
|
|
5914
|
+
# CloudWatch Log Groups, keyed by operation name
|
|
5915
|
+
output "lambda_log_group_names" {
|
|
5916
|
+
description = "Name of each operation's Lambda CloudWatch log group, keyed by operation name"
|
|
5917
|
+
value = { for op, lg in aws_cloudwatch_log_group.lambda_logs : op => lg.name }
|
|
3850
5918
|
}
|
|
3851
5919
|
|
|
3852
|
-
output "
|
|
3853
|
-
description = "ARN of
|
|
3854
|
-
value = aws_cloudwatch_log_group.lambda_logs.arn
|
|
5920
|
+
output "lambda_log_group_arns" {
|
|
5921
|
+
description = "ARN of each operation's Lambda CloudWatch log group, keyed by operation name"
|
|
5922
|
+
value = { for op, lg in aws_cloudwatch_log_group.lambda_logs : op => lg.arn }
|
|
3855
5923
|
}
|
|
3856
5924
|
"
|
|
3857
5925
|
`;
|