@aws/nx-plugin 1.0.0-rc.84 → 1.0.0-rc.86
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 +6 -1
- package/package.json +1 -1
- package/src/internal/test-matrix/generator.js +16 -0
- package/src/internal/test-matrix/generator.js.map +1 -1
- 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/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/fast-api/__snapshots__/generator.terraform.spec.ts.snap +1604 -559
- package/src/py/fast-api/generator.js +2 -1
- package/src/py/fast-api/generator.js.map +1 -1
- package/src/py/rdb/__snapshots__/generator.spec.ts.snap +21 -9
- package/src/py/rdb/files/__name__/utils.py.template +17 -1
- 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 +1548 -440
- 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 +2 -0
- package/src/terraform/project/files/application/scripts/bootstrap-destroy.ts.template +111 -0
- package/src/terraform/project/files/application/src/providers.tf.template +2 -0
- package/src/terraform/project/files/checkov/checkov.yml.template +8 -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 +1552 -525
- 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/rdb/__snapshots__/generator.spec.ts.snap +128 -250
- package/src/ts/rdb/files/src/utils.ts.template +28 -1
- 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 +243 -3
- package/src/utils/api-constructs/files/terraform/app/apis/rest/__apiNameKebabCase__/__apiNameKebabCase__.tf.template +428 -1
- 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/rdb-constructs/files/terraform/app/dbs/__nameKebabCase__/__nameKebabCase__.tf.template +6 -8
- package/src/utils/rdb-constructs/files/terraform/core/rdb/aurora/aurora.tf.template +28 -116
|
@@ -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":"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"}
|
|
@@ -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"}
|
|
@@ -88,12 +88,6 @@ variable "enable_rds_proxy" {
|
|
|
88
88
|
default = true
|
|
89
89
|
}
|
|
90
90
|
|
|
91
|
-
variable "enable_credential_rotation" {
|
|
92
|
-
description = "Whether to enable automatic credential rotation for the admin secret."
|
|
93
|
-
type = bool
|
|
94
|
-
default = true
|
|
95
|
-
}
|
|
96
|
-
|
|
97
91
|
variable "enable_cloudwatch_logs" {
|
|
98
92
|
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."
|
|
99
93
|
type = bool
|
|
@@ -177,7 +171,6 @@ module "aurora" {
|
|
|
177
171
|
name = "<%= nameKebabCase %>"
|
|
178
172
|
vpc_id = var.vpc_id
|
|
179
173
|
subnet_ids = var.database_subnet_ids
|
|
180
|
-
lambda_subnet_ids = var.lambda_subnet_ids
|
|
181
174
|
engine = "<%= engine === 'mysql' ? 'aurora-mysql' : 'aurora-postgresql' %>"
|
|
182
175
|
engine_version = var.engine_version
|
|
183
176
|
database_name = "<%= databaseName %>"
|
|
@@ -189,7 +182,6 @@ module "aurora" {
|
|
|
189
182
|
deletion_protection = var.deletion_protection
|
|
190
183
|
skip_final_snapshot = var.skip_final_snapshot
|
|
191
184
|
enable_rds_proxy = var.enable_rds_proxy
|
|
192
|
-
enable_credential_rotation = var.enable_credential_rotation
|
|
193
185
|
enable_cloudwatch_logs = var.enable_cloudwatch_logs
|
|
194
186
|
enable_performance_insights = var.enable_performance_insights
|
|
195
187
|
performance_insights_retention_period = var.performance_insights_retention_period
|
|
@@ -612,6 +604,9 @@ resource "aws_lambda_function" "create_db_user" {
|
|
|
612
604
|
environment {
|
|
613
605
|
variables = {
|
|
614
606
|
DATABASE_SECRET_ARN = module.aurora.secret_arn
|
|
607
|
+
DATABASE_HOST = module.aurora.writer_endpoint
|
|
608
|
+
DATABASE_PORT = module.aurora.cluster_port
|
|
609
|
+
DATABASE_NAME = module.aurora.database_name
|
|
615
610
|
<%_ if (framework === 'prisma') { _%>
|
|
616
611
|
NODE_EXTRA_CA_CERTS = "/var/runtime/ca-cert.pem"
|
|
617
612
|
<%_ } _%>
|
|
@@ -699,6 +694,9 @@ resource "aws_lambda_function" "migration_handler" {
|
|
|
699
694
|
environment {
|
|
700
695
|
variables = {
|
|
701
696
|
DATABASE_SECRET_ARN = module.aurora.secret_arn
|
|
697
|
+
DATABASE_HOST = module.aurora.writer_endpoint
|
|
698
|
+
DATABASE_PORT = module.aurora.cluster_port
|
|
699
|
+
DATABASE_NAME = module.aurora.database_name
|
|
702
700
|
}
|
|
703
701
|
}
|
|
704
702
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# Core Aurora module
|
|
2
|
-
# This module creates an Aurora cluster
|
|
2
|
+
# This module creates an Aurora cluster whose admin credentials are generated
|
|
3
|
+
# and rotated by RDS in Secrets Manager.
|
|
3
4
|
|
|
4
5
|
terraform {
|
|
5
6
|
required_version = ">= 1.0"
|
|
@@ -43,11 +44,6 @@ variable "subnet_ids" {
|
|
|
43
44
|
type = list(string)
|
|
44
45
|
}
|
|
45
46
|
|
|
46
|
-
variable "lambda_subnet_ids" {
|
|
47
|
-
description = "Subnet IDs for the credential-rotation Lambda. Must have outbound egress to AWS service endpoints (e.g. Secrets Manager) — use private subnets with a NAT gateway."
|
|
48
|
-
type = list(string)
|
|
49
|
-
}
|
|
50
|
-
|
|
51
47
|
variable "engine" {
|
|
52
48
|
description = "Aurora engine to use."
|
|
53
49
|
type = string
|
|
@@ -117,12 +113,6 @@ variable "enable_rds_proxy" {
|
|
|
117
113
|
default = true
|
|
118
114
|
}
|
|
119
115
|
|
|
120
|
-
variable "enable_credential_rotation" {
|
|
121
|
-
description = "Whether to enable automatic credential rotation for the admin secret."
|
|
122
|
-
type = bool
|
|
123
|
-
default = true
|
|
124
|
-
}
|
|
125
|
-
|
|
126
116
|
variable "enable_cloudwatch_logs" {
|
|
127
117
|
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."
|
|
128
118
|
type = bool
|
|
@@ -244,6 +234,20 @@ resource "aws_kms_key" "database" {
|
|
|
244
234
|
"kms:CreateGrant"
|
|
245
235
|
]
|
|
246
236
|
Resource = "*"
|
|
237
|
+
},
|
|
238
|
+
{
|
|
239
|
+
Sid = "AllowSecretsManagerService"
|
|
240
|
+
Effect = "Allow"
|
|
241
|
+
Principal = {
|
|
242
|
+
Service = "secretsmanager.amazonaws.com"
|
|
243
|
+
}
|
|
244
|
+
Action = [
|
|
245
|
+
"kms:Encrypt",
|
|
246
|
+
"kms:Decrypt",
|
|
247
|
+
"kms:GenerateDataKey*",
|
|
248
|
+
"kms:DescribeKey"
|
|
249
|
+
]
|
|
250
|
+
Resource = "*"
|
|
247
251
|
}
|
|
248
252
|
]
|
|
249
253
|
})
|
|
@@ -298,35 +302,6 @@ resource "aws_db_subnet_group" "database" {
|
|
|
298
302
|
})
|
|
299
303
|
}
|
|
300
304
|
|
|
301
|
-
resource "random_password" "master_password" {
|
|
302
|
-
length = 32
|
|
303
|
-
special = true
|
|
304
|
-
override_special = "!#$%&*()-_=+[]{}<>:?"
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
resource "aws_secretsmanager_secret" "credentials" {
|
|
308
|
-
#checkov:skip=CKV2_AWS_57:Rotation is configured via aws_cloudformation_stack.credentials_rotation using the AWS::SecretsManager-2024-09-16 transform; Checkov cannot resolve rotation schedules created by CloudFormation transforms
|
|
309
|
-
name_prefix = "${var.name}-aurora-credentials-"
|
|
310
|
-
kms_key_id = aws_kms_key.database.arn
|
|
311
|
-
|
|
312
|
-
tags = merge(var.tags, {
|
|
313
|
-
Name = "${var.name}-aurora-credentials"
|
|
314
|
-
})
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
resource "aws_secretsmanager_secret_version" "credentials" {
|
|
318
|
-
secret_id = aws_secretsmanager_secret.credentials.id
|
|
319
|
-
secret_string = jsonencode({
|
|
320
|
-
engine = var.engine == "aurora-mysql" ? "mysql" : "postgres"
|
|
321
|
-
username = var.admin_user
|
|
322
|
-
password = random_password.master_password.result
|
|
323
|
-
host = aws_rds_cluster.database.endpoint
|
|
324
|
-
port = aws_rds_cluster.database.port
|
|
325
|
-
dbname = var.database_name
|
|
326
|
-
dbClusterIdentifier = aws_rds_cluster.database.cluster_identifier
|
|
327
|
-
})
|
|
328
|
-
}
|
|
329
|
-
|
|
330
305
|
resource "aws_rds_cluster" "database" {
|
|
331
306
|
#checkov:skip=CKV2_AWS_27:Query logging is enabled by default via enable_cloudwatch_logs; checkov cannot resolve the conditional count expression on aws_rds_cluster_parameter_group.database
|
|
332
307
|
#checkov:skip=CKV_AWS_139:Deletion protection is enabled but checkov is unable to detect it correctly
|
|
@@ -335,7 +310,8 @@ resource "aws_rds_cluster" "database" {
|
|
|
335
310
|
engine_version = coalesce(var.engine_version, local.default_engine_version)
|
|
336
311
|
database_name = var.database_name
|
|
337
312
|
master_username = var.admin_user
|
|
338
|
-
|
|
313
|
+
manage_master_user_password = true
|
|
314
|
+
master_user_secret_kms_key_id = aws_kms_key.database.arn
|
|
339
315
|
db_subnet_group_name = aws_db_subnet_group.database.name
|
|
340
316
|
db_cluster_parameter_group_name = var.enable_cloudwatch_logs ? aws_rds_cluster_parameter_group.database[0].name : null
|
|
341
317
|
vpc_security_group_ids = [aws_security_group.database.id]
|
|
@@ -387,75 +363,6 @@ resource "aws_rds_cluster_instance" "database" {
|
|
|
387
363
|
})
|
|
388
364
|
}
|
|
389
365
|
|
|
390
|
-
resource "aws_security_group" "rotation" {
|
|
391
|
-
#checkov:skip=CKV2_AWS_5:Security group is attached to the hosted rotation Lambda created by AWS::SecretsManager::RotationSchedule; Checkov cannot resolve resources created by the CloudFormation transform
|
|
392
|
-
count = var.enable_credential_rotation ? 1 : 0
|
|
393
|
-
name_prefix = "${var.name}-aurora-rotation-"
|
|
394
|
-
description = "Security group for Aurora secret rotation ${var.name}"
|
|
395
|
-
vpc_id = var.vpc_id
|
|
396
|
-
|
|
397
|
-
tags = merge(var.tags, {
|
|
398
|
-
Name = "${var.name}-aurora-rotation"
|
|
399
|
-
})
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
resource "aws_vpc_security_group_egress_rule" "rotation_to_database" {
|
|
403
|
-
count = var.enable_credential_rotation ? 1 : 0
|
|
404
|
-
security_group_id = aws_security_group.rotation[0].id
|
|
405
|
-
referenced_security_group_id = aws_security_group.database.id
|
|
406
|
-
from_port = coalesce(var.port, local.default_port)
|
|
407
|
-
to_port = coalesce(var.port, local.default_port)
|
|
408
|
-
ip_protocol = "tcp"
|
|
409
|
-
description = "Allow outbound database traffic from secret rotation Lambda"
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
resource "aws_vpc_security_group_ingress_rule" "rotation_to_database" {
|
|
413
|
-
count = var.enable_credential_rotation ? 1 : 0
|
|
414
|
-
security_group_id = aws_security_group.database.id
|
|
415
|
-
referenced_security_group_id = aws_security_group.rotation[0].id
|
|
416
|
-
from_port = coalesce(var.port, local.default_port)
|
|
417
|
-
to_port = coalesce(var.port, local.default_port)
|
|
418
|
-
ip_protocol = "tcp"
|
|
419
|
-
description = "Allow inbound database traffic from secret rotation Lambda"
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
resource "aws_cloudformation_stack" "credentials_rotation" {
|
|
423
|
-
#checkov:skip=CKV_AWS_124:SNS event notifications are not required for the credentials rotation stack
|
|
424
|
-
count = var.enable_credential_rotation ? 1 : 0
|
|
425
|
-
name = "${local.cluster_name}-credentials-rotation"
|
|
426
|
-
|
|
427
|
-
capabilities = ["CAPABILITY_IAM", "CAPABILITY_AUTO_EXPAND"]
|
|
428
|
-
|
|
429
|
-
template_body = jsonencode({
|
|
430
|
-
AWSTemplateFormatVersion = "2010-09-09"
|
|
431
|
-
Transform = "AWS::SecretsManager-2024-09-16"
|
|
432
|
-
Resources = {
|
|
433
|
-
CredentialsRotationSchedule = {
|
|
434
|
-
Type = "AWS::SecretsManager::RotationSchedule"
|
|
435
|
-
Properties = {
|
|
436
|
-
SecretId = aws_secretsmanager_secret.credentials.arn
|
|
437
|
-
HostedRotationLambda = {
|
|
438
|
-
RotationType = var.engine == "aurora-mysql" ? "MySQLSingleUser" : "PostgreSQLSingleUser"
|
|
439
|
-
RotationLambdaName = "${local.cluster_name}-credentials-rotation"
|
|
440
|
-
VpcSecurityGroupIds = aws_security_group.rotation[0].id
|
|
441
|
-
VpcSubnetIds = join(",", var.lambda_subnet_ids)
|
|
442
|
-
}
|
|
443
|
-
RotationRules = {
|
|
444
|
-
AutomaticallyAfterDays = 30
|
|
445
|
-
}
|
|
446
|
-
}
|
|
447
|
-
}
|
|
448
|
-
}
|
|
449
|
-
})
|
|
450
|
-
|
|
451
|
-
depends_on = [
|
|
452
|
-
aws_secretsmanager_secret_version.credentials,
|
|
453
|
-
aws_rds_cluster_instance.database,
|
|
454
|
-
aws_vpc_security_group_egress_rule.rotation_to_database,
|
|
455
|
-
aws_vpc_security_group_ingress_rule.rotation_to_database,
|
|
456
|
-
]
|
|
457
|
-
}
|
|
458
|
-
|
|
459
366
|
resource "aws_iam_role" "proxy" {
|
|
460
367
|
count = var.enable_rds_proxy ? 1 : 0
|
|
461
368
|
|
|
@@ -694,6 +601,11 @@ output "cluster_endpoint" {
|
|
|
694
601
|
value = var.enable_rds_proxy ? aws_db_proxy.aurora[0].endpoint : aws_rds_cluster.database.endpoint
|
|
695
602
|
}
|
|
696
603
|
|
|
604
|
+
output "writer_endpoint" {
|
|
605
|
+
description = "Writer endpoint of the Aurora cluster itself, bypassing the RDS Proxy. Used by the admin-credentialled handlers, which connect directly to the cluster."
|
|
606
|
+
value = aws_rds_cluster.database.endpoint
|
|
607
|
+
}
|
|
608
|
+
|
|
697
609
|
output "reader_endpoint" {
|
|
698
610
|
description = "Reader endpoint of the Aurora cluster."
|
|
699
611
|
value = aws_rds_cluster.database.reader_endpoint
|
|
@@ -720,12 +632,12 @@ output "proxy_role_name" {
|
|
|
720
632
|
}
|
|
721
633
|
|
|
722
634
|
output "secret_arn" {
|
|
723
|
-
description = "ARN of the
|
|
724
|
-
value =
|
|
635
|
+
description = "ARN of the RDS-managed admin credentials secret. Its value is a JSON object with username and password only — connection details come from this module's other outputs."
|
|
636
|
+
value = one(aws_rds_cluster.database.master_user_secret[*].secret_arn)
|
|
725
637
|
}
|
|
726
638
|
|
|
727
639
|
output "kms_key_arn" {
|
|
728
|
-
description = "ARN of the KMS key protecting Aurora and
|
|
640
|
+
description = "ARN of the KMS key protecting Aurora and its admin credentials secret."
|
|
729
641
|
value = aws_kms_key.database.arn
|
|
730
642
|
}
|
|
731
643
|
|
|
@@ -750,6 +662,6 @@ output "database_name" {
|
|
|
750
662
|
}
|
|
751
663
|
|
|
752
664
|
output "admin_user" {
|
|
753
|
-
description = "Admin username stored in the
|
|
754
|
-
value =
|
|
665
|
+
description = "Admin username stored in the RDS-managed credentials secret."
|
|
666
|
+
value = aws_rds_cluster.database.master_username
|
|
755
667
|
}
|