@aws/nx-plugin 1.0.0-rc.83 → 1.0.0-rc.85
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/generators.json +7 -0
- package/migrations.json +31 -1
- package/package.json +1 -1
- package/src/agentcore-gateway/__snapshots__/generator.spec.ts.snap +51 -2
- package/src/agentcore-harness/__snapshots__/generator.spec.ts.snap +4 -5
- package/src/agentcore-harness/files/project/README.md.template +4 -5
- package/src/internal/test-matrix/generator.js +16 -0
- package/src/internal/test-matrix/generator.js.map +1 -1
- package/src/migrations/latest/agentcore-harness-no-tools-by-default/__snapshots__/migration.spec.ts.snap +79 -0
- package/src/migrations/latest/agentcore-harness-no-tools-by-default/metadata.json +3 -0
- package/src/migrations/latest/agentcore-harness-no-tools-by-default/migration.d.ts +6 -0
- package/src/migrations/latest/agentcore-harness-no-tools-by-default/migration.js +87 -0
- package/src/migrations/latest/agentcore-harness-no-tools-by-default/migration.js.map +1 -0
- package/src/migrations/latest/rdb-terraform-aurora-app-module-defaults/__snapshots__/migration.spec.ts.snap +54 -0
- package/src/migrations/latest/rdb-terraform-aurora-app-module-defaults/metadata.json +3 -0
- package/src/migrations/latest/rdb-terraform-aurora-app-module-defaults/migration.d.ts +6 -0
- package/src/migrations/latest/rdb-terraform-aurora-app-module-defaults/migration.js +86 -0
- package/src/migrations/latest/rdb-terraform-aurora-app-module-defaults/migration.js.map +1 -0
- package/src/migrations/latest/terraform-declare-used-providers/metadata.json +3 -0
- package/src/migrations/latest/terraform-declare-used-providers/migration.d.ts +6 -0
- package/src/migrations/latest/terraform-declare-used-providers/migration.js +147 -0
- package/src/migrations/latest/terraform-declare-used-providers/migration.js.map +1 -0
- package/src/migrations/latest/terraform-harness-vpc-role-and-memory-grant/__snapshots__/migration.spec.ts.snap +521 -0
- package/src/migrations/latest/terraform-harness-vpc-role-and-memory-grant/metadata.json +3 -0
- package/src/migrations/latest/terraform-harness-vpc-role-and-memory-grant/migration.d.ts +6 -0
- package/src/migrations/latest/terraform-harness-vpc-role-and-memory-grant/migration.js +504 -0
- package/src/migrations/latest/terraform-harness-vpc-role-and-memory-grant/migration.js.map +1 -0
- package/src/migrations/latest/terraform-project-checkov-target-and-bootstrap-destroy/metadata.json +3 -0
- package/src/migrations/latest/terraform-project-checkov-target-and-bootstrap-destroy/migration.d.ts +6 -0
- package/src/migrations/latest/terraform-project-checkov-target-and-bootstrap-destroy/migration.js +146 -0
- package/src/migrations/latest/terraform-project-checkov-target-and-bootstrap-destroy/migration.js.map +1 -0
- package/src/migrations/latest/waf-log-group-cmk-encryption/__snapshots__/migration.spec.ts.snap +286 -0
- package/src/migrations/latest/waf-log-group-cmk-encryption/metadata.json +3 -0
- package/src/migrations/latest/waf-log-group-cmk-encryption/migration.d.ts +6 -0
- package/src/migrations/latest/waf-log-group-cmk-encryption/migration.js +238 -0
- package/src/migrations/latest/waf-log-group-cmk-encryption/migration.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/py/agent/__snapshots__/generator.protocols.spec.ts.snap +12 -0
- package/src/py/fast-api/__snapshots__/generator.terraform.spec.ts.snap +1875 -623
- package/src/py/fast-api/generator.js +2 -1
- package/src/py/fast-api/generator.js.map +1 -1
- package/src/py/lambda-function/__snapshots__/generator.spec.ts.snap +8 -0
- package/src/py/mcp-server/__snapshots__/generator.spec.ts.snap +4 -0
- package/src/py/rdb/__snapshots__/generator.spec.ts.snap +31 -2
- package/src/sdk/open-api.d.ts +2 -0
- package/src/sdk/open-api.js +2 -1
- package/src/sdk/open-api.js.map +1 -1
- package/src/smithy/ts/api/__snapshots__/generator.spec.ts.snap +1756 -457
- package/src/smithy/ts/api/generator.js +2 -1
- package/src/smithy/ts/api/generator.js.map +1 -1
- 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/src/providers.tf.template +6 -0
- 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.js +47 -4
- package/src/terraform/project/generator.js.map +1 -1
- package/src/trpc/backend/__snapshots__/generator.spec.ts.snap +1848 -614
- package/src/trpc/backend/files-operations/scripts/generate-operations.ts.template +40 -0
- package/src/trpc/backend/generator.js +10 -0
- package/src/trpc/backend/generator.js.map +1 -1
- package/src/ts/agent/__snapshots__/generator.spec.ts.snap +8 -0
- package/src/ts/dcr-proxy/__snapshots__/generator.spec.ts.snap +4 -0
- package/src/ts/lambda-function/__snapshots__/generator.spec.ts.snap +8 -0
- package/src/ts/mcp-server/__snapshots__/generator.spec.ts.snap +4 -0
- package/src/ts/rdb/__snapshots__/generator.spec.ts.snap +62 -4
- package/src/ts/react-website/app/__snapshots__/generator.spec.ts.snap +4 -0
- package/src/ts/react-website/cognito-auth/__snapshots__/generator.spec.ts.snap +35 -8
- package/src/ts/react-website/cognito-auth/__snapshots__/generator.terraform.spec.ts.snap +4 -0
- package/src/utils/agent-core-constructs/files/cdk/app/agentcore-harness/__nameKebabCase__/__nameKebabCase__.ts.template +39 -1
- package/src/utils/agent-core-constructs/files/terraform/app/agent-core/__nameKebabCase__/__nameKebabCase__.tf.template +8 -1
- package/src/utils/agent-core-constructs/files/terraform/app/agentcore-gateway/__nameKebabCase__/__nameKebabCase__.tf.template +57 -2
- package/src/utils/agent-core-constructs/files/terraform/app/agentcore-harness/__nameKebabCase__/__nameKebabCase__.tf.template +258 -24
- package/src/utils/agent-core-constructs/files/terraform/core/agent-core/runtime.tf.template +4 -0
- package/src/utils/api-constructs/api-constructs.js +11 -0
- package/src/utils/api-constructs/api-constructs.js.map +1 -1
- package/src/utils/api-constructs/files/terraform/app/apis/http/__apiNameKebabCase__/__apiNameKebabCase__.tf.template +251 -3
- package/src/utils/api-constructs/files/terraform/app/apis/rest/__apiNameKebabCase__/__apiNameKebabCase__.tf.template +437 -2
- package/src/utils/api-constructs/files/terraform/core/api/rest/rest-api/rest-api.tf.template +60 -7
- package/src/utils/api-constructs/open-api-metadata.d.ts +20 -3
- package/src/utils/api-constructs/open-api-metadata.js +64 -8
- 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 +55 -0
- package/src/utils/api-constructs/trpc-operations-metadata.js.map +1 -0
- package/src/utils/dcr-proxy-constructs/files/terraform/app/dcr-proxies/__nameKebabCase__/__nameKebabCase__.tf.template +4 -0
- package/src/utils/files/terraform/src/metrics/providers.tf.template +12 -0
- package/src/utils/function-constructs/files/terraform/app/lambda-functions/__nameKebabCase__/__nameKebabCase__.tf.template +4 -0
- package/src/utils/identity-constructs/files/cdk/core/user-identity.ts.template +33 -8
- package/src/utils/identity-constructs/files/terraform/core/user-identity/add-callback-url/add-callback-url.tf.template +4 -0
- package/src/utils/identity-constructs/files/terraform/core/user-identity/identity/identity.tf.template +51 -2
- package/src/utils/rdb-constructs/files/cdk/core/rdb/aurora.ts.template +18 -0
- package/src/utils/rdb-constructs/files/terraform/app/dbs/__nameKebabCase__/__nameKebabCase__.tf.template +15 -4
- package/src/utils/rdb-constructs/files/terraform/core/rdb/aurora/aurora.tf.template +2 -2
- package/src/utils/rdb-constructs/rdb-constructs.d.ts +12 -0
- package/src/utils/rdb-constructs/rdb-constructs.js +24 -3
- package/src/utils/rdb-constructs/rdb-constructs.js.map +1 -1
- package/src/utils/website-constructs/files/terraform/core/static-website/static-website.tf.template +4 -0
|
@@ -9,9 +9,26 @@ export interface AddOpenApiMetadataGenerateTargetOptions {
|
|
|
9
9
|
apiNameKebabCase: string;
|
|
10
10
|
specPath: string;
|
|
11
11
|
specBuildTargetName: string;
|
|
12
|
+
/**
|
|
13
|
+
* How integrations are mapped to operations. Terraform only needs the
|
|
14
|
+
* operations metadata for the `isolated` pattern, since the `shared` pattern
|
|
15
|
+
* routes every operation to one proxy Lambda.
|
|
16
|
+
*/
|
|
17
|
+
integrationPattern?: 'isolated' | 'shared';
|
|
12
18
|
}
|
|
13
19
|
/**
|
|
14
|
-
* Adds a
|
|
15
|
-
*
|
|
20
|
+
* Adds a target which generates metadata about the API's operations from its
|
|
21
|
+
* OpenAPI specification, so that infrastructure can define an integration per
|
|
22
|
+
* operation.
|
|
23
|
+
*
|
|
24
|
+
* For CDK this generates TypeScript, giving the construct type-safe integrations.
|
|
25
|
+
* For Terraform this generates JSON, which the vended module reads to build one
|
|
26
|
+
* Lambda function and route per operation.
|
|
16
27
|
*/
|
|
17
|
-
export declare const addSharedConstructsOpenApiMetadataGenerateTarget: (tree: Tree,
|
|
28
|
+
export declare const addSharedConstructsOpenApiMetadataGenerateTarget: (tree: Tree, options: AddOpenApiMetadataGenerateTargetOptions) => void;
|
|
29
|
+
/**
|
|
30
|
+
* Directory the operations metadata for an API is generated into, relative to
|
|
31
|
+
* the shared Terraform project's `src`. The vended module reads the file from
|
|
32
|
+
* here, so the module template and this target must agree on the location.
|
|
33
|
+
*/
|
|
34
|
+
export declare const terraformOperationsMetadataDir: (apiNameKebabCase: string) => string;
|
|
@@ -4,16 +4,23 @@
|
|
|
4
4
|
*/ import { joinPathFragments, updateJson } from "@nx/devkit";
|
|
5
5
|
import { updateGitIgnore } from "../git.js";
|
|
6
6
|
import { addDependencyToTargetIfNotPresent } from "../nx.js";
|
|
7
|
-
import { PACKAGES_DIR, SHARED_CONSTRUCTS_DIR } from "../shared-constructs-constants.js";
|
|
7
|
+
import { PACKAGES_DIR, SHARED_CONSTRUCTS_DIR, SHARED_TERRAFORM_DIR } from "../shared-constructs-constants.js";
|
|
8
8
|
/**
|
|
9
|
-
* Adds a
|
|
10
|
-
*
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
9
|
+
* Adds a target which generates metadata about the API's operations from its
|
|
10
|
+
* OpenAPI specification, so that infrastructure can define an integration per
|
|
11
|
+
* operation.
|
|
12
|
+
*
|
|
13
|
+
* For CDK this generates TypeScript, giving the construct type-safe integrations.
|
|
14
|
+
* For Terraform this generates JSON, which the vended module reads to build one
|
|
15
|
+
* Lambda function and route per operation.
|
|
16
|
+
*/ export const addSharedConstructsOpenApiMetadataGenerateTarget = (tree, options)=>{
|
|
17
|
+
if (options.iac === 'cdk') {
|
|
18
|
+
addCdkOpenApiMetadataGenerateTarget(tree, options);
|
|
19
|
+
} else if (options.iac === 'terraform') {
|
|
20
|
+
addTerraformOpenApiOperationsGenerateTarget(tree, options);
|
|
16
21
|
}
|
|
22
|
+
};
|
|
23
|
+
const addCdkOpenApiMetadataGenerateTarget = (tree, { apiNameKebabCase, specPath, specBuildTargetName })=>{
|
|
17
24
|
const generatedMetadataDir = joinPathFragments('generated', apiNameKebabCase);
|
|
18
25
|
const generatedMetadataDirFromRoot = joinPathFragments(joinPathFragments(PACKAGES_DIR, SHARED_CONSTRUCTS_DIR), 'src', generatedMetadataDir);
|
|
19
26
|
updateJson(tree, joinPathFragments(PACKAGES_DIR, SHARED_CONSTRUCTS_DIR, 'project.json'), (config)=>{
|
|
@@ -58,5 +65,54 @@ import { PACKAGES_DIR, SHARED_CONSTRUCTS_DIR } from "../shared-constructs-consta
|
|
|
58
65
|
joinPathFragments('src', generatedMetadataDir)
|
|
59
66
|
]);
|
|
60
67
|
};
|
|
68
|
+
/**
|
|
69
|
+
* Directory the operations metadata for an API is generated into, relative to
|
|
70
|
+
* the shared Terraform project's `src`. The vended module reads the file from
|
|
71
|
+
* here, so the module template and this target must agree on the location.
|
|
72
|
+
*/ export const terraformOperationsMetadataDir = (apiNameKebabCase)=>joinPathFragments('generated', apiNameKebabCase);
|
|
73
|
+
const addTerraformOpenApiOperationsGenerateTarget = (tree, { apiNameKebabCase, specPath, specBuildTargetName, integrationPattern })=>{
|
|
74
|
+
// The `shared` pattern routes every operation to a single proxy Lambda, so the
|
|
75
|
+
// module has no need for the operations metadata.
|
|
76
|
+
if (integrationPattern !== 'isolated') {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
const generatedDirFromRoot = joinPathFragments(PACKAGES_DIR, SHARED_TERRAFORM_DIR, 'src', terraformOperationsMetadataDir(apiNameKebabCase));
|
|
80
|
+
updateJson(tree, joinPathFragments(PACKAGES_DIR, SHARED_TERRAFORM_DIR, 'project.json'), (config)=>{
|
|
81
|
+
config.targets ??= {};
|
|
82
|
+
// Terraform reads the operations metadata with `file()`, so it must exist
|
|
83
|
+
// before plan; the target is wired into `build` below.
|
|
84
|
+
const operationsTargetName = `generate:${apiNameKebabCase}-operations`;
|
|
85
|
+
if (!config.targets[operationsTargetName]) {
|
|
86
|
+
config.targets[operationsTargetName] = {
|
|
87
|
+
cache: true,
|
|
88
|
+
executor: 'nx:run-commands',
|
|
89
|
+
inputs: [
|
|
90
|
+
{
|
|
91
|
+
dependentTasksOutputFiles: '**/*.json'
|
|
92
|
+
}
|
|
93
|
+
],
|
|
94
|
+
outputs: [
|
|
95
|
+
joinPathFragments('{workspaceRoot}', generatedDirFromRoot)
|
|
96
|
+
],
|
|
97
|
+
options: {
|
|
98
|
+
commands: [
|
|
99
|
+
`nx g @aws/nx-plugin:open-api#json-metadata --openApiSpecPath="${specPath}" --outputPath="${generatedDirFromRoot}" --no-interactive`
|
|
100
|
+
]
|
|
101
|
+
},
|
|
102
|
+
dependsOn: [
|
|
103
|
+
specBuildTargetName
|
|
104
|
+
]
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
addDependencyToTargetIfNotPresent(config, 'build', operationsTargetName);
|
|
108
|
+
return config;
|
|
109
|
+
});
|
|
110
|
+
// Ignore the generated metadata by default
|
|
111
|
+
// Users can safely remove the entry from the .gitignore if they prefer to check it in
|
|
112
|
+
updateGitIgnore(tree, joinPathFragments(PACKAGES_DIR, SHARED_TERRAFORM_DIR), (patterns)=>[
|
|
113
|
+
...patterns,
|
|
114
|
+
joinPathFragments('src', terraformOperationsMetadataDir(apiNameKebabCase))
|
|
115
|
+
]);
|
|
116
|
+
};
|
|
61
117
|
|
|
62
118
|
//# sourceMappingURL=open-api-metadata.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../packages/nx-plugin/src/utils/api-constructs/open-api-metadata.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n joinPathFragments,\n type ProjectConfiguration,\n type Tree,\n updateJson,\n} from '@nx/devkit';\nimport { updateGitIgnore } from '../git.js';\nimport type { Iac } from '../iac.js';\nimport { addDependencyToTargetIfNotPresent } from '../nx.js';\nimport {\n PACKAGES_DIR,\n SHARED_CONSTRUCTS_DIR,\n} from '../shared-constructs-constants.js';\n\nexport interface AddOpenApiMetadataGenerateTargetOptions {\n iac: Iac;\n apiNameKebabCase: string;\n specPath: string;\n specBuildTargetName: string;\n}\n\n/**\n * Adds a
|
|
1
|
+
{"version":3,"sources":["../../../../../../packages/nx-plugin/src/utils/api-constructs/open-api-metadata.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n joinPathFragments,\n type ProjectConfiguration,\n type Tree,\n updateJson,\n} from '@nx/devkit';\nimport { updateGitIgnore } from '../git.js';\nimport type { Iac } from '../iac.js';\nimport { addDependencyToTargetIfNotPresent } from '../nx.js';\nimport {\n PACKAGES_DIR,\n SHARED_CONSTRUCTS_DIR,\n SHARED_TERRAFORM_DIR,\n} from '../shared-constructs-constants.js';\n\nexport interface AddOpenApiMetadataGenerateTargetOptions {\n iac: Iac;\n apiNameKebabCase: string;\n specPath: string;\n specBuildTargetName: string;\n /**\n * How integrations are mapped to operations. Terraform only needs the\n * operations metadata for the `isolated` pattern, since the `shared` pattern\n * routes every operation to one proxy Lambda.\n */\n integrationPattern?: 'isolated' | 'shared';\n}\n\n/**\n * Adds a target which generates metadata about the API's operations from its\n * OpenAPI specification, so that infrastructure can define an integration per\n * operation.\n *\n * For CDK this generates TypeScript, giving the construct type-safe integrations.\n * For Terraform this generates JSON, which the vended module reads to build one\n * Lambda function and route per operation.\n */\nexport const addSharedConstructsOpenApiMetadataGenerateTarget = (\n tree: Tree,\n options: AddOpenApiMetadataGenerateTargetOptions,\n) => {\n if (options.iac === 'cdk') {\n addCdkOpenApiMetadataGenerateTarget(tree, options);\n } else if (options.iac === 'terraform') {\n addTerraformOpenApiOperationsGenerateTarget(tree, options);\n }\n};\n\nconst addCdkOpenApiMetadataGenerateTarget = (\n tree: Tree,\n {\n apiNameKebabCase,\n specPath,\n specBuildTargetName,\n }: AddOpenApiMetadataGenerateTargetOptions,\n) => {\n const generatedMetadataDir = joinPathFragments('generated', apiNameKebabCase);\n const generatedMetadataDirFromRoot = joinPathFragments(\n joinPathFragments(PACKAGES_DIR, SHARED_CONSTRUCTS_DIR),\n 'src',\n generatedMetadataDir,\n );\n\n updateJson(\n tree,\n joinPathFragments(PACKAGES_DIR, SHARED_CONSTRUCTS_DIR, 'project.json'),\n (config: ProjectConfiguration) => {\n if (!config.targets) {\n config.targets = {};\n }\n if (!config.targets.build) {\n config.targets.build = {};\n }\n // If not already defined, add a target to generate metadata from the OpenAPI spec, used\n // for providing a type-safe CDK construct\n const metadataTargetName = `generate:${apiNameKebabCase}-metadata`;\n if (!config.targets[metadataTargetName]) {\n config.targets[metadataTargetName] = {\n cache: true,\n executor: 'nx:run-commands',\n inputs: [\n {\n dependentTasksOutputFiles: '**/*.json',\n },\n ],\n outputs: [\n joinPathFragments('{workspaceRoot}', generatedMetadataDirFromRoot),\n ],\n options: {\n commands: [\n `nx g @aws/nx-plugin:open-api#ts-metadata --openApiSpecPath=\"${specPath}\" --outputPath=\"${generatedMetadataDirFromRoot}\" --no-interactive`,\n ],\n },\n dependsOn: [specBuildTargetName],\n };\n }\n addDependencyToTargetIfNotPresent(config, 'compile', metadataTargetName);\n return config;\n },\n );\n\n // Ignore the generated metadata by default\n // Users can safely remove the entry from the .gitignore if they prefer to check it in\n updateGitIgnore(\n tree,\n joinPathFragments(PACKAGES_DIR, SHARED_CONSTRUCTS_DIR),\n (patterns) => [...patterns, joinPathFragments('src', generatedMetadataDir)],\n );\n};\n\n/**\n * Directory the operations metadata for an API is generated into, relative to\n * the shared Terraform project's `src`. The vended module reads the file from\n * here, so the module template and this target must agree on the location.\n */\nexport const terraformOperationsMetadataDir = (apiNameKebabCase: string) =>\n joinPathFragments('generated', apiNameKebabCase);\n\nconst addTerraformOpenApiOperationsGenerateTarget = (\n tree: Tree,\n {\n apiNameKebabCase,\n specPath,\n specBuildTargetName,\n integrationPattern,\n }: AddOpenApiMetadataGenerateTargetOptions,\n) => {\n // The `shared` pattern routes every operation to a single proxy Lambda, so the\n // module has no need for the operations metadata.\n if (integrationPattern !== 'isolated') {\n return;\n }\n\n const generatedDirFromRoot = joinPathFragments(\n PACKAGES_DIR,\n SHARED_TERRAFORM_DIR,\n 'src',\n terraformOperationsMetadataDir(apiNameKebabCase),\n );\n\n updateJson(\n tree,\n joinPathFragments(PACKAGES_DIR, SHARED_TERRAFORM_DIR, 'project.json'),\n (config: ProjectConfiguration) => {\n config.targets ??= {};\n // Terraform reads the operations metadata with `file()`, so it must exist\n // before plan; the target is wired into `build` below.\n const operationsTargetName = `generate:${apiNameKebabCase}-operations`;\n if (!config.targets[operationsTargetName]) {\n config.targets[operationsTargetName] = {\n cache: true,\n executor: 'nx:run-commands',\n inputs: [\n {\n dependentTasksOutputFiles: '**/*.json',\n },\n ],\n outputs: [joinPathFragments('{workspaceRoot}', generatedDirFromRoot)],\n options: {\n commands: [\n `nx g @aws/nx-plugin:open-api#json-metadata --openApiSpecPath=\"${specPath}\" --outputPath=\"${generatedDirFromRoot}\" --no-interactive`,\n ],\n },\n dependsOn: [specBuildTargetName],\n };\n }\n addDependencyToTargetIfNotPresent(config, 'build', operationsTargetName);\n return config;\n },\n );\n\n // Ignore the generated metadata by default\n // Users can safely remove the entry from the .gitignore if they prefer to check it in\n updateGitIgnore(\n tree,\n joinPathFragments(PACKAGES_DIR, SHARED_TERRAFORM_DIR),\n (patterns) => [\n ...patterns,\n joinPathFragments(\n 'src',\n terraformOperationsMetadataDir(apiNameKebabCase),\n ),\n ],\n );\n};\n"],"names":["joinPathFragments","updateJson","updateGitIgnore","addDependencyToTargetIfNotPresent","PACKAGES_DIR","SHARED_CONSTRUCTS_DIR","SHARED_TERRAFORM_DIR","addSharedConstructsOpenApiMetadataGenerateTarget","tree","options","iac","addCdkOpenApiMetadataGenerateTarget","addTerraformOpenApiOperationsGenerateTarget","apiNameKebabCase","specPath","specBuildTargetName","generatedMetadataDir","generatedMetadataDirFromRoot","config","targets","build","metadataTargetName","cache","executor","inputs","dependentTasksOutputFiles","outputs","commands","dependsOn","patterns","terraformOperationsMetadataDir","integrationPattern","generatedDirFromRoot","operationsTargetName"],"mappings":"AAAA;;;CAGC,GACD,SACEA,iBAAiB,EAGjBC,UAAU,QACL,aAAa;AACpB,SAASC,eAAe,QAAQ,YAAY;AAE5C,SAASC,iCAAiC,QAAQ,WAAW;AAC7D,SACEC,YAAY,EACZC,qBAAqB,EACrBC,oBAAoB,QACf,oCAAoC;AAe3C;;;;;;;;CAQC,GACD,OAAO,MAAMC,mDAAmD,CAC9DC,MACAC;IAEA,IAAIA,QAAQC,GAAG,KAAK,OAAO;QACzBC,oCAAoCH,MAAMC;IAC5C,OAAO,IAAIA,QAAQC,GAAG,KAAK,aAAa;QACtCE,4CAA4CJ,MAAMC;IACpD;AACF,EAAE;AAEF,MAAME,sCAAsC,CAC1CH,MACA,EACEK,gBAAgB,EAChBC,QAAQ,EACRC,mBAAmB,EACqB;IAE1C,MAAMC,uBAAuBhB,kBAAkB,aAAaa;IAC5D,MAAMI,+BAA+BjB,kBACnCA,kBAAkBI,cAAcC,wBAChC,OACAW;IAGFf,WACEO,MACAR,kBAAkBI,cAAcC,uBAAuB,iBACvD,CAACa;QACC,IAAI,CAACA,OAAOC,OAAO,EAAE;YACnBD,OAAOC,OAAO,GAAG,CAAC;QACpB;QACA,IAAI,CAACD,OAAOC,OAAO,CAACC,KAAK,EAAE;YACzBF,OAAOC,OAAO,CAACC,KAAK,GAAG,CAAC;QAC1B;QACA,wFAAwF;QACxF,0CAA0C;QAC1C,MAAMC,qBAAqB,CAAC,SAAS,EAAER,iBAAiB,SAAS,CAAC;QAClE,IAAI,CAACK,OAAOC,OAAO,CAACE,mBAAmB,EAAE;YACvCH,OAAOC,OAAO,CAACE,mBAAmB,GAAG;gBACnCC,OAAO;gBACPC,UAAU;gBACVC,QAAQ;oBACN;wBACEC,2BAA2B;oBAC7B;iBACD;gBACDC,SAAS;oBACP1B,kBAAkB,mBAAmBiB;iBACtC;gBACDR,SAAS;oBACPkB,UAAU;wBACR,CAAC,4DAA4D,EAAEb,SAAS,gBAAgB,EAAEG,6BAA6B,kBAAkB,CAAC;qBAC3I;gBACH;gBACAW,WAAW;oBAACb;iBAAoB;YAClC;QACF;QACAZ,kCAAkCe,QAAQ,WAAWG;QACrD,OAAOH;IACT;IAGF,2CAA2C;IAC3C,sFAAsF;IACtFhB,gBACEM,MACAR,kBAAkBI,cAAcC,wBAChC,CAACwB,WAAa;eAAIA;YAAU7B,kBAAkB,OAAOgB;SAAsB;AAE/E;AAEA;;;;CAIC,GACD,OAAO,MAAMc,iCAAiC,CAACjB,mBAC7Cb,kBAAkB,aAAaa,kBAAkB;AAEnD,MAAMD,8CAA8C,CAClDJ,MACA,EACEK,gBAAgB,EAChBC,QAAQ,EACRC,mBAAmB,EACnBgB,kBAAkB,EACsB;IAE1C,+EAA+E;IAC/E,kDAAkD;IAClD,IAAIA,uBAAuB,YAAY;QACrC;IACF;IAEA,MAAMC,uBAAuBhC,kBAC3BI,cACAE,sBACA,OACAwB,+BAA+BjB;IAGjCZ,WACEO,MACAR,kBAAkBI,cAAcE,sBAAsB,iBACtD,CAACY;QACCA,OAAOC,OAAO,KAAK,CAAC;QACpB,0EAA0E;QAC1E,uDAAuD;QACvD,MAAMc,uBAAuB,CAAC,SAAS,EAAEpB,iBAAiB,WAAW,CAAC;QACtE,IAAI,CAACK,OAAOC,OAAO,CAACc,qBAAqB,EAAE;YACzCf,OAAOC,OAAO,CAACc,qBAAqB,GAAG;gBACrCX,OAAO;gBACPC,UAAU;gBACVC,QAAQ;oBACN;wBACEC,2BAA2B;oBAC7B;iBACD;gBACDC,SAAS;oBAAC1B,kBAAkB,mBAAmBgC;iBAAsB;gBACrEvB,SAAS;oBACPkB,UAAU;wBACR,CAAC,8DAA8D,EAAEb,SAAS,gBAAgB,EAAEkB,qBAAqB,kBAAkB,CAAC;qBACrI;gBACH;gBACAJ,WAAW;oBAACb;iBAAoB;YAClC;QACF;QACAZ,kCAAkCe,QAAQ,SAASe;QACnD,OAAOf;IACT;IAGF,2CAA2C;IAC3C,sFAAsF;IACtFhB,gBACEM,MACAR,kBAAkBI,cAAcE,uBAChC,CAACuB,WAAa;eACTA;YACH7B,kBACE,OACA8B,+BAA+BjB;SAElC;AAEL"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
import { type ProjectConfiguration, type Tree } from '@nx/devkit';
|
|
6
|
+
export interface AddTrpcOperationsMetadataTargetOptions {
|
|
7
|
+
apiNameKebabCase: string;
|
|
8
|
+
/** The tRPC backend project the operations are derived from. */
|
|
9
|
+
project: ProjectConfiguration;
|
|
10
|
+
/** Template variables for the vended script (module format). */
|
|
11
|
+
templateOptions: Record<string, unknown>;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Adds operations metadata generation for a tRPC API deployed with Terraform.
|
|
15
|
+
*
|
|
16
|
+
* tRPC has no OpenAPI specification, so the operations are derived by walking
|
|
17
|
+
* the router: a vended script writes the same JSON shape the OpenAPI-based
|
|
18
|
+
* generator produces, which the Terraform module reads to define one Lambda
|
|
19
|
+
* function and route per procedure.
|
|
20
|
+
*/
|
|
21
|
+
export declare const addTrpcOperationsMetadataTarget: (tree: Tree, { apiNameKebabCase, project, templateOptions, }: AddTrpcOperationsMetadataTargetOptions) => void;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/ import { generateFiles, joinPathFragments, OverwriteStrategy, updateJson } from "@nx/devkit";
|
|
5
|
+
import { OPERATIONS_METADATA_FILE_NAME } from "../../open-api/json-metadata/generator.js";
|
|
6
|
+
import { updateGitIgnore } from "../git.js";
|
|
7
|
+
import { addDependencyToTargetIfNotPresent } from "../nx.js";
|
|
8
|
+
import { PACKAGES_DIR, SHARED_TERRAFORM_DIR } from "../shared-constructs-constants.js";
|
|
9
|
+
import { terraformOperationsMetadataDir } from "./open-api-metadata.js";
|
|
10
|
+
/**
|
|
11
|
+
* Adds operations metadata generation for a tRPC API deployed with Terraform.
|
|
12
|
+
*
|
|
13
|
+
* tRPC has no OpenAPI specification, so the operations are derived by walking
|
|
14
|
+
* the router: a vended script writes the same JSON shape the OpenAPI-based
|
|
15
|
+
* generator produces, which the Terraform module reads to define one Lambda
|
|
16
|
+
* function and route per procedure.
|
|
17
|
+
*/ export const addTrpcOperationsMetadataTarget = (tree, { apiNameKebabCase, project, templateOptions })=>{
|
|
18
|
+
generateFiles(tree, joinPathFragments(import.meta.dirname, '..', '..', 'trpc', 'backend', 'files-operations'), project.root, templateOptions, {
|
|
19
|
+
overwriteStrategy: OverwriteStrategy.Overwrite
|
|
20
|
+
});
|
|
21
|
+
const generatedDirFromRoot = joinPathFragments(PACKAGES_DIR, SHARED_TERRAFORM_DIR, 'src', terraformOperationsMetadataDir(apiNameKebabCase));
|
|
22
|
+
const operationsFile = joinPathFragments(generatedDirFromRoot, OPERATIONS_METADATA_FILE_NAME);
|
|
23
|
+
project.targets ??= {};
|
|
24
|
+
project.targets.operations ??= {
|
|
25
|
+
cache: true,
|
|
26
|
+
executor: 'nx:run-commands',
|
|
27
|
+
outputs: [
|
|
28
|
+
joinPathFragments('{workspaceRoot}', generatedDirFromRoot)
|
|
29
|
+
],
|
|
30
|
+
options: {
|
|
31
|
+
commands: [
|
|
32
|
+
`tsx {projectRoot}/scripts/generate-operations.ts ${operationsFile}`
|
|
33
|
+
],
|
|
34
|
+
cwd: '{workspaceRoot}'
|
|
35
|
+
},
|
|
36
|
+
dependsOn: [
|
|
37
|
+
'compile'
|
|
38
|
+
]
|
|
39
|
+
};
|
|
40
|
+
addDependencyToTargetIfNotPresent(project, 'build', 'operations');
|
|
41
|
+
// The shared Terraform project reads the generated file with `file()`, so it
|
|
42
|
+
// must be written before that project is planned.
|
|
43
|
+
updateJson(tree, joinPathFragments(PACKAGES_DIR, SHARED_TERRAFORM_DIR, 'project.json'), (config)=>{
|
|
44
|
+
addDependencyToTargetIfNotPresent(config, 'build', `${project.name}:operations`);
|
|
45
|
+
return config;
|
|
46
|
+
});
|
|
47
|
+
// Ignore the generated metadata by default
|
|
48
|
+
// Users can safely remove the entry from the .gitignore if they prefer to check it in
|
|
49
|
+
updateGitIgnore(tree, joinPathFragments(PACKAGES_DIR, SHARED_TERRAFORM_DIR), (patterns)=>[
|
|
50
|
+
...patterns,
|
|
51
|
+
joinPathFragments('src', terraformOperationsMetadataDir(apiNameKebabCase))
|
|
52
|
+
]);
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
//# sourceMappingURL=trpc-operations-metadata.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../packages/nx-plugin/src/utils/api-constructs/trpc-operations-metadata.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n generateFiles,\n joinPathFragments,\n OverwriteStrategy,\n type ProjectConfiguration,\n type Tree,\n updateJson,\n} from '@nx/devkit';\nimport { OPERATIONS_METADATA_FILE_NAME } from '../../open-api/json-metadata/generator.js';\nimport { updateGitIgnore } from '../git.js';\nimport { addDependencyToTargetIfNotPresent } from '../nx.js';\nimport {\n PACKAGES_DIR,\n SHARED_TERRAFORM_DIR,\n} from '../shared-constructs-constants.js';\nimport { terraformOperationsMetadataDir } from './open-api-metadata.js';\n\nexport interface AddTrpcOperationsMetadataTargetOptions {\n apiNameKebabCase: string;\n /** The tRPC backend project the operations are derived from. */\n project: ProjectConfiguration;\n /** Template variables for the vended script (module format). */\n templateOptions: Record<string, unknown>;\n}\n\n/**\n * Adds operations metadata generation for a tRPC API deployed with Terraform.\n *\n * tRPC has no OpenAPI specification, so the operations are derived by walking\n * the router: a vended script writes the same JSON shape the OpenAPI-based\n * generator produces, which the Terraform module reads to define one Lambda\n * function and route per procedure.\n */\nexport const addTrpcOperationsMetadataTarget = (\n tree: Tree,\n {\n apiNameKebabCase,\n project,\n templateOptions,\n }: AddTrpcOperationsMetadataTargetOptions,\n) => {\n generateFiles(\n tree,\n joinPathFragments(\n import.meta.dirname,\n '..',\n '..',\n 'trpc',\n 'backend',\n 'files-operations',\n ),\n project.root,\n templateOptions,\n {\n overwriteStrategy: OverwriteStrategy.Overwrite,\n },\n );\n\n const generatedDirFromRoot = joinPathFragments(\n PACKAGES_DIR,\n SHARED_TERRAFORM_DIR,\n 'src',\n terraformOperationsMetadataDir(apiNameKebabCase),\n );\n const operationsFile = joinPathFragments(\n generatedDirFromRoot,\n OPERATIONS_METADATA_FILE_NAME,\n );\n\n project.targets ??= {};\n project.targets.operations ??= {\n cache: true,\n executor: 'nx:run-commands',\n outputs: [joinPathFragments('{workspaceRoot}', generatedDirFromRoot)],\n options: {\n commands: [\n `tsx {projectRoot}/scripts/generate-operations.ts ${operationsFile}`,\n ],\n cwd: '{workspaceRoot}',\n },\n dependsOn: ['compile'],\n };\n addDependencyToTargetIfNotPresent(project, 'build', 'operations');\n\n // The shared Terraform project reads the generated file with `file()`, so it\n // must be written before that project is planned.\n updateJson(\n tree,\n joinPathFragments(PACKAGES_DIR, SHARED_TERRAFORM_DIR, 'project.json'),\n (config: ProjectConfiguration) => {\n addDependencyToTargetIfNotPresent(\n config,\n 'build',\n `${project.name}:operations`,\n );\n return config;\n },\n );\n\n // Ignore the generated metadata by default\n // Users can safely remove the entry from the .gitignore if they prefer to check it in\n updateGitIgnore(\n tree,\n joinPathFragments(PACKAGES_DIR, SHARED_TERRAFORM_DIR),\n (patterns) => [\n ...patterns,\n joinPathFragments(\n 'src',\n terraformOperationsMetadataDir(apiNameKebabCase),\n ),\n ],\n );\n};\n"],"names":["generateFiles","joinPathFragments","OverwriteStrategy","updateJson","OPERATIONS_METADATA_FILE_NAME","updateGitIgnore","addDependencyToTargetIfNotPresent","PACKAGES_DIR","SHARED_TERRAFORM_DIR","terraformOperationsMetadataDir","addTrpcOperationsMetadataTarget","tree","apiNameKebabCase","project","templateOptions","dirname","root","overwriteStrategy","Overwrite","generatedDirFromRoot","operationsFile","targets","operations","cache","executor","outputs","options","commands","cwd","dependsOn","config","name","patterns"],"mappings":"AAAA;;;CAGC,GACD,SACEA,aAAa,EACbC,iBAAiB,EACjBC,iBAAiB,EAGjBC,UAAU,QACL,aAAa;AACpB,SAASC,6BAA6B,QAAQ,4CAA4C;AAC1F,SAASC,eAAe,QAAQ,YAAY;AAC5C,SAASC,iCAAiC,QAAQ,WAAW;AAC7D,SACEC,YAAY,EACZC,oBAAoB,QACf,oCAAoC;AAC3C,SAASC,8BAA8B,QAAQ,yBAAyB;AAUxE;;;;;;;CAOC,GACD,OAAO,MAAMC,kCAAkC,CAC7CC,MACA,EACEC,gBAAgB,EAChBC,OAAO,EACPC,eAAe,EACwB;IAEzCd,cACEW,MACAV,kBACE,YAAYc,OAAO,EACnB,MACA,MACA,QACA,WACA,qBAEFF,QAAQG,IAAI,EACZF,iBACA;QACEG,mBAAmBf,kBAAkBgB,SAAS;IAChD;IAGF,MAAMC,uBAAuBlB,kBAC3BM,cACAC,sBACA,OACAC,+BAA+BG;IAEjC,MAAMQ,iBAAiBnB,kBACrBkB,sBACAf;IAGFS,QAAQQ,OAAO,KAAK,CAAC;IACrBR,QAAQQ,OAAO,CAACC,UAAU,KAAK;QAC7BC,OAAO;QACPC,UAAU;QACVC,SAAS;YAACxB,kBAAkB,mBAAmBkB;SAAsB;QACrEO,SAAS;YACPC,UAAU;gBACR,CAAC,iDAAiD,EAAEP,gBAAgB;aACrE;YACDQ,KAAK;QACP;QACAC,WAAW;YAAC;SAAU;IACxB;IACAvB,kCAAkCO,SAAS,SAAS;IAEpD,6EAA6E;IAC7E,kDAAkD;IAClDV,WACEQ,MACAV,kBAAkBM,cAAcC,sBAAsB,iBACtD,CAACsB;QACCxB,kCACEwB,QACA,SACA,GAAGjB,QAAQkB,IAAI,CAAC,WAAW,CAAC;QAE9B,OAAOD;IACT;IAGF,2CAA2C;IAC3C,sFAAsF;IACtFzB,gBACEM,MACAV,kBAAkBM,cAAcC,uBAChC,CAACwB,WAAa;eACTA;YACH/B,kBACE,OACAQ,+BAA+BG;SAElC;AAEL,EAAE"}
|
|
@@ -29,6 +29,8 @@ import {
|
|
|
29
29
|
CfnWebACLAssociation,
|
|
30
30
|
} from 'aws-cdk-lib/aws-wafv2';
|
|
31
31
|
import { LogGroup, RetentionDays } from 'aws-cdk-lib/aws-logs';
|
|
32
|
+
import { Key } from 'aws-cdk-lib/aws-kms';
|
|
33
|
+
import { Effect, PolicyStatement, ServicePrincipal } from 'aws-cdk-lib/aws-iam';
|
|
32
34
|
import { Construct } from 'constructs';
|
|
33
35
|
import { RuntimeConfig } from './runtime-config<% if (esm) { %>.js<% } %>';
|
|
34
36
|
import { Distribution } from 'aws-cdk-lib/aws-cloudfront';
|
|
@@ -265,18 +267,41 @@ export class UserIdentity extends Construct {
|
|
|
265
267
|
webAclArn: webAcl.attrArn,
|
|
266
268
|
});
|
|
267
269
|
|
|
268
|
-
//
|
|
269
|
-
//
|
|
270
|
+
// The log group name must start with `aws-waf-logs-` to satisfy the WAFv2
|
|
271
|
+
// logging destination requirement.
|
|
272
|
+
const stack = Stack.of(this);
|
|
273
|
+
const wafLogGroupName = `aws-waf-logs-${id}-${this.node.addr.slice(-8)}`;
|
|
274
|
+
|
|
275
|
+
// KMS key for encrypting WAF logs at rest, usable by CloudWatch Logs
|
|
276
|
+
const logsKey = new Key(this, 'WebAclLogsKey', {
|
|
277
|
+
enableKeyRotation: true,
|
|
278
|
+
});
|
|
279
|
+
logsKey.addToResourcePolicy(
|
|
280
|
+
new PolicyStatement({
|
|
281
|
+
effect: Effect.ALLOW,
|
|
282
|
+
principals: [new ServicePrincipal(`logs.${stack.region}.amazonaws.com`)],
|
|
283
|
+
actions: [
|
|
284
|
+
'kms:Encrypt',
|
|
285
|
+
'kms:Decrypt',
|
|
286
|
+
'kms:ReEncrypt*',
|
|
287
|
+
'kms:GenerateDataKey*',
|
|
288
|
+
'kms:DescribeKey',
|
|
289
|
+
],
|
|
290
|
+
resources: ['*'],
|
|
291
|
+
conditions: {
|
|
292
|
+
ArnEquals: {
|
|
293
|
+
'kms:EncryptionContext:aws:logs:arn': `arn:aws:logs:${stack.region}:${stack.account}:log-group:${wafLogGroupName}`,
|
|
294
|
+
},
|
|
295
|
+
},
|
|
296
|
+
}),
|
|
297
|
+
);
|
|
298
|
+
|
|
270
299
|
const wafLogGroup = new LogGroup(this, 'WebAclLogs', {
|
|
271
|
-
logGroupName:
|
|
300
|
+
logGroupName: wafLogGroupName,
|
|
272
301
|
retention: RetentionDays.ONE_MONTH,
|
|
302
|
+
encryptionKey: logsKey,
|
|
273
303
|
removalPolicy: RemovalPolicy.DESTROY,
|
|
274
304
|
});
|
|
275
|
-
suppressRules(
|
|
276
|
-
wafLogGroup,
|
|
277
|
-
['CKV_AWS_158'],
|
|
278
|
-
'Using default CloudWatch log encryption for WAF logs',
|
|
279
|
-
);
|
|
280
305
|
|
|
281
306
|
new CfnLoggingConfiguration(this, 'WebAclLoggingConfig', {
|
|
282
307
|
resourceArn: webAcl.attrArn,
|
|
@@ -73,6 +73,8 @@ locals {
|
|
|
73
73
|
"http://localhost:4200",
|
|
74
74
|
"http://localhost:4300"
|
|
75
75
|
]
|
|
76
|
+
|
|
77
|
+
user_pool_waf_log_group_name = var.enable_waf ? "aws-waf-logs-UserPool-${random_id.unique_suffix.hex}" : null
|
|
76
78
|
}
|
|
77
79
|
|
|
78
80
|
# Random suffix for resource names
|
|
@@ -368,14 +370,61 @@ resource "aws_wafv2_web_acl_association" "user_pool_waf_association" {
|
|
|
368
370
|
web_acl_arn = aws_wafv2_web_acl.user_pool_waf[0].arn
|
|
369
371
|
}
|
|
370
372
|
|
|
373
|
+
# KMS key for encrypting WAF request logs at rest
|
|
374
|
+
resource "aws_kms_key" "user_pool_waf_logs" {
|
|
375
|
+
count = var.enable_waf ? 1 : 0
|
|
376
|
+
|
|
377
|
+
description = "User pool WAF log encryption"
|
|
378
|
+
deletion_window_in_days = 7
|
|
379
|
+
enable_key_rotation = true
|
|
380
|
+
|
|
381
|
+
policy = jsonencode({
|
|
382
|
+
Version = "2012-10-17"
|
|
383
|
+
Statement = [
|
|
384
|
+
{
|
|
385
|
+
Sid = "Enable IAM User Permissions"
|
|
386
|
+
Effect = "Allow"
|
|
387
|
+
Principal = { AWS = "arn:aws:iam::${data.aws_caller_identity.current.account_id}:root" }
|
|
388
|
+
Action = "kms:*"
|
|
389
|
+
Resource = "*"
|
|
390
|
+
},
|
|
391
|
+
{
|
|
392
|
+
Sid = "Allow CloudWatch Logs"
|
|
393
|
+
Effect = "Allow"
|
|
394
|
+
Principal = { Service = "logs.${data.aws_region.current.region}.amazonaws.com" }
|
|
395
|
+
Action = [
|
|
396
|
+
"kms:Encrypt",
|
|
397
|
+
"kms:Decrypt",
|
|
398
|
+
"kms:ReEncrypt*",
|
|
399
|
+
"kms:GenerateDataKey*",
|
|
400
|
+
"kms:DescribeKey"
|
|
401
|
+
]
|
|
402
|
+
Resource = "*"
|
|
403
|
+
Condition = {
|
|
404
|
+
ArnEquals = {
|
|
405
|
+
"kms:EncryptionContext:aws:logs:arn" = "arn:aws:logs:${data.aws_region.current.region}:${data.aws_caller_identity.current.account_id}:log-group:${local.user_pool_waf_log_group_name}"
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
]
|
|
410
|
+
})
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
resource "aws_kms_alias" "user_pool_waf_logs" {
|
|
414
|
+
count = var.enable_waf ? 1 : 0
|
|
415
|
+
|
|
416
|
+
name = "alias/user-pool-${random_id.unique_suffix.hex}-waf-logs"
|
|
417
|
+
target_key_id = aws_kms_key.user_pool_waf_logs[0].key_id
|
|
418
|
+
}
|
|
419
|
+
|
|
371
420
|
# CloudWatch Log Group for WAF request logs. Name must start with `aws-waf-logs-`.
|
|
372
421
|
resource "aws_cloudwatch_log_group" "user_pool_waf_logs" {
|
|
373
|
-
#checkov:skip=CKV_AWS_158:Using default CloudWatch log encryption
|
|
374
422
|
#checkov:skip=CKV_AWS_338:Log retention set to one month which is sufficient for WAF logs
|
|
375
423
|
count = var.enable_waf ? 1 : 0
|
|
376
424
|
|
|
377
|
-
name =
|
|
425
|
+
name = local.user_pool_waf_log_group_name
|
|
378
426
|
retention_in_days = 30
|
|
427
|
+
kms_key_id = aws_kms_key.user_pool_waf_logs[0].arn
|
|
379
428
|
}
|
|
380
429
|
|
|
381
430
|
resource "aws_wafv2_web_acl_logging_configuration" "user_pool_waf_logging" {
|
|
@@ -180,6 +180,20 @@ export interface AuroraDatabaseProps extends _AuroraDatabaseProps {
|
|
|
180
180
|
* @default true
|
|
181
181
|
*/
|
|
182
182
|
readonly enablePerformanceInsights?: boolean;
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Minimum Aurora Serverless v2 ACUs.
|
|
186
|
+
*
|
|
187
|
+
* @default <%= serverlessMinCapacity %>
|
|
188
|
+
*/
|
|
189
|
+
readonly serverlessV2MinCapacity?: number;
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Maximum Aurora Serverless v2 ACUs.
|
|
193
|
+
*
|
|
194
|
+
* @default <%= serverlessMaxCapacity %>
|
|
195
|
+
*/
|
|
196
|
+
readonly serverlessV2MaxCapacity?: number;
|
|
183
197
|
}
|
|
184
198
|
|
|
185
199
|
/**
|
|
@@ -209,6 +223,8 @@ export abstract class AuroraDatabase extends Construct {
|
|
|
209
223
|
enableKeyRotation = true,
|
|
210
224
|
enableCloudwatchLogs = true,
|
|
211
225
|
enablePerformanceInsights = true,
|
|
226
|
+
serverlessV2MinCapacity = <%= serverlessMinCapacity %>,
|
|
227
|
+
serverlessV2MaxCapacity = <%= serverlessMaxCapacity %>,
|
|
212
228
|
engine,
|
|
213
229
|
engineVersion,
|
|
214
230
|
...clusterProps
|
|
@@ -224,6 +240,8 @@ export abstract class AuroraDatabase extends Construct {
|
|
|
224
240
|
vpc,
|
|
225
241
|
vpcSubnets,
|
|
226
242
|
engine: engine.clusterEngine(engineVersion ?? engine.defaultVersion),
|
|
243
|
+
serverlessV2MinCapacity,
|
|
244
|
+
serverlessV2MaxCapacity,
|
|
227
245
|
writer:
|
|
228
246
|
writer ??
|
|
229
247
|
ClusterInstance.serverlessV2("writer", {
|
|
@@ -10,6 +10,10 @@ terraform {
|
|
|
10
10
|
source = "hashicorp/aws"
|
|
11
11
|
version = "<%- awsProviderVersion %>"
|
|
12
12
|
}
|
|
13
|
+
external = {
|
|
14
|
+
source = "hashicorp/external"
|
|
15
|
+
version = "<%- externalProviderVersion %>"
|
|
16
|
+
}
|
|
13
17
|
null = {
|
|
14
18
|
source = "hashicorp/null"
|
|
15
19
|
version = "<%- nullProviderVersion %>"
|
|
@@ -51,13 +55,13 @@ variable "port" {
|
|
|
51
55
|
variable "serverless_min_capacity" {
|
|
52
56
|
description = "Minimum Aurora Serverless v2 ACUs."
|
|
53
57
|
type = number
|
|
54
|
-
default =
|
|
58
|
+
default = <%= serverlessMinCapacity %>
|
|
55
59
|
}
|
|
56
60
|
|
|
57
61
|
variable "serverless_max_capacity" {
|
|
58
62
|
description = "Maximum Aurora Serverless v2 ACUs."
|
|
59
63
|
type = number
|
|
60
|
-
default =
|
|
64
|
+
default = <%= serverlessMaxCapacity %>
|
|
61
65
|
}
|
|
62
66
|
|
|
63
67
|
variable "instance_count" {
|
|
@@ -91,9 +95,9 @@ variable "enable_credential_rotation" {
|
|
|
91
95
|
}
|
|
92
96
|
|
|
93
97
|
variable "enable_cloudwatch_logs" {
|
|
94
|
-
description = "Whether to export Aurora engine logs to CloudWatch. PostgreSQL
|
|
98
|
+
description = "Whether to export Aurora engine logs to CloudWatch. PostgreSQL logs DDL statements only (log_statement=ddl); MySQL enables Advanced Auditing scoped to connections and DDL (server_audit_events=CONNECT,QUERY_DDL). Neither logs statement parameter values, to avoid leaking PII into log data."
|
|
95
99
|
type = bool
|
|
96
|
-
default =
|
|
100
|
+
default = true
|
|
97
101
|
}
|
|
98
102
|
|
|
99
103
|
variable "enable_performance_insights" {
|
|
@@ -114,6 +118,12 @@ variable "enable_backup" {
|
|
|
114
118
|
default = false
|
|
115
119
|
}
|
|
116
120
|
|
|
121
|
+
variable "enable_key_rotation" {
|
|
122
|
+
description = "Whether to enable automatic key rotation on the KMS key used to encrypt the Aurora cluster and its credentials secret."
|
|
123
|
+
type = bool
|
|
124
|
+
default = true
|
|
125
|
+
}
|
|
126
|
+
|
|
117
127
|
variable "tags" {
|
|
118
128
|
description = "Tags to apply to all resources."
|
|
119
129
|
type = map(string)
|
|
@@ -184,6 +194,7 @@ module "aurora" {
|
|
|
184
194
|
enable_performance_insights = var.enable_performance_insights
|
|
185
195
|
performance_insights_retention_period = var.performance_insights_retention_period
|
|
186
196
|
enable_backup = var.enable_backup
|
|
197
|
+
enable_key_rotation = var.enable_key_rotation
|
|
187
198
|
tags = var.tags
|
|
188
199
|
}
|
|
189
200
|
|
|
@@ -84,13 +84,13 @@ variable "port" {
|
|
|
84
84
|
variable "serverless_min_capacity" {
|
|
85
85
|
description = "Minimum Aurora Serverless v2 ACUs."
|
|
86
86
|
type = number
|
|
87
|
-
default =
|
|
87
|
+
default = <%= serverlessMinCapacity %>
|
|
88
88
|
}
|
|
89
89
|
|
|
90
90
|
variable "serverless_max_capacity" {
|
|
91
91
|
description = "Maximum Aurora Serverless v2 ACUs."
|
|
92
92
|
type = number
|
|
93
|
-
default =
|
|
93
|
+
default = <%= serverlessMaxCapacity %>
|
|
94
94
|
}
|
|
95
95
|
|
|
96
96
|
variable "instance_count" {
|
|
@@ -5,6 +5,18 @@
|
|
|
5
5
|
import { type Tree } from '@nx/devkit';
|
|
6
6
|
import type { Containers } from '../containers.js';
|
|
7
7
|
import type { Iac } from '../iac.js';
|
|
8
|
+
/**
|
|
9
|
+
* Aurora Serverless v2 scaling bounds, in ACUs, that both IaC providers derive
|
|
10
|
+
* from so the same generator options vend the same ceiling regardless of `--iac`.
|
|
11
|
+
*
|
|
12
|
+
* Set explicitly on CDK rather than inheriting `DatabaseClusterProps`, whose
|
|
13
|
+
* default moves with `aws-cdk-lib`. Serverless v2 bills on ACUs consumed, not on
|
|
14
|
+
* the ceiling, so the maximum is headroom rather than a cost commitment.
|
|
15
|
+
*/
|
|
16
|
+
export declare const AURORA_SERVERLESS_V2_CAPACITY: {
|
|
17
|
+
readonly min: 0.5;
|
|
18
|
+
readonly max: 4;
|
|
19
|
+
};
|
|
8
20
|
export interface AddRdbConstructOptions {
|
|
9
21
|
projectName: string;
|
|
10
22
|
projectRoot: string;
|
|
@@ -7,6 +7,24 @@ import { esmVars } from "../module-format.js";
|
|
|
7
7
|
import { addDependencyToTargetIfNotPresent } from "../nx.js";
|
|
8
8
|
import { PACKAGES_DIR, SHARED_CONSTRUCTS_DIR, SHARED_TERRAFORM_DIR } from "../shared-constructs-constants.js";
|
|
9
9
|
import { terraformProviderVersions } from "../versions.js";
|
|
10
|
+
/**
|
|
11
|
+
* Aurora Serverless v2 scaling bounds, in ACUs, that both IaC providers derive
|
|
12
|
+
* from so the same generator options vend the same ceiling regardless of `--iac`.
|
|
13
|
+
*
|
|
14
|
+
* Set explicitly on CDK rather than inheriting `DatabaseClusterProps`, whose
|
|
15
|
+
* default moves with `aws-cdk-lib`. Serverless v2 bills on ACUs consumed, not on
|
|
16
|
+
* the ceiling, so the maximum is headroom rather than a cost commitment.
|
|
17
|
+
*/ export const AURORA_SERVERLESS_V2_CAPACITY = {
|
|
18
|
+
min: 0.5,
|
|
19
|
+
max: 4
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Substitution variables exposing the Aurora Serverless v2 scaling bounds to
|
|
23
|
+
* generated CDK and Terraform templates.
|
|
24
|
+
*/ const auroraServerlessV2Capacity = ()=>({
|
|
25
|
+
serverlessMinCapacity: AURORA_SERVERLESS_V2_CAPACITY.min,
|
|
26
|
+
serverlessMaxCapacity: AURORA_SERVERLESS_V2_CAPACITY.max
|
|
27
|
+
});
|
|
10
28
|
export const addRdbInfra = async (tree, options)=>{
|
|
11
29
|
if (options.iac === 'cdk') {
|
|
12
30
|
await addRdbCdkConstructs(tree, options);
|
|
@@ -23,7 +41,8 @@ export const addRdbInfra = async (tree, options)=>{
|
|
|
23
41
|
export const addRdbCdkConstructs = async (tree, options)=>{
|
|
24
42
|
generateFiles(tree, joinPathFragments(import.meta.dirname, 'files', 'cdk', 'core', 'rdb'), joinPathFragments(PACKAGES_DIR, SHARED_CONSTRUCTS_DIR, 'src', 'core', 'rdb'), {
|
|
25
43
|
...options,
|
|
26
|
-
...esmVars(tree)
|
|
44
|
+
...esmVars(tree),
|
|
45
|
+
...auroraServerlessV2Capacity()
|
|
27
46
|
}, {
|
|
28
47
|
overwriteStrategy: OverwriteStrategy.KeepExisting
|
|
29
48
|
});
|
|
@@ -39,13 +58,15 @@ export const addRdbCdkConstructs = async (tree, options)=>{
|
|
|
39
58
|
};
|
|
40
59
|
export const addRdbTerraformModules = (tree, options)=>{
|
|
41
60
|
generateFiles(tree, joinPathFragments(import.meta.dirname, 'files', 'terraform', 'core', 'rdb'), joinPathFragments(PACKAGES_DIR, SHARED_TERRAFORM_DIR, 'src', 'core', 'rdb'), {
|
|
42
|
-
...terraformProviderVersions()
|
|
61
|
+
...terraformProviderVersions(),
|
|
62
|
+
...auroraServerlessV2Capacity()
|
|
43
63
|
}, {
|
|
44
64
|
overwriteStrategy: OverwriteStrategy.KeepExisting
|
|
45
65
|
});
|
|
46
66
|
generateFiles(tree, joinPathFragments(import.meta.dirname, 'files', 'terraform', 'app', 'dbs'), joinPathFragments(PACKAGES_DIR, SHARED_TERRAFORM_DIR, 'src', 'app', 'dbs'), {
|
|
47
67
|
...options,
|
|
48
|
-
...terraformProviderVersions()
|
|
68
|
+
...terraformProviderVersions(),
|
|
69
|
+
...auroraServerlessV2Capacity()
|
|
49
70
|
}, {
|
|
50
71
|
overwriteStrategy: OverwriteStrategy.KeepExisting
|
|
51
72
|
});
|