@aws/nx-plugin 1.0.0-rc.71 → 1.0.0-rc.72
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/migrations.json +6 -1
- package/package.json +1 -1
- package/src/agentcore-harness/generator.d.ts +1 -1
- package/src/infra/app/generator.d.ts +1 -1
- package/src/init/generator.d.ts +1 -1
- package/src/license/dependency-check/evaluator.js +55 -10
- package/src/license/dependency-check/evaluator.js.map +1 -1
- package/src/migrations/latest/py-agent-session-management-support/metadata.json +3 -0
- package/src/migrations/latest/py-agent-session-management-support/migration.d.ts +2 -0
- package/src/migrations/latest/py-agent-session-management-support/migration.js +308 -0
- package/src/migrations/latest/py-agent-session-management-support/migration.js.map +1 -0
- package/src/preset/generator.d.ts +1 -1
- package/src/py/agent/__snapshots__/generator.constructs.spec.ts.snap +615 -6
- package/src/py/agent/__snapshots__/generator.core.spec.ts.snap +186 -0
- package/src/py/agent/__snapshots__/generator.frameworks.spec.ts.snap +47 -3
- package/src/py/agent/__snapshots__/generator.protocols.spec.ts.snap +667 -2
- package/src/py/agent/files/langchain/common/__init__.py.template +0 -0
- package/src/py/agent/files/langchain/common/agent.py.template +3 -3
- package/src/py/agent/files/langchain/common/session.py.template +61 -0
- package/src/py/agent/files/strands/ag-ui/main.py.template +5 -1
- package/src/py/agent/files/strands/common/agent.py.template +9 -2
- package/src/py/agent/files/strands/common/session.py.template +36 -0
- package/src/py/agent/generator.d.ts +11 -1
- package/src/py/agent/generator.js +78 -28
- package/src/py/agent/generator.js.map +1 -1
- package/src/py/agent/mcp-connection/__snapshots__/generator.spec.ts.snap +2 -0
- package/src/py/agent/react-connection/generator.d.ts +1 -1
- package/src/py/agent/schema.d.js.map +1 -1
- package/src/py/agent/schema.d.ts +1 -1
- package/src/py/agent/schema.json +3 -3
- package/src/py/fast-api/react/generator.d.ts +1 -1
- package/src/smithy/project/generator.d.ts +1 -1
- package/src/smithy/react-connection/generator.d.ts +1 -1
- package/src/terraform/project/generator.d.ts +1 -1
- package/src/trpc/react/generator.d.ts +1 -1
- package/src/ts/agent/__snapshots__/generator.spec.ts.snap +27 -6
- package/src/ts/agent/a2a-connection/generator.d.ts +1 -1
- package/src/ts/agent/gateway-connection/generator.d.ts +1 -1
- package/src/ts/agent/mcp-connection/generator.d.ts +1 -1
- package/src/ts/agent/react-connection/generator.d.ts +1 -1
- package/src/ts/astro-docs/generator.d.ts +1 -1
- package/src/ts/dcr-proxy/generator.d.ts +1 -1
- package/src/ts/dynamodb/generator.d.ts +1 -1
- package/src/ts/lambda-function/generator.d.ts +1 -1
- package/src/ts/lib/generator.d.ts +1 -1
- package/src/ts/nx-generator/generator.d.ts +1 -1
- package/src/ts/nx-migration/generator.d.ts +1 -1
- package/src/ts/nx-plugin/generator.d.ts +1 -1
- package/src/ts/rdb/generator.d.ts +1 -1
- package/src/ts/react-website/agui/generator.d.ts +1 -1
- package/src/utils/agent-connection/agent-connection.d.ts +10 -0
- package/src/utils/agent-connection/agent-connection.js +15 -0
- package/src/utils/agent-connection/agent-connection.js.map +1 -1
- package/src/utils/agent-connection/files/core-runtime-config/runtime-config.ts.template +5 -3
- package/src/utils/agent-connection/files/py-core-langchain/s3/s3_checkpoint_saver_langchain.py.template +360 -0
- package/src/utils/agent-connection/files/py-core-runtime-config/runtime_config.py.template +2 -4
- package/src/utils/agent-connection/files/py-core-strands/base/tool_errors_strands.py.template +24 -0
- package/src/utils/agent-core-constructs/agent-core-constructs.d.ts +1 -1
- package/src/utils/agent-core-constructs/agent-core-constructs.js.map +1 -1
- package/src/utils/agent-core-constructs/files/cdk/app/agent-core/__nameKebabCase__/__nameKebabCase__.ts.template +113 -13
- package/src/utils/agent-core-constructs/files/terraform/app/agent-core/__nameKebabCase__/__nameKebabCase__.tf.template +76 -7
- package/src/utils/versions.d.ts +3 -0
- package/src/utils/versions.js +3 -0
- package/src/utils/versions.js.map +1 -1
|
@@ -1,7 +1,376 @@
|
|
|
1
1
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
|
2
2
|
|
|
3
|
+
exports[`py#agent generator > should create DynamoDB checkpoint table and S3 offload bucket infrastructure when session is dynamodb-s3 (Terraform) > terraform-agent.tf (dynamodb-s3) 1`] = `
|
|
4
|
+
"terraform {
|
|
5
|
+
required_providers {
|
|
6
|
+
random = {
|
|
7
|
+
source = "hashicorp/random"
|
|
8
|
+
version = "3.9.0"
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
variable "env" {
|
|
14
|
+
description = "Environment variables to pass to the agent core runtime"
|
|
15
|
+
type = map(string)
|
|
16
|
+
default = {}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
variable "additional_iam_policy_statements" {
|
|
20
|
+
description = "Additional IAM policy statements to attach to the agent core runtime role"
|
|
21
|
+
type = list(object({
|
|
22
|
+
Effect = string
|
|
23
|
+
Action = list(string)
|
|
24
|
+
Resource = list(string)
|
|
25
|
+
}))
|
|
26
|
+
default = []
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
variable "tags" {
|
|
30
|
+
description = "Tags to apply to resources"
|
|
31
|
+
type = map(string)
|
|
32
|
+
default = {}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
# VPC Configuration (optional)
|
|
36
|
+
variable "enable_vpc" {
|
|
37
|
+
description = "Run the agent core runtime inside a VPC. Set alongside vpc_id/subnet_ids."
|
|
38
|
+
type = bool
|
|
39
|
+
default = false
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
variable "vpc_id" {
|
|
43
|
+
description = "VPC ID to run the agent core runtime in. Required when enable_vpc is true."
|
|
44
|
+
type = string
|
|
45
|
+
default = null
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
variable "subnet_ids" {
|
|
49
|
+
description = "Subnet IDs to run the agent core runtime in. Required when enable_vpc is true."
|
|
50
|
+
type = list(string)
|
|
51
|
+
default = null
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
variable "appconfig_application_id" {
|
|
55
|
+
description = "ID of the shared runtime-config AppConfig application (from \`core/runtime-config/appconfig.application_id\`). The agent reads its runtime configuration from this application."
|
|
56
|
+
type = string
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
variable "session_force_destroy" {
|
|
60
|
+
description = "Whether to allow the session bucket to be destroyed even if it still contains objects."
|
|
61
|
+
type = bool
|
|
62
|
+
default = false
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
variable "session_deletion_protection_enabled" {
|
|
66
|
+
description = "Whether to enable deletion protection on the session checkpoint table."
|
|
67
|
+
type = bool
|
|
68
|
+
default = true
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
variable "appconfig_application_arn" {
|
|
72
|
+
description = "ARN of the shared runtime-config AppConfig application (from \`core/runtime-config/appconfig.application_arn\`). Used to scope the IAM read permission granted to the agent runtime."
|
|
73
|
+
type = string
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
data "aws_region" "current" {}
|
|
77
|
+
data "aws_caller_identity" "current" {}
|
|
78
|
+
|
|
79
|
+
locals {
|
|
80
|
+
# Delivery source/destination names have a 60 character maximum. Truncate
|
|
81
|
+
# the agent name so these stay within the limit.
|
|
82
|
+
session_access_logs_name_prefix = substr("dynamodb-terraform-agent", 0, 30)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
# Uniquifies resource names below so this construct can be deployed more than
|
|
86
|
+
# once (e.g. across stages) within the same account/region.
|
|
87
|
+
resource "random_id" "session_unique_suffix" {
|
|
88
|
+
byte_length = 4
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
# KMS key encrypting the session bucket and its server access logs.
|
|
92
|
+
resource "aws_kms_key" "session" {
|
|
93
|
+
description = "KMS key for dynamodb-terraform-agent agent session data"
|
|
94
|
+
enable_key_rotation = true
|
|
95
|
+
deletion_window_in_days = 7
|
|
96
|
+
|
|
97
|
+
policy = jsonencode({
|
|
98
|
+
Version = "2012-10-17"
|
|
99
|
+
Statement = [
|
|
100
|
+
{
|
|
101
|
+
Sid = "EnableIAMUserPermissions"
|
|
102
|
+
Effect = "Allow"
|
|
103
|
+
Principal = { AWS = "arn:aws:iam::\${data.aws_caller_identity.current.account_id}:root" }
|
|
104
|
+
Action = "kms:*"
|
|
105
|
+
Resource = "*"
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
Sid = "AllowCloudWatchLogs"
|
|
109
|
+
Effect = "Allow"
|
|
110
|
+
Principal = { Service = "logs.\${data.aws_region.current.region}.amazonaws.com" }
|
|
111
|
+
Action = [
|
|
112
|
+
"kms:Encrypt",
|
|
113
|
+
"kms:Decrypt",
|
|
114
|
+
"kms:ReEncrypt*",
|
|
115
|
+
"kms:GenerateDataKey*",
|
|
116
|
+
"kms:DescribeKey"
|
|
117
|
+
]
|
|
118
|
+
Resource = "*"
|
|
119
|
+
Condition = {
|
|
120
|
+
ArnLike = {
|
|
121
|
+
"kms:EncryptionContext:aws:logs:arn" = "arn:aws:logs:\${data.aws_region.current.region}:\${data.aws_caller_identity.current.account_id}:log-group:*"
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
]
|
|
126
|
+
})
|
|
127
|
+
|
|
128
|
+
tags = var.tags
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
# CloudWatch log group receiving the session bucket's server access logs.
|
|
132
|
+
resource "aws_cloudwatch_log_group" "session_access_logs" {
|
|
133
|
+
name = "/aws/s3/dynamodb-terraform-agent-session-access-logs-\${random_id.session_unique_suffix.hex}"
|
|
134
|
+
retention_in_days = 365
|
|
135
|
+
kms_key_id = aws_kms_key.session.arn
|
|
136
|
+
|
|
137
|
+
tags = var.tags
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
# Bucket storing the agent's session data
|
|
141
|
+
resource "aws_s3_bucket" "session" {
|
|
142
|
+
bucket = "dynamodb-terraform-agent-sessions-\${random_id.session_unique_suffix.hex}"
|
|
143
|
+
#checkov:skip=CKV2_AWS_61:Lifecycle configuration not required for session data
|
|
144
|
+
#checkov:skip=CKV_AWS_144:Cross-region replication not required for session data
|
|
145
|
+
#checkov:skip=CKV2_AWS_62:Event notifications not required for session data
|
|
146
|
+
#checkov:skip=CKV_AWS_18:Server access logs are delivered to CloudWatch Logs (see aws_cloudwatch_log_delivery.session)
|
|
147
|
+
#checkov:skip=CKV_AWS_21:Session data does not need versioning enabled
|
|
148
|
+
force_destroy = var.session_force_destroy
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
resource "aws_s3_bucket_server_side_encryption_configuration" "session" {
|
|
152
|
+
bucket = aws_s3_bucket.session.id
|
|
153
|
+
|
|
154
|
+
rule {
|
|
155
|
+
apply_server_side_encryption_by_default {
|
|
156
|
+
kms_master_key_id = aws_kms_key.session.arn
|
|
157
|
+
sse_algorithm = "aws:kms"
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
resource "aws_s3_bucket_public_access_block" "session" {
|
|
163
|
+
bucket = aws_s3_bucket.session.id
|
|
164
|
+
|
|
165
|
+
block_public_acls = true
|
|
166
|
+
block_public_policy = true
|
|
167
|
+
ignore_public_acls = true
|
|
168
|
+
restrict_public_buckets = true
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
resource "aws_s3_bucket_policy" "session" {
|
|
172
|
+
bucket = aws_s3_bucket.session.id
|
|
173
|
+
|
|
174
|
+
policy = jsonencode({
|
|
175
|
+
Version = "2012-10-17"
|
|
176
|
+
Statement = [
|
|
177
|
+
{
|
|
178
|
+
Sid = "DenyInsecureConnections"
|
|
179
|
+
Effect = "Deny"
|
|
180
|
+
Principal = "*"
|
|
181
|
+
Action = "s3:*"
|
|
182
|
+
Resource = [
|
|
183
|
+
aws_s3_bucket.session.arn,
|
|
184
|
+
"\${aws_s3_bucket.session.arn}/*"
|
|
185
|
+
]
|
|
186
|
+
Condition = {
|
|
187
|
+
Bool = {
|
|
188
|
+
"aws:SecureTransport" = "false"
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
]
|
|
193
|
+
})
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
# Deliver the session bucket's server access logs to CloudWatch Logs.
|
|
197
|
+
resource "aws_cloudwatch_log_delivery_source" "session" {
|
|
198
|
+
name = "\${local.session_access_logs_name_prefix}-access-logs-source-\${random_id.session_unique_suffix.hex}"
|
|
199
|
+
log_type = "S3_SERVER_ACCESS_LOGS"
|
|
200
|
+
resource_arn = aws_s3_bucket.session.arn
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
resource "aws_cloudwatch_log_delivery_destination" "session" {
|
|
204
|
+
name = "\${local.session_access_logs_name_prefix}-access-logs-dest-\${random_id.session_unique_suffix.hex}"
|
|
205
|
+
|
|
206
|
+
delivery_destination_configuration {
|
|
207
|
+
destination_resource_arn = aws_cloudwatch_log_group.session_access_logs.arn
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
resource "aws_cloudwatch_log_delivery" "session" {
|
|
212
|
+
delivery_source_name = aws_cloudwatch_log_delivery_source.session.name
|
|
213
|
+
delivery_destination_arn = aws_cloudwatch_log_delivery_destination.session.arn
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
# Unified checkpoints/writes table, matching the schema
|
|
217
|
+
# langgraph_checkpoint_aws.DynamoDBSaver expects (PK/SK, TTL on \`ttl\`).
|
|
218
|
+
resource "aws_dynamodb_table" "session" {
|
|
219
|
+
name = "dynamodb-terraform-agent-checkpoints-\${random_id.session_unique_suffix.hex}"
|
|
220
|
+
billing_mode = "PAY_PER_REQUEST"
|
|
221
|
+
hash_key = "PK"
|
|
222
|
+
range_key = "SK"
|
|
223
|
+
|
|
224
|
+
attribute {
|
|
225
|
+
name = "PK"
|
|
226
|
+
type = "S"
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
attribute {
|
|
230
|
+
name = "SK"
|
|
231
|
+
type = "S"
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
ttl {
|
|
235
|
+
attribute_name = "ttl"
|
|
236
|
+
enabled = true
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
point_in_time_recovery {
|
|
240
|
+
enabled = true
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
server_side_encryption {
|
|
244
|
+
enabled = true
|
|
245
|
+
kms_key_arn = aws_kms_key.session.arn
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
deletion_protection_enabled = var.session_deletion_protection_enabled
|
|
249
|
+
|
|
250
|
+
tags = var.tags
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
module "agent_core_runtime" {
|
|
254
|
+
source = "../../../core/agent-core"
|
|
255
|
+
agent_runtime_name = "DynamodbTerraformAgent"
|
|
256
|
+
docker_image_tag = "proj-dynamodb-terraform-agent:latest"
|
|
257
|
+
server_protocol = "HTTP"
|
|
258
|
+
enable_vpc = var.enable_vpc
|
|
259
|
+
vpc_id = var.vpc_id
|
|
260
|
+
subnet_ids = var.subnet_ids
|
|
261
|
+
|
|
262
|
+
env = merge({
|
|
263
|
+
RUNTIME_CONFIG_APP_ID = var.appconfig_application_id
|
|
264
|
+
}, var.env)
|
|
265
|
+
additional_iam_policy_statements = concat([
|
|
266
|
+
{
|
|
267
|
+
Effect = "Allow"
|
|
268
|
+
Action = [
|
|
269
|
+
"appconfig:StartConfigurationSession",
|
|
270
|
+
"appconfig:GetLatestConfiguration"
|
|
271
|
+
]
|
|
272
|
+
Resource = ["\${var.appconfig_application_arn}/*"]
|
|
273
|
+
},
|
|
274
|
+
# Grant access for the agent to invoke bedrock models
|
|
275
|
+
{
|
|
276
|
+
Effect = "Allow"
|
|
277
|
+
Action = [
|
|
278
|
+
"bedrock:InvokeModel",
|
|
279
|
+
"bedrock:InvokeModelWithResponseStream"
|
|
280
|
+
]
|
|
281
|
+
Resource = [
|
|
282
|
+
"arn:aws:bedrock:*:*:foundation-model/*",
|
|
283
|
+
"arn:aws:bedrock:*:*:inference-profile/*"
|
|
284
|
+
]
|
|
285
|
+
},
|
|
286
|
+
# Grant access for the agent to read/write its session data
|
|
287
|
+
{
|
|
288
|
+
Effect = "Allow"
|
|
289
|
+
Action = [
|
|
290
|
+
"s3:GetObject",
|
|
291
|
+
"s3:PutObject",
|
|
292
|
+
"s3:DeleteObject",
|
|
293
|
+
"s3:ListBucket"
|
|
294
|
+
]
|
|
295
|
+
Resource = [
|
|
296
|
+
aws_s3_bucket.session.arn,
|
|
297
|
+
"\${aws_s3_bucket.session.arn}/*"
|
|
298
|
+
]
|
|
299
|
+
},
|
|
300
|
+
# Grant access for the agent to use the session bucket's KMS key
|
|
301
|
+
{
|
|
302
|
+
Effect = "Allow"
|
|
303
|
+
Action = [
|
|
304
|
+
"kms:Decrypt",
|
|
305
|
+
"kms:GenerateDataKey*"
|
|
306
|
+
]
|
|
307
|
+
Resource = [aws_kms_key.session.arn]
|
|
308
|
+
},
|
|
309
|
+
# Grant access for the agent to read/write its checkpoint table
|
|
310
|
+
{
|
|
311
|
+
Effect = "Allow"
|
|
312
|
+
Action = [
|
|
313
|
+
"dynamodb:GetItem",
|
|
314
|
+
"dynamodb:PutItem",
|
|
315
|
+
"dynamodb:Query",
|
|
316
|
+
"dynamodb:BatchGetItem",
|
|
317
|
+
"dynamodb:BatchWriteItem"
|
|
318
|
+
]
|
|
319
|
+
Resource = [aws_dynamodb_table.session.arn]
|
|
320
|
+
}
|
|
321
|
+
], var.additional_iam_policy_statements)
|
|
322
|
+
tags = var.tags
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
# Add agent runtime ARN to runtime config
|
|
326
|
+
module "add_agent_runtime_to_runtime_config" {
|
|
327
|
+
source = "../../../core/runtime-config/entry"
|
|
328
|
+
|
|
329
|
+
namespace = "agentcore"
|
|
330
|
+
key = "agentRuntimes"
|
|
331
|
+
value = { "DynamodbTerraformAgent" = { arn = module.agent_core_runtime.agent_core_runtime_arn, session = { tableName = aws_dynamodb_table.session.name, bucketName = aws_s3_bucket.session.bucket } } }
|
|
332
|
+
|
|
333
|
+
depends_on = [module.agent_core_runtime]
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
output "agent_core_runtime_role_arn" {
|
|
337
|
+
description = "ARN of the agent core runtime role"
|
|
338
|
+
value = module.agent_core_runtime.agent_core_runtime_role_arn
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
output "agent_core_runtime_arn" {
|
|
342
|
+
description = "ARN of the Bedrock Agent Core runtime"
|
|
343
|
+
value = module.agent_core_runtime.agent_core_runtime_arn
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
output "invocation_url" {
|
|
347
|
+
description = "HTTPS invocation URL of the runtime"
|
|
348
|
+
value = module.agent_core_runtime.invocation_url
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
output "appconfig_application_id" {
|
|
352
|
+
description = "AppConfig Application ID for runtime config (passthrough of the shared \`appconfig_application_id\` input)."
|
|
353
|
+
value = var.appconfig_application_id
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
output "security_group_id" {
|
|
357
|
+
description = "Security group ID of the agent core runtime, for use in ingress rules on resources it must reach (e.g. a database). Null unless enable_vpc is true."
|
|
358
|
+
value = module.agent_core_runtime.security_group_id
|
|
359
|
+
}
|
|
360
|
+
"
|
|
361
|
+
`;
|
|
362
|
+
|
|
3
363
|
exports[`py#agent generator > should match snapshot for Terraform generated files > terraform-agent.tf 1`] = `
|
|
4
|
-
"
|
|
364
|
+
"terraform {
|
|
365
|
+
required_providers {
|
|
366
|
+
random = {
|
|
367
|
+
source = "hashicorp/random"
|
|
368
|
+
version = "3.9.0"
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
variable "env" {
|
|
5
374
|
description = "Environment variables to pass to the agent core runtime"
|
|
6
375
|
type = map(string)
|
|
7
376
|
default = {}
|
|
@@ -47,11 +416,157 @@ variable "appconfig_application_id" {
|
|
|
47
416
|
type = string
|
|
48
417
|
}
|
|
49
418
|
|
|
419
|
+
variable "session_force_destroy" {
|
|
420
|
+
description = "Whether to allow the session bucket to be destroyed even if it still contains objects."
|
|
421
|
+
type = bool
|
|
422
|
+
default = false
|
|
423
|
+
}
|
|
424
|
+
|
|
50
425
|
variable "appconfig_application_arn" {
|
|
51
426
|
description = "ARN of the shared runtime-config AppConfig application (from \`core/runtime-config/appconfig.application_arn\`). Used to scope the IAM read permission granted to the agent runtime."
|
|
52
427
|
type = string
|
|
53
428
|
}
|
|
54
429
|
|
|
430
|
+
data "aws_region" "current" {}
|
|
431
|
+
data "aws_caller_identity" "current" {}
|
|
432
|
+
|
|
433
|
+
locals {
|
|
434
|
+
# Delivery source/destination names have a 60 character maximum. Truncate
|
|
435
|
+
# the agent name so these stay within the limit.
|
|
436
|
+
session_access_logs_name_prefix = substr("terraform-snapshot-agent", 0, 30)
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
# Uniquifies resource names below so this construct can be deployed more than
|
|
440
|
+
# once (e.g. across stages) within the same account/region.
|
|
441
|
+
resource "random_id" "session_unique_suffix" {
|
|
442
|
+
byte_length = 4
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
# KMS key encrypting the session bucket and its server access logs.
|
|
446
|
+
resource "aws_kms_key" "session" {
|
|
447
|
+
description = "KMS key for terraform-snapshot-agent agent session data"
|
|
448
|
+
enable_key_rotation = true
|
|
449
|
+
deletion_window_in_days = 7
|
|
450
|
+
|
|
451
|
+
policy = jsonencode({
|
|
452
|
+
Version = "2012-10-17"
|
|
453
|
+
Statement = [
|
|
454
|
+
{
|
|
455
|
+
Sid = "EnableIAMUserPermissions"
|
|
456
|
+
Effect = "Allow"
|
|
457
|
+
Principal = { AWS = "arn:aws:iam::\${data.aws_caller_identity.current.account_id}:root" }
|
|
458
|
+
Action = "kms:*"
|
|
459
|
+
Resource = "*"
|
|
460
|
+
},
|
|
461
|
+
{
|
|
462
|
+
Sid = "AllowCloudWatchLogs"
|
|
463
|
+
Effect = "Allow"
|
|
464
|
+
Principal = { Service = "logs.\${data.aws_region.current.region}.amazonaws.com" }
|
|
465
|
+
Action = [
|
|
466
|
+
"kms:Encrypt",
|
|
467
|
+
"kms:Decrypt",
|
|
468
|
+
"kms:ReEncrypt*",
|
|
469
|
+
"kms:GenerateDataKey*",
|
|
470
|
+
"kms:DescribeKey"
|
|
471
|
+
]
|
|
472
|
+
Resource = "*"
|
|
473
|
+
Condition = {
|
|
474
|
+
ArnLike = {
|
|
475
|
+
"kms:EncryptionContext:aws:logs:arn" = "arn:aws:logs:\${data.aws_region.current.region}:\${data.aws_caller_identity.current.account_id}:log-group:*"
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
]
|
|
480
|
+
})
|
|
481
|
+
|
|
482
|
+
tags = var.tags
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
# CloudWatch log group receiving the session bucket's server access logs.
|
|
486
|
+
resource "aws_cloudwatch_log_group" "session_access_logs" {
|
|
487
|
+
name = "/aws/s3/terraform-snapshot-agent-session-access-logs-\${random_id.session_unique_suffix.hex}"
|
|
488
|
+
retention_in_days = 365
|
|
489
|
+
kms_key_id = aws_kms_key.session.arn
|
|
490
|
+
|
|
491
|
+
tags = var.tags
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
# Bucket storing the agent's session data
|
|
495
|
+
resource "aws_s3_bucket" "session" {
|
|
496
|
+
bucket = "terraform-snapshot-agent-sessions-\${random_id.session_unique_suffix.hex}"
|
|
497
|
+
#checkov:skip=CKV2_AWS_61:Lifecycle configuration not required for session data
|
|
498
|
+
#checkov:skip=CKV_AWS_144:Cross-region replication not required for session data
|
|
499
|
+
#checkov:skip=CKV2_AWS_62:Event notifications not required for session data
|
|
500
|
+
#checkov:skip=CKV_AWS_18:Server access logs are delivered to CloudWatch Logs (see aws_cloudwatch_log_delivery.session)
|
|
501
|
+
#checkov:skip=CKV_AWS_21:Session data does not need versioning enabled
|
|
502
|
+
force_destroy = var.session_force_destroy
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
resource "aws_s3_bucket_server_side_encryption_configuration" "session" {
|
|
506
|
+
bucket = aws_s3_bucket.session.id
|
|
507
|
+
|
|
508
|
+
rule {
|
|
509
|
+
apply_server_side_encryption_by_default {
|
|
510
|
+
kms_master_key_id = aws_kms_key.session.arn
|
|
511
|
+
sse_algorithm = "aws:kms"
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
resource "aws_s3_bucket_public_access_block" "session" {
|
|
517
|
+
bucket = aws_s3_bucket.session.id
|
|
518
|
+
|
|
519
|
+
block_public_acls = true
|
|
520
|
+
block_public_policy = true
|
|
521
|
+
ignore_public_acls = true
|
|
522
|
+
restrict_public_buckets = true
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
resource "aws_s3_bucket_policy" "session" {
|
|
526
|
+
bucket = aws_s3_bucket.session.id
|
|
527
|
+
|
|
528
|
+
policy = jsonencode({
|
|
529
|
+
Version = "2012-10-17"
|
|
530
|
+
Statement = [
|
|
531
|
+
{
|
|
532
|
+
Sid = "DenyInsecureConnections"
|
|
533
|
+
Effect = "Deny"
|
|
534
|
+
Principal = "*"
|
|
535
|
+
Action = "s3:*"
|
|
536
|
+
Resource = [
|
|
537
|
+
aws_s3_bucket.session.arn,
|
|
538
|
+
"\${aws_s3_bucket.session.arn}/*"
|
|
539
|
+
]
|
|
540
|
+
Condition = {
|
|
541
|
+
Bool = {
|
|
542
|
+
"aws:SecureTransport" = "false"
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
]
|
|
547
|
+
})
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
# Deliver the session bucket's server access logs to CloudWatch Logs.
|
|
551
|
+
resource "aws_cloudwatch_log_delivery_source" "session" {
|
|
552
|
+
name = "\${local.session_access_logs_name_prefix}-access-logs-source-\${random_id.session_unique_suffix.hex}"
|
|
553
|
+
log_type = "S3_SERVER_ACCESS_LOGS"
|
|
554
|
+
resource_arn = aws_s3_bucket.session.arn
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
resource "aws_cloudwatch_log_delivery_destination" "session" {
|
|
558
|
+
name = "\${local.session_access_logs_name_prefix}-access-logs-dest-\${random_id.session_unique_suffix.hex}"
|
|
559
|
+
|
|
560
|
+
delivery_destination_configuration {
|
|
561
|
+
destination_resource_arn = aws_cloudwatch_log_group.session_access_logs.arn
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
resource "aws_cloudwatch_log_delivery" "session" {
|
|
566
|
+
delivery_source_name = aws_cloudwatch_log_delivery_source.session.name
|
|
567
|
+
delivery_destination_arn = aws_cloudwatch_log_delivery_destination.session.arn
|
|
568
|
+
}
|
|
569
|
+
|
|
55
570
|
module "agent_core_runtime" {
|
|
56
571
|
source = "../../../core/agent-core"
|
|
57
572
|
agent_runtime_name = "TerraformSnapshotAgent"
|
|
@@ -84,6 +599,29 @@ module "agent_core_runtime" {
|
|
|
84
599
|
"arn:aws:bedrock:*:*:foundation-model/*",
|
|
85
600
|
"arn:aws:bedrock:*:*:inference-profile/*"
|
|
86
601
|
]
|
|
602
|
+
},
|
|
603
|
+
# Grant access for the agent to read/write its session data
|
|
604
|
+
{
|
|
605
|
+
Effect = "Allow"
|
|
606
|
+
Action = [
|
|
607
|
+
"s3:GetObject",
|
|
608
|
+
"s3:PutObject",
|
|
609
|
+
"s3:DeleteObject",
|
|
610
|
+
"s3:ListBucket"
|
|
611
|
+
]
|
|
612
|
+
Resource = [
|
|
613
|
+
aws_s3_bucket.session.arn,
|
|
614
|
+
"\${aws_s3_bucket.session.arn}/*"
|
|
615
|
+
]
|
|
616
|
+
},
|
|
617
|
+
# Grant access for the agent to use the session bucket's KMS key
|
|
618
|
+
{
|
|
619
|
+
Effect = "Allow"
|
|
620
|
+
Action = [
|
|
621
|
+
"kms:Decrypt",
|
|
622
|
+
"kms:GenerateDataKey*"
|
|
623
|
+
]
|
|
624
|
+
Resource = [aws_kms_key.session.arn]
|
|
87
625
|
}
|
|
88
626
|
], var.additional_iam_policy_statements)
|
|
89
627
|
tags = var.tags
|
|
@@ -95,7 +633,7 @@ module "add_agent_runtime_to_runtime_config" {
|
|
|
95
633
|
|
|
96
634
|
namespace = "agentcore"
|
|
97
635
|
key = "agentRuntimes"
|
|
98
|
-
value = { "TerraformSnapshotAgent" = { arn = module.agent_core_runtime.agent_core_runtime_arn } }
|
|
636
|
+
value = { "TerraformSnapshotAgent" = { arn = module.agent_core_runtime.agent_core_runtime_arn, session = { bucketName = aws_s3_bucket.session.bucket } } }
|
|
99
637
|
|
|
100
638
|
depends_on = [module.agent_core_runtime]
|
|
101
639
|
}
|
|
@@ -643,3 +1181,130 @@ output "security_group_id" {
|
|
|
643
1181
|
}
|
|
644
1182
|
"
|
|
645
1183
|
`;
|
|
1184
|
+
|
|
1185
|
+
exports[`py#agent generator > should not create session bucket infrastructure when session is in-memory (Terraform) > terraform-agent.tf (in-memory) 1`] = `
|
|
1186
|
+
"variable "env" {
|
|
1187
|
+
description = "Environment variables to pass to the agent core runtime"
|
|
1188
|
+
type = map(string)
|
|
1189
|
+
default = {}
|
|
1190
|
+
}
|
|
1191
|
+
|
|
1192
|
+
variable "additional_iam_policy_statements" {
|
|
1193
|
+
description = "Additional IAM policy statements to attach to the agent core runtime role"
|
|
1194
|
+
type = list(object({
|
|
1195
|
+
Effect = string
|
|
1196
|
+
Action = list(string)
|
|
1197
|
+
Resource = list(string)
|
|
1198
|
+
}))
|
|
1199
|
+
default = []
|
|
1200
|
+
}
|
|
1201
|
+
|
|
1202
|
+
variable "tags" {
|
|
1203
|
+
description = "Tags to apply to resources"
|
|
1204
|
+
type = map(string)
|
|
1205
|
+
default = {}
|
|
1206
|
+
}
|
|
1207
|
+
|
|
1208
|
+
# VPC Configuration (optional)
|
|
1209
|
+
variable "enable_vpc" {
|
|
1210
|
+
description = "Run the agent core runtime inside a VPC. Set alongside vpc_id/subnet_ids."
|
|
1211
|
+
type = bool
|
|
1212
|
+
default = false
|
|
1213
|
+
}
|
|
1214
|
+
|
|
1215
|
+
variable "vpc_id" {
|
|
1216
|
+
description = "VPC ID to run the agent core runtime in. Required when enable_vpc is true."
|
|
1217
|
+
type = string
|
|
1218
|
+
default = null
|
|
1219
|
+
}
|
|
1220
|
+
|
|
1221
|
+
variable "subnet_ids" {
|
|
1222
|
+
description = "Subnet IDs to run the agent core runtime in. Required when enable_vpc is true."
|
|
1223
|
+
type = list(string)
|
|
1224
|
+
default = null
|
|
1225
|
+
}
|
|
1226
|
+
|
|
1227
|
+
variable "appconfig_application_id" {
|
|
1228
|
+
description = "ID of the shared runtime-config AppConfig application (from \`core/runtime-config/appconfig.application_id\`). The agent reads its runtime configuration from this application."
|
|
1229
|
+
type = string
|
|
1230
|
+
}
|
|
1231
|
+
|
|
1232
|
+
variable "appconfig_application_arn" {
|
|
1233
|
+
description = "ARN of the shared runtime-config AppConfig application (from \`core/runtime-config/appconfig.application_arn\`). Used to scope the IAM read permission granted to the agent runtime."
|
|
1234
|
+
type = string
|
|
1235
|
+
}
|
|
1236
|
+
|
|
1237
|
+
module "agent_core_runtime" {
|
|
1238
|
+
source = "../../../core/agent-core"
|
|
1239
|
+
agent_runtime_name = "InMemoryTerraformAgent"
|
|
1240
|
+
docker_image_tag = "proj-in-memory-terraform-agent:latest"
|
|
1241
|
+
server_protocol = "HTTP"
|
|
1242
|
+
enable_vpc = var.enable_vpc
|
|
1243
|
+
vpc_id = var.vpc_id
|
|
1244
|
+
subnet_ids = var.subnet_ids
|
|
1245
|
+
|
|
1246
|
+
env = merge({
|
|
1247
|
+
RUNTIME_CONFIG_APP_ID = var.appconfig_application_id
|
|
1248
|
+
}, var.env)
|
|
1249
|
+
additional_iam_policy_statements = concat([
|
|
1250
|
+
{
|
|
1251
|
+
Effect = "Allow"
|
|
1252
|
+
Action = [
|
|
1253
|
+
"appconfig:StartConfigurationSession",
|
|
1254
|
+
"appconfig:GetLatestConfiguration"
|
|
1255
|
+
]
|
|
1256
|
+
Resource = ["\${var.appconfig_application_arn}/*"]
|
|
1257
|
+
},
|
|
1258
|
+
# Grant access for the agent to invoke bedrock models
|
|
1259
|
+
{
|
|
1260
|
+
Effect = "Allow"
|
|
1261
|
+
Action = [
|
|
1262
|
+
"bedrock:InvokeModel",
|
|
1263
|
+
"bedrock:InvokeModelWithResponseStream"
|
|
1264
|
+
]
|
|
1265
|
+
Resource = [
|
|
1266
|
+
"arn:aws:bedrock:*:*:foundation-model/*",
|
|
1267
|
+
"arn:aws:bedrock:*:*:inference-profile/*"
|
|
1268
|
+
]
|
|
1269
|
+
}
|
|
1270
|
+
], var.additional_iam_policy_statements)
|
|
1271
|
+
tags = var.tags
|
|
1272
|
+
}
|
|
1273
|
+
|
|
1274
|
+
# Add agent runtime ARN to runtime config
|
|
1275
|
+
module "add_agent_runtime_to_runtime_config" {
|
|
1276
|
+
source = "../../../core/runtime-config/entry"
|
|
1277
|
+
|
|
1278
|
+
namespace = "agentcore"
|
|
1279
|
+
key = "agentRuntimes"
|
|
1280
|
+
value = { "InMemoryTerraformAgent" = { arn = module.agent_core_runtime.agent_core_runtime_arn } }
|
|
1281
|
+
|
|
1282
|
+
depends_on = [module.agent_core_runtime]
|
|
1283
|
+
}
|
|
1284
|
+
|
|
1285
|
+
output "agent_core_runtime_role_arn" {
|
|
1286
|
+
description = "ARN of the agent core runtime role"
|
|
1287
|
+
value = module.agent_core_runtime.agent_core_runtime_role_arn
|
|
1288
|
+
}
|
|
1289
|
+
|
|
1290
|
+
output "agent_core_runtime_arn" {
|
|
1291
|
+
description = "ARN of the Bedrock Agent Core runtime"
|
|
1292
|
+
value = module.agent_core_runtime.agent_core_runtime_arn
|
|
1293
|
+
}
|
|
1294
|
+
|
|
1295
|
+
output "invocation_url" {
|
|
1296
|
+
description = "HTTPS invocation URL of the runtime"
|
|
1297
|
+
value = module.agent_core_runtime.invocation_url
|
|
1298
|
+
}
|
|
1299
|
+
|
|
1300
|
+
output "appconfig_application_id" {
|
|
1301
|
+
description = "AppConfig Application ID for runtime config (passthrough of the shared \`appconfig_application_id\` input)."
|
|
1302
|
+
value = var.appconfig_application_id
|
|
1303
|
+
}
|
|
1304
|
+
|
|
1305
|
+
output "security_group_id" {
|
|
1306
|
+
description = "Security group ID of the agent core runtime, for use in ingress rules on resources it must reach (e.g. a database). Null unless enable_vpc is true."
|
|
1307
|
+
value = module.agent_core_runtime.security_group_id
|
|
1308
|
+
}
|
|
1309
|
+
"
|
|
1310
|
+
`;
|
|
File without changes
|