@aws/nx-plugin 0.110.0 → 0.112.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/generators.json +6 -0
- package/package.json +1 -1
- package/src/connection/agent-serve-local.js +7 -8
- package/src/connection/agent-serve-local.js.map +1 -1
- package/src/connection/serve-local.js +7 -8
- package/src/connection/serve-local.js.map +1 -1
- package/src/infra/app/generator.js +2 -5
- package/src/infra/app/generator.js.map +1 -1
- package/src/preset/__snapshots__/generator.spec.ts.snap +2 -0
- package/src/py/fast-api/__snapshots__/generator.spec.ts.snap +2 -2
- package/src/py/fast-api/files/app/__name__/init.py.template +2 -2
- package/src/py/project/generator.js +17 -1
- package/src/py/project/generator.js.map +1 -1
- package/src/py/strands-agent/__snapshots__/generator.spec.ts.snap +1 -1
- package/src/py/strands-agent/a2a-connection/generator.js +4 -8
- package/src/py/strands-agent/a2a-connection/generator.js.map +1 -1
- package/src/py/strands-agent/files/http/init.py.template +2 -2
- package/src/py/strands-agent/mcp-connection/__snapshots__/generator.spec.ts.snap +8 -4
- package/src/py/strands-agent/mcp-connection/generator.js +4 -8
- package/src/py/strands-agent/mcp-connection/generator.js.map +1 -1
- package/src/ts/rdb/__snapshots__/generator.spec.ts.snap +4822 -0
- package/src/ts/rdb/files/Dockerfile.template +15 -0
- package/src/ts/rdb/files/prisma/models/example.prisma.template +5 -0
- package/src/ts/rdb/files/prisma/schema.prisma.template +9 -0
- package/src/ts/rdb/files/prisma.config.ts.template +24 -0
- package/src/ts/rdb/files/scripts/docker-pull.ts.template +15 -0
- package/src/ts/rdb/files/scripts/docker-start.ts.template +81 -0
- package/src/ts/rdb/files/scripts/wait-for-db.ts.template +55 -0
- package/src/ts/rdb/files/src/constants.ts.template +8 -0
- package/src/ts/rdb/files/src/create-db-user-handler.ts.template +128 -0
- package/src/ts/rdb/files/src/index.ts.template +2 -0
- package/src/ts/rdb/files/src/migration-handler.ts.template +54 -0
- package/src/ts/rdb/files/src/prisma.ts.template +104 -0
- package/src/ts/rdb/files/src/utils.ts.template +145 -0
- package/src/ts/rdb/generator.d.ts +10 -0
- package/src/ts/rdb/generator.js +206 -0
- package/src/ts/rdb/generator.js.map +1 -0
- package/src/ts/rdb/schema.d.ts +17 -0
- package/src/ts/rdb/schema.json +73 -0
- package/src/ts/strands-agent/a2a-connection/generator.js +4 -8
- package/src/ts/strands-agent/a2a-connection/generator.js.map +1 -1
- package/src/ts/strands-agent/mcp-connection/generator.js +4 -8
- package/src/ts/strands-agent/mcp-connection/generator.js.map +1 -1
- package/src/utils/agent-connection/files/py-core-mcp/agentcore_mcp_client.py.template +9 -3
- package/src/utils/agent-connection/files/py-core-runtime-config/runtime_config.py.template +3 -2
- package/src/utils/api-constructs/api-constructs.js +2 -10
- package/src/utils/api-constructs/api-constructs.js.map +1 -1
- package/src/utils/api-constructs/open-api-metadata.js +2 -7
- package/src/utils/api-constructs/open-api-metadata.js.map +1 -1
- package/src/utils/function-constructs/function-constructs.js +2 -10
- package/src/utils/function-constructs/function-constructs.js.map +1 -1
- package/src/utils/nx.d.ts +14 -1
- package/src/utils/nx.js +27 -1
- package/src/utils/nx.js.map +1 -1
- package/src/utils/rdb-constructs/files/cdk/app/dbs/__nameKebabCase__.ts.template +43 -0
- package/src/utils/rdb-constructs/files/cdk/core/rdb/aurora.ts.template +380 -0
- package/src/utils/rdb-constructs/files/terraform/app/dbs/__nameKebabCase__/__nameKebabCase__.tf.template +732 -0
- package/src/utils/rdb-constructs/files/terraform/core/rdb/aurora/aurora.tf.template +742 -0
- package/src/utils/rdb-constructs/rdb-constructs.d.ts +23 -0
- package/src/utils/rdb-constructs/rdb-constructs.js +59 -0
- package/src/utils/rdb-constructs/rdb-constructs.js.map +1 -0
- package/src/utils/versions.d.ts +15 -3
- package/src/utils/versions.js +14 -2
- package/src/utils/versions.js.map +1 -1
- package/src/utils/website-constructs/website-constructs.js +2 -10
- package/src/utils/website-constructs/website-constructs.js.map +1 -1
|
@@ -0,0 +1,732 @@
|
|
|
1
|
+
terraform {
|
|
2
|
+
required_version = ">= 1.0"
|
|
3
|
+
|
|
4
|
+
required_providers {
|
|
5
|
+
archive = {
|
|
6
|
+
source = "hashicorp/archive"
|
|
7
|
+
version = "~> 2.5"
|
|
8
|
+
}
|
|
9
|
+
aws = {
|
|
10
|
+
source = "hashicorp/aws"
|
|
11
|
+
version = "~> 6.33"
|
|
12
|
+
}
|
|
13
|
+
null = {
|
|
14
|
+
source = "hashicorp/null"
|
|
15
|
+
version = ">= 3.0"
|
|
16
|
+
}
|
|
17
|
+
random = {
|
|
18
|
+
source = "hashicorp/random"
|
|
19
|
+
version = ">= 3.0"
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
variable "vpc_id" {
|
|
25
|
+
description = "VPC where the Aurora cluster will be deployed."
|
|
26
|
+
type = string
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
variable "database_subnet_ids" {
|
|
30
|
+
description = "Subnet IDs for the Aurora cluster and RDS Proxy. Private isolated subnets are fine — no outbound egress required."
|
|
31
|
+
type = list(string)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
variable "lambda_subnet_ids" {
|
|
35
|
+
description = "Subnet IDs for the create-db-user and migration Lambda functions. Must have outbound egress to AWS service endpoints (e.g. Secrets Manager) — use private subnets with a NAT gateway."
|
|
36
|
+
type = list(string)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
variable "engine_version" {
|
|
40
|
+
description = "Aurora engine version."
|
|
41
|
+
type = string
|
|
42
|
+
default = null
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
variable "port" {
|
|
46
|
+
description = "Database port for the selected Aurora engine."
|
|
47
|
+
type = number
|
|
48
|
+
default = null
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
variable "serverless_min_capacity" {
|
|
52
|
+
description = "Minimum Aurora Serverless v2 ACUs."
|
|
53
|
+
type = number
|
|
54
|
+
default = 0.5
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
variable "serverless_max_capacity" {
|
|
58
|
+
description = "Maximum Aurora Serverless v2 ACUs."
|
|
59
|
+
type = number
|
|
60
|
+
default = 4
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
variable "instance_count" {
|
|
64
|
+
description = "Number of Aurora instances to create."
|
|
65
|
+
type = number
|
|
66
|
+
default = 1
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
variable "deletion_protection" {
|
|
70
|
+
description = "Whether deletion protection is enabled."
|
|
71
|
+
type = bool
|
|
72
|
+
default = true
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
variable "skip_final_snapshot" {
|
|
76
|
+
description = "Whether to skip the final snapshot on deletion."
|
|
77
|
+
type = bool
|
|
78
|
+
default = false
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
variable "enable_rds_proxy" {
|
|
82
|
+
description = "Whether to provision an RDS Proxy in front of the Aurora cluster."
|
|
83
|
+
type = bool
|
|
84
|
+
default = true
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
variable "enable_credential_rotation" {
|
|
88
|
+
description = "Whether to enable automatic credential rotation for the admin secret."
|
|
89
|
+
type = bool
|
|
90
|
+
default = true
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
variable "enable_cloudwatch_logs" {
|
|
94
|
+
description = "Whether to export Aurora engine logs to CloudWatch. PostgreSQL also enables verbose statement logging."
|
|
95
|
+
type = bool
|
|
96
|
+
default = false
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
variable "enable_performance_insights" {
|
|
100
|
+
description = "Whether to enable Performance Insights on Aurora cluster instances."
|
|
101
|
+
type = bool
|
|
102
|
+
default = true
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
variable "performance_insights_retention_period" {
|
|
106
|
+
description = "Retention period, in days, for Performance Insights data when enabled."
|
|
107
|
+
type = number
|
|
108
|
+
default = 7
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
variable "enable_backup" {
|
|
112
|
+
description = "Whether to provision an AWS Backup plan for the Aurora cluster."
|
|
113
|
+
type = bool
|
|
114
|
+
default = false
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
variable "tags" {
|
|
118
|
+
description = "Tags to apply to all resources."
|
|
119
|
+
type = map(string)
|
|
120
|
+
default = {}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
variable "docker_image_tag" {
|
|
124
|
+
description = "Docker image tag for the migration handler. Defaults to the tag built by the Nx docker target."
|
|
125
|
+
type = string
|
|
126
|
+
default = "<%= dockerImageTag %>"
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
variable "asset_bucket_name" {
|
|
130
|
+
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."
|
|
131
|
+
type = string
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
data "aws_region" "current" {}
|
|
135
|
+
data "aws_caller_identity" "current" {}
|
|
136
|
+
|
|
137
|
+
resource "random_string" "suffix" {
|
|
138
|
+
length = 8
|
|
139
|
+
special = false
|
|
140
|
+
upper = false
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
locals {
|
|
144
|
+
create_db_user_bundle_path = "${path.module}/../../../../../../../<%- createDbUserBundleDir %>"
|
|
145
|
+
migration_function_name = "<%= nameKebabCase %>-migration-${random_string.suffix.result}"
|
|
146
|
+
create_db_user_function_name = "<%= nameKebabCase %>-create-db-user-${random_string.suffix.result}"
|
|
147
|
+
database_runtime_user = "db_${random_string.suffix.result}"
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
module "aurora" {
|
|
151
|
+
source = "../../../core/rdb/aurora"
|
|
152
|
+
#checkov:skip=CKV_AWS_139:Deletion protection is enabled but checkov is unable to detect it correctly
|
|
153
|
+
name = "<%= nameKebabCase %>"
|
|
154
|
+
vpc_id = var.vpc_id
|
|
155
|
+
subnet_ids = var.database_subnet_ids
|
|
156
|
+
lambda_subnet_ids = var.lambda_subnet_ids
|
|
157
|
+
engine = "<%= engine === 'mysql' ? 'aurora-mysql' : 'aurora-postgresql' %>"
|
|
158
|
+
engine_version = var.engine_version
|
|
159
|
+
database_name = "<%= databaseName %>"
|
|
160
|
+
admin_user = "<%= adminUser %>"
|
|
161
|
+
port = var.port
|
|
162
|
+
serverless_min_capacity = var.serverless_min_capacity
|
|
163
|
+
serverless_max_capacity = var.serverless_max_capacity
|
|
164
|
+
instance_count = var.instance_count
|
|
165
|
+
deletion_protection = var.deletion_protection
|
|
166
|
+
skip_final_snapshot = var.skip_final_snapshot
|
|
167
|
+
enable_rds_proxy = var.enable_rds_proxy
|
|
168
|
+
enable_credential_rotation = var.enable_credential_rotation
|
|
169
|
+
enable_cloudwatch_logs = var.enable_cloudwatch_logs
|
|
170
|
+
enable_performance_insights = var.enable_performance_insights
|
|
171
|
+
performance_insights_retention_period = var.performance_insights_retention_period
|
|
172
|
+
enable_backup = var.enable_backup
|
|
173
|
+
tags = var.tags
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
resource "aws_iam_role_policy" "proxy_db_user_connect" {
|
|
177
|
+
count = var.enable_rds_proxy ? 1 : 0
|
|
178
|
+
|
|
179
|
+
role = module.aurora.proxy_role_name
|
|
180
|
+
|
|
181
|
+
policy = jsonencode({
|
|
182
|
+
Version = "2012-10-17"
|
|
183
|
+
Statement = [
|
|
184
|
+
{
|
|
185
|
+
Effect = "Allow"
|
|
186
|
+
Action = ["rds-db:connect"]
|
|
187
|
+
Resource = [
|
|
188
|
+
"arn:aws:rds-db:${data.aws_region.current.region}:${data.aws_caller_identity.current.account_id}:dbuser:${module.aurora.cluster_resource_id}/${local.database_runtime_user}"
|
|
189
|
+
]
|
|
190
|
+
}
|
|
191
|
+
]
|
|
192
|
+
})
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
data "archive_file" "create_db_user_zip" {
|
|
196
|
+
type = "zip"
|
|
197
|
+
source_dir = local.create_db_user_bundle_path
|
|
198
|
+
output_path = "${path.module}/../../../../../../../dist/packages/common/terraform/dbs/<%= nameKebabCase %>/create-db-user.zip"
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
resource "aws_s3_object" "create_db_user_zip" {
|
|
202
|
+
bucket = var.asset_bucket_name
|
|
203
|
+
key = "dbs/<%= nameKebabCase %>/${data.archive_file.create_db_user_zip.output_sha256}.zip"
|
|
204
|
+
source = data.archive_file.create_db_user_zip.output_path
|
|
205
|
+
source_hash = data.archive_file.create_db_user_zip.output_base64sha256
|
|
206
|
+
etag = data.archive_file.create_db_user_zip.output_md5
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
module "add_rdb_to_runtime_config" {
|
|
210
|
+
source = "../../../core/runtime-config/entry"
|
|
211
|
+
|
|
212
|
+
namespace = "database"
|
|
213
|
+
key = "<%= nameClassName %>"
|
|
214
|
+
value = {
|
|
215
|
+
hostname = module.aurora.cluster_endpoint
|
|
216
|
+
port = module.aurora.cluster_port
|
|
217
|
+
database = module.aurora.database_name
|
|
218
|
+
adminUser = module.aurora.admin_user
|
|
219
|
+
dbUser = local.database_runtime_user
|
|
220
|
+
region = data.aws_region.current.region
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
resource "aws_ecr_repository" "migration_handler" {
|
|
225
|
+
#checkov:skip=CKV_AWS_136:AES256 encryption is sufficient for ECR repositories
|
|
226
|
+
#checkov:skip=CKV_AWS_51:Mutable tags are intentional; the migration handler is always pushed as latest and redeployment is gated on docker_digest changes in null_resource.docker_publish
|
|
227
|
+
name = "<%= nameKebabCase %>-migration-${random_string.suffix.result}"
|
|
228
|
+
image_tag_mutability = "MUTABLE"
|
|
229
|
+
force_delete = true
|
|
230
|
+
|
|
231
|
+
image_scanning_configuration {
|
|
232
|
+
scan_on_push = true
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
tags = var.tags
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
resource "aws_ecr_repository_policy" "migration_handler" {
|
|
239
|
+
repository = aws_ecr_repository.migration_handler.name
|
|
240
|
+
|
|
241
|
+
policy = jsonencode({
|
|
242
|
+
Version = "2012-10-17"
|
|
243
|
+
Statement = [
|
|
244
|
+
{
|
|
245
|
+
Sid = "AllowPushPull"
|
|
246
|
+
Effect = "Allow"
|
|
247
|
+
Principal = {
|
|
248
|
+
AWS = "arn:aws:iam::${data.aws_caller_identity.current.account_id}:root"
|
|
249
|
+
}
|
|
250
|
+
Action = [
|
|
251
|
+
"ecr:BatchCheckLayerAvailability",
|
|
252
|
+
"ecr:CompleteLayerUpload",
|
|
253
|
+
"ecr:GetDownloadUrlForLayer",
|
|
254
|
+
"ecr:InitiateLayerUpload",
|
|
255
|
+
"ecr:PutImage",
|
|
256
|
+
"ecr:UploadLayerPart"
|
|
257
|
+
]
|
|
258
|
+
},
|
|
259
|
+
{
|
|
260
|
+
Sid = "AllowLambdaPull"
|
|
261
|
+
Effect = "Allow"
|
|
262
|
+
Principal = {
|
|
263
|
+
Service = "lambda.amazonaws.com"
|
|
264
|
+
}
|
|
265
|
+
Action = [
|
|
266
|
+
"ecr:BatchCheckLayerAvailability",
|
|
267
|
+
"ecr:BatchGetImage",
|
|
268
|
+
"ecr:GetDownloadUrlForLayer"
|
|
269
|
+
]
|
|
270
|
+
}
|
|
271
|
+
]
|
|
272
|
+
})
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
data "external" "docker_digest" {
|
|
276
|
+
program = ["sh", "-c", "echo '{\"digest\":\"'$(docker inspect ${var.docker_image_tag} --format '{{.Id}}')'\"}' "]
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
resource "null_resource" "docker_publish" {
|
|
280
|
+
triggers = {
|
|
281
|
+
docker_digest = data.external.docker_digest.result.digest
|
|
282
|
+
repository_url = aws_ecr_repository.migration_handler.repository_url
|
|
283
|
+
docker_image_tag = var.docker_image_tag
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
provisioner "local-exec" {
|
|
287
|
+
command = <<-EOT
|
|
288
|
+
aws ecr get-login-password --region ${data.aws_region.current.region} | docker login --username AWS --password-stdin ${self.triggers.repository_url}
|
|
289
|
+
docker tag ${self.triggers.docker_image_tag} ${self.triggers.repository_url}:latest
|
|
290
|
+
docker push ${self.triggers.repository_url}:latest
|
|
291
|
+
EOT
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
depends_on = [aws_ecr_repository_policy.migration_handler]
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
resource "aws_iam_role" "migration_handler" {
|
|
298
|
+
name = "<%= nameClassName %>MigrationHandlerRole-${random_string.suffix.result}"
|
|
299
|
+
|
|
300
|
+
assume_role_policy = jsonencode({
|
|
301
|
+
Version = "2012-10-17"
|
|
302
|
+
Statement = [
|
|
303
|
+
{
|
|
304
|
+
Effect = "Allow"
|
|
305
|
+
Principal = {
|
|
306
|
+
Service = "lambda.amazonaws.com"
|
|
307
|
+
}
|
|
308
|
+
Action = "sts:AssumeRole"
|
|
309
|
+
}
|
|
310
|
+
]
|
|
311
|
+
})
|
|
312
|
+
|
|
313
|
+
tags = var.tags
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
resource "aws_iam_role_policy_attachment" "migration_handler_basic_execution" {
|
|
317
|
+
role = aws_iam_role.migration_handler.name
|
|
318
|
+
policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
resource "aws_iam_role_policy_attachment" "migration_handler_vpc_access" {
|
|
322
|
+
role = aws_iam_role.migration_handler.name
|
|
323
|
+
policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole"
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
resource "aws_iam_role_policy_attachment" "migration_handler_xray" {
|
|
327
|
+
role = aws_iam_role.migration_handler.name
|
|
328
|
+
policy_arn = "arn:aws:iam::aws:policy/AWSXRayDaemonWriteAccess"
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
resource "aws_iam_role_policy" "migration_handler_access" {
|
|
332
|
+
role = aws_iam_role.migration_handler.name
|
|
333
|
+
|
|
334
|
+
policy = jsonencode({
|
|
335
|
+
Version = "2012-10-17"
|
|
336
|
+
Statement = [
|
|
337
|
+
<%_ if (engine === 'mysql') { _%>
|
|
338
|
+
{
|
|
339
|
+
Effect = "Allow"
|
|
340
|
+
Action = [
|
|
341
|
+
"secretsmanager:GetSecretValue"
|
|
342
|
+
]
|
|
343
|
+
Resource = [module.aurora.secret_arn]
|
|
344
|
+
},
|
|
345
|
+
{
|
|
346
|
+
Effect = "Allow"
|
|
347
|
+
Action = [
|
|
348
|
+
"kms:Decrypt"
|
|
349
|
+
]
|
|
350
|
+
Resource = [module.aurora.kms_key_arn]
|
|
351
|
+
}
|
|
352
|
+
<%_ } else { _%>
|
|
353
|
+
{
|
|
354
|
+
Effect = "Allow"
|
|
355
|
+
Action = [
|
|
356
|
+
"rds-db:connect"
|
|
357
|
+
]
|
|
358
|
+
Resource = [
|
|
359
|
+
"arn:aws:rds-db:${data.aws_region.current.region}:${data.aws_caller_identity.current.account_id}:dbuser:${var.enable_rds_proxy ? module.aurora.proxy_resource_id : module.aurora.cluster_resource_id}/${local.database_runtime_user}"
|
|
360
|
+
]
|
|
361
|
+
}
|
|
362
|
+
<%_ } _%>
|
|
363
|
+
]
|
|
364
|
+
})
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
resource "aws_iam_role" "create_db_user" {
|
|
368
|
+
name = "<%= nameClassName %>CreateDbUserRole-${random_string.suffix.result}"
|
|
369
|
+
|
|
370
|
+
assume_role_policy = jsonencode({
|
|
371
|
+
Version = "2012-10-17"
|
|
372
|
+
Statement = [
|
|
373
|
+
{
|
|
374
|
+
Effect = "Allow"
|
|
375
|
+
Principal = {
|
|
376
|
+
Service = "lambda.amazonaws.com"
|
|
377
|
+
}
|
|
378
|
+
Action = "sts:AssumeRole"
|
|
379
|
+
}
|
|
380
|
+
]
|
|
381
|
+
})
|
|
382
|
+
|
|
383
|
+
tags = var.tags
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
resource "aws_iam_role_policy_attachment" "create_db_user_basic_execution" {
|
|
387
|
+
role = aws_iam_role.create_db_user.name
|
|
388
|
+
policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
resource "aws_iam_role_policy_attachment" "create_db_user_vpc_access" {
|
|
392
|
+
role = aws_iam_role.create_db_user.name
|
|
393
|
+
policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole"
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
resource "aws_iam_role_policy_attachment" "create_db_user_xray" {
|
|
397
|
+
role = aws_iam_role.create_db_user.name
|
|
398
|
+
policy_arn = "arn:aws:iam::aws:policy/AWSXRayDaemonWriteAccess"
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
resource "aws_iam_role_policy" "create_db_user_secret_access" {
|
|
402
|
+
role = aws_iam_role.create_db_user.name
|
|
403
|
+
|
|
404
|
+
policy = jsonencode({
|
|
405
|
+
Version = "2012-10-17"
|
|
406
|
+
Statement = [
|
|
407
|
+
{
|
|
408
|
+
Effect = "Allow"
|
|
409
|
+
Action = [
|
|
410
|
+
"secretsmanager:GetSecretValue"
|
|
411
|
+
]
|
|
412
|
+
Resource = [module.aurora.secret_arn]
|
|
413
|
+
},
|
|
414
|
+
{
|
|
415
|
+
Effect = "Allow"
|
|
416
|
+
Action = [
|
|
417
|
+
"kms:Decrypt"
|
|
418
|
+
]
|
|
419
|
+
Resource = [module.aurora.kms_key_arn]
|
|
420
|
+
}
|
|
421
|
+
]
|
|
422
|
+
})
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
resource "aws_cloudwatch_log_group" "migration_handler" {
|
|
426
|
+
#checkov:skip=CKV_AWS_158:Using default CloudWatch log encryption
|
|
427
|
+
#checkov:skip=CKV_AWS_338:Log retention set to forever
|
|
428
|
+
#checkov:skip=CKV_AWS_66:Log retention set to forever
|
|
429
|
+
name = "/aws/lambda/${local.migration_function_name}"
|
|
430
|
+
tags = var.tags
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
resource "aws_cloudwatch_log_group" "create_db_user" {
|
|
434
|
+
#checkov:skip=CKV_AWS_158:Using default CloudWatch log encryption
|
|
435
|
+
#checkov:skip=CKV_AWS_338:Log retention set to forever
|
|
436
|
+
#checkov:skip=CKV_AWS_66:Log retention set to forever
|
|
437
|
+
name = "/aws/lambda/${local.create_db_user_function_name}"
|
|
438
|
+
tags = var.tags
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
resource "aws_security_group" "migration_handler" {
|
|
442
|
+
name_prefix = "<%= nameKebabCase %>-migration-"
|
|
443
|
+
description = "Security group for the migration Lambda function"
|
|
444
|
+
vpc_id = var.vpc_id
|
|
445
|
+
tags = var.tags
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
resource "aws_vpc_security_group_egress_rule" "migration_handler_to_database" {
|
|
449
|
+
<%_ if (engine === 'mysql') { _%>
|
|
450
|
+
security_group_id = aws_security_group.migration_handler.id
|
|
451
|
+
referenced_security_group_id = module.aurora.database_security_group_id
|
|
452
|
+
<%_ } else { _%>
|
|
453
|
+
security_group_id = aws_security_group.migration_handler.id
|
|
454
|
+
referenced_security_group_id = module.aurora.security_group_id
|
|
455
|
+
<%_ } _%>
|
|
456
|
+
from_port = module.aurora.cluster_port
|
|
457
|
+
to_port = module.aurora.cluster_port
|
|
458
|
+
ip_protocol = "tcp"
|
|
459
|
+
description = "Allow outbound traffic to Aurora on database port"
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
resource "aws_vpc_security_group_egress_rule" "migration_handler_https" {
|
|
463
|
+
security_group_id = aws_security_group.migration_handler.id
|
|
464
|
+
cidr_ipv4 = "0.0.0.0/0"
|
|
465
|
+
from_port = 443
|
|
466
|
+
to_port = 443
|
|
467
|
+
ip_protocol = "tcp"
|
|
468
|
+
description = "Allow outbound HTTPS to AWS service endpoints"
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
resource "aws_security_group" "create_db_user" {
|
|
472
|
+
name_prefix = "<%= nameKebabCase %>-create-db-user-"
|
|
473
|
+
description = "Security group for the create-db-user Lambda function"
|
|
474
|
+
vpc_id = var.vpc_id
|
|
475
|
+
tags = var.tags
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
resource "aws_vpc_security_group_egress_rule" "create_db_user_to_database" {
|
|
479
|
+
security_group_id = aws_security_group.create_db_user.id
|
|
480
|
+
referenced_security_group_id = module.aurora.database_security_group_id
|
|
481
|
+
from_port = module.aurora.cluster_port
|
|
482
|
+
to_port = module.aurora.cluster_port
|
|
483
|
+
ip_protocol = "tcp"
|
|
484
|
+
description = "Allow outbound traffic to Aurora on database port"
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
resource "aws_vpc_security_group_egress_rule" "create_db_user_https" {
|
|
488
|
+
security_group_id = aws_security_group.create_db_user.id
|
|
489
|
+
cidr_ipv4 = "0.0.0.0/0"
|
|
490
|
+
from_port = 443
|
|
491
|
+
to_port = 443
|
|
492
|
+
ip_protocol = "tcp"
|
|
493
|
+
description = "Allow outbound HTTPS to AWS service endpoints"
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
resource "aws_vpc_security_group_ingress_rule" "migration_handler_to_database" {
|
|
497
|
+
<%_ if (engine === 'mysql') { _%>
|
|
498
|
+
security_group_id = module.aurora.database_security_group_id
|
|
499
|
+
<%_ } else { _%>
|
|
500
|
+
security_group_id = module.aurora.security_group_id
|
|
501
|
+
<%_ } _%>
|
|
502
|
+
referenced_security_group_id = aws_security_group.migration_handler.id
|
|
503
|
+
from_port = module.aurora.cluster_port
|
|
504
|
+
to_port = module.aurora.cluster_port
|
|
505
|
+
ip_protocol = "tcp"
|
|
506
|
+
description = "Allow inbound traffic from migration Lambda on database port"
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
resource "aws_vpc_security_group_ingress_rule" "create_db_user_to_database" {
|
|
510
|
+
security_group_id = module.aurora.database_security_group_id
|
|
511
|
+
referenced_security_group_id = aws_security_group.create_db_user.id
|
|
512
|
+
from_port = module.aurora.cluster_port
|
|
513
|
+
to_port = module.aurora.cluster_port
|
|
514
|
+
ip_protocol = "tcp"
|
|
515
|
+
description = "Allow inbound traffic from create-db-user Lambda on database port"
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
resource "aws_lambda_function" "create_db_user" {
|
|
519
|
+
#checkov:skip=CKV_AWS_116:Dead Letter Queue not required for the create-db-user handler
|
|
520
|
+
#checkov:skip=CKV_AWS_115:Concurrent execution limit not required for the create-db-user handler
|
|
521
|
+
#checkov:skip=CKV_AWS_173:Lambda environment variables encrypted by managed key
|
|
522
|
+
#checkov:skip=CKV_AWS_272:Code signing not configured as deployment packages are built and deployed within the same pipeline
|
|
523
|
+
s3_bucket = aws_s3_object.create_db_user_zip.bucket
|
|
524
|
+
s3_key = aws_s3_object.create_db_user_zip.key
|
|
525
|
+
s3_object_version = aws_s3_object.create_db_user_zip.version_id
|
|
526
|
+
function_name = local.create_db_user_function_name
|
|
527
|
+
role = aws_iam_role.create_db_user.arn
|
|
528
|
+
handler = "index.handler"
|
|
529
|
+
source_code_hash = data.archive_file.create_db_user_zip.output_base64sha256
|
|
530
|
+
runtime = "nodejs24.x"
|
|
531
|
+
timeout = 300
|
|
532
|
+
architectures = ["arm64"]
|
|
533
|
+
|
|
534
|
+
tracing_config {
|
|
535
|
+
mode = "Active"
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
vpc_config {
|
|
539
|
+
subnet_ids = var.lambda_subnet_ids
|
|
540
|
+
security_group_ids = [aws_security_group.create_db_user.id]
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
environment {
|
|
544
|
+
variables = {
|
|
545
|
+
DATABASE_SECRET_ARN = module.aurora.secret_arn
|
|
546
|
+
NODE_EXTRA_CA_CERTS = "/var/runtime/ca-cert.pem"
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
tags = var.tags
|
|
551
|
+
|
|
552
|
+
depends_on = [
|
|
553
|
+
aws_s3_object.create_db_user_zip,
|
|
554
|
+
aws_iam_role_policy_attachment.create_db_user_basic_execution,
|
|
555
|
+
aws_iam_role_policy_attachment.create_db_user_vpc_access,
|
|
556
|
+
aws_iam_role_policy_attachment.create_db_user_xray,
|
|
557
|
+
aws_iam_role_policy.create_db_user_secret_access,
|
|
558
|
+
aws_cloudwatch_log_group.create_db_user,
|
|
559
|
+
aws_vpc_security_group_ingress_rule.create_db_user_to_database
|
|
560
|
+
]
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
resource "null_resource" "create_db_user_trigger" {
|
|
564
|
+
triggers = {
|
|
565
|
+
cluster_arn = module.aurora.cluster_arn
|
|
566
|
+
function_name = aws_lambda_function.create_db_user.function_name
|
|
567
|
+
db_user = local.database_runtime_user
|
|
568
|
+
bundle_hash = data.archive_file.create_db_user_zip.output_base64sha256
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
provisioner "local-exec" {
|
|
572
|
+
command = <<-EOT
|
|
573
|
+
output_file=$(mktemp)
|
|
574
|
+
response=$(aws lambda invoke \
|
|
575
|
+
--region ${data.aws_region.current.region} \
|
|
576
|
+
--function-name ${self.triggers.function_name} \
|
|
577
|
+
--cli-binary-format raw-in-base64-out \
|
|
578
|
+
--payload '{"RequestType":"Create","PhysicalResourceId":"db-user:${self.triggers.db_user}"}' \
|
|
579
|
+
"$output_file")
|
|
580
|
+
cat "$output_file"
|
|
581
|
+
echo "$response"
|
|
582
|
+
if echo "$response" | grep -q '"FunctionError"'; then
|
|
583
|
+
rm -f "$output_file"
|
|
584
|
+
exit 1
|
|
585
|
+
fi
|
|
586
|
+
rm -f "$output_file"
|
|
587
|
+
EOT
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
depends_on = [aws_lambda_function.create_db_user, module.aurora]
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
resource "aws_lambda_function" "migration_handler" {
|
|
594
|
+
#checkov:skip=CKV_AWS_116:Dead Letter Queue not required for the migration handler
|
|
595
|
+
#checkov:skip=CKV_AWS_115:Concurrent execution limit not required for the migration handler
|
|
596
|
+
#checkov:skip=CKV_AWS_173:Lambda environment variables encrypted by managed key
|
|
597
|
+
#checkov:skip=CKV_AWS_272:Code signing does not apply to container image Lambda functions
|
|
598
|
+
package_type = "Image"
|
|
599
|
+
function_name = local.migration_function_name
|
|
600
|
+
role = aws_iam_role.migration_handler.arn
|
|
601
|
+
image_uri = "${aws_ecr_repository.migration_handler.repository_url}:latest"
|
|
602
|
+
memory_size = 1024
|
|
603
|
+
timeout = 300
|
|
604
|
+
architectures = ["arm64"]
|
|
605
|
+
|
|
606
|
+
tracing_config {
|
|
607
|
+
mode = "Active"
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
vpc_config {
|
|
611
|
+
subnet_ids = var.lambda_subnet_ids
|
|
612
|
+
security_group_ids = [aws_security_group.migration_handler.id]
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
environment {
|
|
616
|
+
variables = {
|
|
617
|
+
<%_ if (engine === 'mysql') { _%>
|
|
618
|
+
DATABASE_SECRET_ARN = module.aurora.secret_arn
|
|
619
|
+
<%_ } else { _%>
|
|
620
|
+
HOSTNAME = module.aurora.cluster_endpoint
|
|
621
|
+
DATABASE = module.aurora.database_name
|
|
622
|
+
PORT = tostring(module.aurora.cluster_port)
|
|
623
|
+
DBUSER = local.database_runtime_user
|
|
624
|
+
<%_ } _%>
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
tags = var.tags
|
|
629
|
+
|
|
630
|
+
depends_on = [
|
|
631
|
+
null_resource.docker_publish,
|
|
632
|
+
aws_iam_role_policy_attachment.migration_handler_basic_execution,
|
|
633
|
+
aws_iam_role_policy_attachment.migration_handler_vpc_access,
|
|
634
|
+
aws_iam_role_policy_attachment.migration_handler_xray,
|
|
635
|
+
aws_iam_role_policy.migration_handler_access,
|
|
636
|
+
aws_cloudwatch_log_group.migration_handler,
|
|
637
|
+
aws_vpc_security_group_ingress_rule.migration_handler_to_database
|
|
638
|
+
]
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
resource "null_resource" "migration_trigger" {
|
|
642
|
+
triggers = {
|
|
643
|
+
docker_digest = data.external.docker_digest.result.digest
|
|
644
|
+
cluster_arn = module.aurora.cluster_arn
|
|
645
|
+
database_ready = module.aurora.database_ready
|
|
646
|
+
function_name = aws_lambda_function.migration_handler.function_name
|
|
647
|
+
<%_ if (engine !== 'mysql') { _%>
|
|
648
|
+
db_user = local.database_runtime_user
|
|
649
|
+
<%_ } _%>
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
provisioner "local-exec" {
|
|
653
|
+
command = <<-EOT
|
|
654
|
+
output_file=$(mktemp)
|
|
655
|
+
response=$(aws lambda invoke \
|
|
656
|
+
--region ${data.aws_region.current.region} \
|
|
657
|
+
--function-name ${self.triggers.function_name} \
|
|
658
|
+
--cli-binary-format raw-in-base64-out \
|
|
659
|
+
"$output_file")
|
|
660
|
+
cat "$output_file"
|
|
661
|
+
echo "$response"
|
|
662
|
+
if echo "$response" | grep -q '"FunctionError"'; then
|
|
663
|
+
rm -f "$output_file"
|
|
664
|
+
exit 1
|
|
665
|
+
fi
|
|
666
|
+
rm -f "$output_file"
|
|
667
|
+
EOT
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
depends_on = [
|
|
671
|
+
aws_lambda_function.migration_handler,
|
|
672
|
+
module.aurora,
|
|
673
|
+
null_resource.create_db_user_trigger,
|
|
674
|
+
aws_iam_role_policy.proxy_db_user_connect
|
|
675
|
+
]
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
output "security_group_id" {
|
|
679
|
+
description = "Security group ID to allow inbound connections to the database (proxy SG if RDS Proxy is enabled, otherwise DB SG)."
|
|
680
|
+
value = module.aurora.security_group_id
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
output "database_security_group_id" {
|
|
684
|
+
description = "Security group ID of the Aurora cluster directly, used for direct DB access rules (e.g. when RDS Proxy is disabled)."
|
|
685
|
+
value = module.aurora.database_security_group_id
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
output "cluster_resource_id" {
|
|
689
|
+
description = "Resource ID of the Aurora cluster, used for IAM rds-db:connect policies."
|
|
690
|
+
value = module.aurora.cluster_resource_id
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
output "proxy_resource_id" {
|
|
694
|
+
description = "Resource identifier of the RDS Proxy (prx-XXXX), used for IAM rds-db:connect policies when connecting through the proxy. Null if RDS Proxy is disabled."
|
|
695
|
+
value = module.aurora.proxy_resource_id
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
output "kms_key_arn" {
|
|
699
|
+
description = "ARN of the KMS key protecting Aurora and the admin credentials secret, used to grant decrypt access alongside secret_arn."
|
|
700
|
+
value = module.aurora.kms_key_arn
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
output "cluster_arn" {
|
|
704
|
+
description = "ARN of the Aurora cluster."
|
|
705
|
+
value = module.aurora.cluster_arn
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
output "cluster_endpoint" {
|
|
709
|
+
description = "Writer endpoint of the Aurora cluster."
|
|
710
|
+
value = module.aurora.cluster_endpoint
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
output "reader_endpoint" {
|
|
714
|
+
description = "Reader endpoint of the Aurora cluster."
|
|
715
|
+
value = module.aurora.reader_endpoint
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
output "cluster_port" {
|
|
719
|
+
description = "Port exposed by the Aurora cluster."
|
|
720
|
+
value = module.aurora.cluster_port
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
output "secret_arn" {
|
|
724
|
+
description = "ARN of the generated admin credentials secret."
|
|
725
|
+
value = module.aurora.secret_arn
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
output "database_runtime_user" {
|
|
729
|
+
description = "Application database user created for IAM-authenticated access."
|
|
730
|
+
value = local.database_runtime_user
|
|
731
|
+
}
|
|
732
|
+
|