@deployfoundation/foundation-deploy 0.2.11 → 0.2.14
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/dist/bin/app.js +2 -2
- package/dist/bin/foundation-deploy.js +4 -5
- package/dist/bin/release-account.js +2 -2
- package/dist/{chunk-n8qzcdq4.js → chunk-7qn00ny1.js} +10 -0
- package/dist/{chunk-sxvts8bf.js → chunk-83781ggk.js} +33 -5
- package/dist/{chunk-2kqazxx6.js → chunk-e9vs85ah.js} +1 -1
- package/dist/src/index.js +2 -2
- package/package.json +1 -1
- package/src/deploy/tracing.ts +7 -10
- package/src/stacks/agent-stack.ts +52 -5
- package/src/stacks/network-stack.ts +13 -6
package/dist/bin/app.js
CHANGED
|
@@ -7,12 +7,12 @@ import {
|
|
|
7
7
|
FoundationNetwork,
|
|
8
8
|
FoundationPipeline,
|
|
9
9
|
NewsletterStack
|
|
10
|
-
} from "../chunk-
|
|
10
|
+
} from "../chunk-83781ggk.js";
|
|
11
11
|
import {
|
|
12
12
|
adminsFor,
|
|
13
13
|
instanceNames,
|
|
14
14
|
loadInstanceFile
|
|
15
|
-
} from "../chunk-
|
|
15
|
+
} from "../chunk-7qn00ny1.js";
|
|
16
16
|
|
|
17
17
|
// bin/app.ts
|
|
18
18
|
import { execFileSync } from "node:child_process";
|
|
@@ -29,7 +29,7 @@ import {
|
|
|
29
29
|
stackExists,
|
|
30
30
|
stackOutput,
|
|
31
31
|
toolVersion
|
|
32
|
-
} from "../chunk-
|
|
32
|
+
} from "../chunk-e9vs85ah.js";
|
|
33
33
|
import {
|
|
34
34
|
BASE_SLACK_EVENTS,
|
|
35
35
|
CAPABILITY_IDS,
|
|
@@ -45,7 +45,7 @@ import {
|
|
|
45
45
|
requiredSlackScopes,
|
|
46
46
|
skillsKey,
|
|
47
47
|
slackCommandPrefix
|
|
48
|
-
} from "../chunk-
|
|
48
|
+
} from "../chunk-7qn00ny1.js";
|
|
49
49
|
|
|
50
50
|
// src/deploy/config-sync.ts
|
|
51
51
|
import { existsSync, mkdirSync, mkdtempSync, readdirSync } from "node:fs";
|
|
@@ -1522,8 +1522,7 @@ function spansIngestionPolicy(account, region) {
|
|
|
1522
1522
|
Version: "2012-10-17",
|
|
1523
1523
|
Statement: [
|
|
1524
1524
|
statement("SpansFromXray", "aws/spans"),
|
|
1525
|
-
statement("ApplicationSignalsFromXray", "/aws/application-signals/data")
|
|
1526
|
-
statement("AgentCoreRuntimeSpansFromXray", "/aws/bedrock-agentcore/runtimes/*")
|
|
1525
|
+
statement("ApplicationSignalsFromXray", "/aws/application-signals/data")
|
|
1527
1526
|
]
|
|
1528
1527
|
});
|
|
1529
1528
|
}
|
|
@@ -1538,7 +1537,7 @@ function hasSpansIngestionPolicy(describeOutput) {
|
|
|
1538
1537
|
return false;
|
|
1539
1538
|
return policies.some((p) => {
|
|
1540
1539
|
const doc = String(p.policyDocument ?? "");
|
|
1541
|
-
return doc.includes("aws/spans") && doc.includes("logs:CreateLogStream")
|
|
1540
|
+
return doc.includes("aws/spans") && doc.includes("logs:CreateLogStream");
|
|
1542
1541
|
});
|
|
1543
1542
|
}
|
|
1544
1543
|
function parseDestination(text) {
|
|
@@ -572,6 +572,14 @@ var RawProactive = z2.object({
|
|
|
572
572
|
channels: z2.array(z2.string().regex(/^[CG][A-Z0-9]{8,}$/)).default([]),
|
|
573
573
|
maxPerHour: z2.number().int().min(1).max(500).default(20)
|
|
574
574
|
}).strict().default({ channels: [] });
|
|
575
|
+
var RawRuntime = z2.object({
|
|
576
|
+
idleTimeoutMinutes: z2.number().int().min(5).max(480).default(15),
|
|
577
|
+
maxLifetimeHours: z2.number().int().min(1).max(8).default(8)
|
|
578
|
+
}).strict().default({});
|
|
579
|
+
var RawNetwork = z2.object({
|
|
580
|
+
natGateways: z2.union([z2.literal(1), z2.literal(2)]).default(1),
|
|
581
|
+
endpointAzs: z2.union([z2.literal(1), z2.literal(2)]).default(1)
|
|
582
|
+
}).strict().default({});
|
|
575
583
|
var RawNaming = z2.object({
|
|
576
584
|
prefix: z2.string().min(1).max(32).regex(/^[A-Z][A-Za-z0-9]*$/),
|
|
577
585
|
secretPrefix: z2.string().min(1).max(40).regex(/^[a-z][a-z0-9-]*$/),
|
|
@@ -711,6 +719,8 @@ var RawInstance = z2.object({
|
|
|
711
719
|
license: RawLicense.optional(),
|
|
712
720
|
config: z2.string().min(1),
|
|
713
721
|
proactive: RawProactive,
|
|
722
|
+
runtime: RawRuntime,
|
|
723
|
+
network: RawNetwork,
|
|
714
724
|
integrations: RawIntegrations,
|
|
715
725
|
newsletter: RawNewsletter
|
|
716
726
|
}).strict().superRefine((doc, ctx) => {
|
|
@@ -19,12 +19,13 @@ import {
|
|
|
19
19
|
scheduledJobBindings,
|
|
20
20
|
slackCommandPrefixes,
|
|
21
21
|
webhookJobBindings
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-7qn00ny1.js";
|
|
23
23
|
|
|
24
24
|
// src/stacks/agent-stack.ts
|
|
25
25
|
import * as cdk from "aws-cdk-lib";
|
|
26
26
|
import * as ecr from "aws-cdk-lib/aws-ecr";
|
|
27
27
|
import * as iam from "aws-cdk-lib/aws-iam";
|
|
28
|
+
import * as logs from "aws-cdk-lib/aws-logs";
|
|
28
29
|
class FoundationAgent extends cdk.Stack {
|
|
29
30
|
repository;
|
|
30
31
|
executionRole;
|
|
@@ -67,6 +68,7 @@ class FoundationAgent extends cdk.Stack {
|
|
|
67
68
|
this.accessPoint = accessPoint;
|
|
68
69
|
this.executionRole = this.buildExecutionRole(props);
|
|
69
70
|
this.readOnlyRole = this.buildReadOnlyRole(props);
|
|
71
|
+
this.buildSpansIngestionPolicy();
|
|
70
72
|
const gateway = this.buildToolGateway(display);
|
|
71
73
|
this.webSearchUrl = gateway.getAtt("GatewayUrl").toString();
|
|
72
74
|
this.executionRole.addToPolicy(new iam.PolicyStatement({
|
|
@@ -118,8 +120,8 @@ class FoundationAgent extends cdk.Stack {
|
|
|
118
120
|
}
|
|
119
121
|
],
|
|
120
122
|
LifecycleConfiguration: {
|
|
121
|
-
IdleRuntimeSessionTimeout:
|
|
122
|
-
MaxLifetime:
|
|
123
|
+
IdleRuntimeSessionTimeout: props.instance.runtime.idleTimeoutMinutes * 60,
|
|
124
|
+
MaxLifetime: props.instance.runtime.maxLifetimeHours * 3600
|
|
123
125
|
},
|
|
124
126
|
RoleArn: this.executionRole.roleArn,
|
|
125
127
|
EnvironmentVariables: {
|
|
@@ -318,6 +320,27 @@ class FoundationAgent extends cdk.Stack {
|
|
|
318
320
|
}));
|
|
319
321
|
return role;
|
|
320
322
|
}
|
|
323
|
+
buildSpansIngestionPolicy() {
|
|
324
|
+
return new logs.ResourcePolicy(this, "AgentSpansIngestion", {
|
|
325
|
+
resourcePolicyName: `${this.stackName}-AgentSpansFromXray`,
|
|
326
|
+
policyStatements: [
|
|
327
|
+
new iam.PolicyStatement({
|
|
328
|
+
sid: "AgentSpansFromXray",
|
|
329
|
+
principals: [new iam.ServicePrincipal("xray.amazonaws.com")],
|
|
330
|
+
actions: ["logs:PutLogEvents", "logs:CreateLogStream"],
|
|
331
|
+
resources: [
|
|
332
|
+
`arn:${this.partition}:logs:${this.region}:${this.account}:log-group:/aws/bedrock-agentcore/runtimes/${this.names.runtimeName}-*:*`
|
|
333
|
+
],
|
|
334
|
+
conditions: {
|
|
335
|
+
StringEquals: { "aws:SourceAccount": this.account },
|
|
336
|
+
ArnLike: {
|
|
337
|
+
"aws:SourceArn": `arn:${this.partition}:xray:${this.region}:${this.account}:*`
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
})
|
|
341
|
+
]
|
|
342
|
+
});
|
|
343
|
+
}
|
|
321
344
|
buildExecutionRole(props) {
|
|
322
345
|
const role = new iam.Role(this, "AgentExecutionRole", {
|
|
323
346
|
assumedBy: new iam.ServicePrincipal("bedrock-agentcore.amazonaws.com"),
|
|
@@ -2043,7 +2066,7 @@ class FoundationNetwork extends cdk5.Stack {
|
|
|
2043
2066
|
} else {
|
|
2044
2067
|
this.vpc = new ec2.Vpc(this, "FoundationVpc", {
|
|
2045
2068
|
maxAzs: 2,
|
|
2046
|
-
natGateways:
|
|
2069
|
+
natGateways: props.instance.network.natGateways,
|
|
2047
2070
|
subnetConfiguration: [
|
|
2048
2071
|
{ name: "ingress", subnetType: ec2.SubnetType.PUBLIC, cidrMask: 24 },
|
|
2049
2072
|
{ name: "egress", subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, cidrMask: 24 },
|
|
@@ -2088,7 +2111,12 @@ class FoundationNetwork extends cdk5.Stack {
|
|
|
2088
2111
|
});
|
|
2089
2112
|
endpointSg.addIngressRule(ec2.Peer.ipv4(this.vpc.vpcCidrBlock), ec2.Port.tcp(443), "HTTPS from VPC");
|
|
2090
2113
|
this.endpointSecurityGroup = endpointSg;
|
|
2091
|
-
const endpointSubnets = importedVpcId ? { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS } : { subnetGroupName: "app" };
|
|
2114
|
+
const endpointSubnets = importedVpcId ? { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, onePerAz: true } : { subnetGroupName: "app", onePerAz: true };
|
|
2115
|
+
if (props.instance.network.endpointAzs === 1) {
|
|
2116
|
+
const zones = this.vpc.selectSubnets(endpointSubnets).availabilityZones;
|
|
2117
|
+
if (zones.length > 1)
|
|
2118
|
+
Object.assign(endpointSubnets, { availabilityZones: [zones[0]] });
|
|
2119
|
+
}
|
|
2092
2120
|
const gatewayEndpointSubnets = importedVpcId ? [{ subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }] : [{ subnetGroupName: "app" }, { subnetGroupName: "egress" }];
|
|
2093
2121
|
const sameAccountOnly = new iam6.PolicyStatement({
|
|
2094
2122
|
effect: iam6.Effect.ALLOW,
|
package/dist/src/index.js
CHANGED
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
FoundationPipeline,
|
|
10
10
|
NewsletterStack,
|
|
11
11
|
deployStatements
|
|
12
|
-
} from "../chunk-
|
|
12
|
+
} from "../chunk-83781ggk.js";
|
|
13
13
|
import {
|
|
14
14
|
BUN_VERSION,
|
|
15
15
|
LAMBDA_ENTRY_POINTS,
|
|
@@ -42,7 +42,7 @@ import {
|
|
|
42
42
|
skillsKey,
|
|
43
43
|
skipBundle,
|
|
44
44
|
verifyManifest
|
|
45
|
-
} from "../chunk-
|
|
45
|
+
} from "../chunk-7qn00ny1.js";
|
|
46
46
|
export {
|
|
47
47
|
BUILD_TIMEOUT,
|
|
48
48
|
BUN_VERSION,
|
package/package.json
CHANGED
package/src/deploy/tracing.ts
CHANGED
|
@@ -82,11 +82,12 @@ export function spansIngestionPolicy(account: string, region: string): string {
|
|
|
82
82
|
Statement: [
|
|
83
83
|
statement("SpansFromXray", "aws/spans"),
|
|
84
84
|
statement("ApplicationSignalsFromXray", "/aws/application-signals/data"),
|
|
85
|
-
//
|
|
86
|
-
//
|
|
87
|
-
//
|
|
88
|
-
//
|
|
89
|
-
|
|
85
|
+
// NOT the runtime's own log group, which is where the agent's spans
|
|
86
|
+
// actually go (`x-aws-log-group`): that grant is per instance and ships
|
|
87
|
+
// with every deploy as the agent stack's `AgentSpansIngestion` policy.
|
|
88
|
+
// Owning it here made it a one-time `setup` side effect, and an instance
|
|
89
|
+
// that reached its account by `deploy` alone never got it — every export
|
|
90
|
+
// a 400 (Olivia, 2026-09-26).
|
|
90
91
|
],
|
|
91
92
|
});
|
|
92
93
|
}
|
|
@@ -102,11 +103,7 @@ export function hasSpansIngestionPolicy(describeOutput: string): boolean {
|
|
|
102
103
|
if (!Array.isArray(policies)) return false;
|
|
103
104
|
return policies.some((p) => {
|
|
104
105
|
const doc = String((p as { policyDocument?: unknown }).policyDocument ?? "");
|
|
105
|
-
return (
|
|
106
|
-
doc.includes("aws/spans") &&
|
|
107
|
-
doc.includes("logs:CreateLogStream") &&
|
|
108
|
-
doc.includes("/aws/bedrock-agentcore/runtimes/")
|
|
109
|
-
);
|
|
106
|
+
return doc.includes("aws/spans") && doc.includes("logs:CreateLogStream");
|
|
110
107
|
});
|
|
111
108
|
}
|
|
112
109
|
|
|
@@ -4,6 +4,7 @@ import type * as ec2 from "aws-cdk-lib/aws-ec2";
|
|
|
4
4
|
import * as ecr from "aws-cdk-lib/aws-ecr";
|
|
5
5
|
import * as iam from "aws-cdk-lib/aws-iam";
|
|
6
6
|
import type * as kms from "aws-cdk-lib/aws-kms";
|
|
7
|
+
import * as logs from "aws-cdk-lib/aws-logs";
|
|
7
8
|
import type * as s3 from "aws-cdk-lib/aws-s3";
|
|
8
9
|
import type * as secretsmanager from "aws-cdk-lib/aws-secretsmanager";
|
|
9
10
|
import type { Construct } from "constructs";
|
|
@@ -147,6 +148,7 @@ export class FoundationAgent extends cdk.Stack {
|
|
|
147
148
|
this.accessPoint = accessPoint;
|
|
148
149
|
this.executionRole = this.buildExecutionRole(props);
|
|
149
150
|
this.readOnlyRole = this.buildReadOnlyRole(props);
|
|
151
|
+
this.buildSpansIngestionPolicy();
|
|
150
152
|
|
|
151
153
|
// The gateway is independent of the runtime: it can (and does) exist
|
|
152
154
|
// during the phase-one bootstrap deploy.
|
|
@@ -227,9 +229,11 @@ export class FoundationAgent extends cdk.Stack {
|
|
|
227
229
|
},
|
|
228
230
|
},
|
|
229
231
|
],
|
|
232
|
+
// Idle sessions are billed for their memory: see `runtime` in the
|
|
233
|
+
// instance schema for why the default is 15 minutes, not 60.
|
|
230
234
|
LifecycleConfiguration: {
|
|
231
|
-
IdleRuntimeSessionTimeout:
|
|
232
|
-
MaxLifetime:
|
|
235
|
+
IdleRuntimeSessionTimeout: props.instance.runtime.idleTimeoutMinutes * 60,
|
|
236
|
+
MaxLifetime: props.instance.runtime.maxLifetimeHours * 3600,
|
|
233
237
|
},
|
|
234
238
|
RoleArn: this.executionRole.roleArn,
|
|
235
239
|
EnvironmentVariables: {
|
|
@@ -521,6 +525,48 @@ export class FoundationAgent extends cdk.Stack {
|
|
|
521
525
|
return role;
|
|
522
526
|
}
|
|
523
527
|
|
|
528
|
+
/**
|
|
529
|
+
* Let X-Ray write this runtime's spans into the runtime's own log group.
|
|
530
|
+
*
|
|
531
|
+
* The agent posts OTLP to the X-Ray endpoint with `x-aws-log-group` naming
|
|
532
|
+
* `/aws/bedrock-agentcore/runtimes/<runtime>-<endpoint>` (see
|
|
533
|
+
* `packages/agent/src/observability/otel.ts`). X-Ray, not the execution
|
|
534
|
+
* role, then calls `PutLogEvents` — as a role in an AWS service account —
|
|
535
|
+
* so the execution role's `AgentLogs` grant does not apply, and without a
|
|
536
|
+
* CloudWatch Logs RESOURCE policy every export is a 400 "not authorized to
|
|
537
|
+
* perform: logs:PutLogEvents" (Olivia, 2026-09-26). AWS: "If you set
|
|
538
|
+
* OTEL_EXPORTER_OTLP_TRACES_HEADERS to deliver spans to your own log group,
|
|
539
|
+
* you must also add an Amazon CloudWatch Logs resource policy … allow X-Ray
|
|
540
|
+
* (xray.amazonaws.com) to call logs:PutLogEvents on that log group"
|
|
541
|
+
* (bedrock-agentcore devguide, observability-configure).
|
|
542
|
+
*
|
|
543
|
+
* Logs resource policies are account-level (ten per Region), so the name is
|
|
544
|
+
* the stack's own and the grant covers only this runtime's endpoint groups,
|
|
545
|
+
* and only when X-Ray acts for this account. `CreateLogStream` rides along
|
|
546
|
+
* because X-Ray creates the `spans` stream on first delivery.
|
|
547
|
+
*/
|
|
548
|
+
private buildSpansIngestionPolicy(): logs.ResourcePolicy {
|
|
549
|
+
return new logs.ResourcePolicy(this, "AgentSpansIngestion", {
|
|
550
|
+
resourcePolicyName: `${this.stackName}-AgentSpansFromXray`,
|
|
551
|
+
policyStatements: [
|
|
552
|
+
new iam.PolicyStatement({
|
|
553
|
+
sid: "AgentSpansFromXray",
|
|
554
|
+
principals: [new iam.ServicePrincipal("xray.amazonaws.com")],
|
|
555
|
+
actions: ["logs:PutLogEvents", "logs:CreateLogStream"],
|
|
556
|
+
resources: [
|
|
557
|
+
`arn:${this.partition}:logs:${this.region}:${this.account}:log-group:/aws/bedrock-agentcore/runtimes/${this.names.runtimeName}-*:*`,
|
|
558
|
+
],
|
|
559
|
+
conditions: {
|
|
560
|
+
StringEquals: { "aws:SourceAccount": this.account },
|
|
561
|
+
ArnLike: {
|
|
562
|
+
"aws:SourceArn": `arn:${this.partition}:xray:${this.region}:${this.account}:*`,
|
|
563
|
+
},
|
|
564
|
+
},
|
|
565
|
+
}),
|
|
566
|
+
],
|
|
567
|
+
});
|
|
568
|
+
}
|
|
569
|
+
|
|
524
570
|
private buildExecutionRole(props: FoundationAgentProps): iam.Role {
|
|
525
571
|
const role = new iam.Role(this, "AgentExecutionRole", {
|
|
526
572
|
assumedBy: new iam.ServicePrincipal("bedrock-agentcore.amazonaws.com"),
|
|
@@ -572,9 +618,10 @@ export class FoundationAgent extends cdk.Stack {
|
|
|
572
618
|
],
|
|
573
619
|
}),
|
|
574
620
|
);
|
|
575
|
-
// Spans: the runtime SigV4-posts OTLP to the X-Ray endpoint
|
|
576
|
-
//
|
|
577
|
-
//
|
|
621
|
+
// Spans: the runtime SigV4-posts OTLP to the X-Ray endpoint. These actions
|
|
622
|
+
// only let it call X-Ray (none takes a resource ARN — X-Ray scopes
|
|
623
|
+
// ingestion by account); X-Ray's own write into the runtime log group is
|
|
624
|
+
// authorized by `AgentSpansIngestion`, not by `AgentLogs` above.
|
|
578
625
|
role.addToPolicy(
|
|
579
626
|
new iam.PolicyStatement({
|
|
580
627
|
sid: "TraceIngest",
|
|
@@ -70,9 +70,9 @@ export class FoundationNetwork extends cdk.Stack {
|
|
|
70
70
|
} else {
|
|
71
71
|
this.vpc = new ec2.Vpc(this, "FoundationVpc", {
|
|
72
72
|
maxAzs: 2,
|
|
73
|
-
// One NAT
|
|
74
|
-
//
|
|
75
|
-
natGateways:
|
|
73
|
+
// One NAT by default: a second (AZ-failure tolerance for egress) is
|
|
74
|
+
// about $33/month, opted into with `network.natGateways: 2`.
|
|
75
|
+
natGateways: props.instance.network.natGateways,
|
|
76
76
|
subnetConfiguration: [
|
|
77
77
|
{ name: "ingress", subnetType: ec2.SubnetType.PUBLIC, cidrMask: 24 },
|
|
78
78
|
{ name: "egress", subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, cidrMask: 24 },
|
|
@@ -82,7 +82,7 @@ export class FoundationNetwork extends cdk.Stack {
|
|
|
82
82
|
this.egressSubnets = { subnetGroupName: "egress" };
|
|
83
83
|
// The addresses everything in the VPC leaves through, so a third party
|
|
84
84
|
// (an Atlas IP allowlist, say) can name this instance and no other.
|
|
85
|
-
// One per
|
|
85
|
+
// One per NAT gateway (`network.natGateways`).
|
|
86
86
|
new cdk.CfnOutput(this, "NatEgressIp", {
|
|
87
87
|
value: cdk.Fn.join(
|
|
88
88
|
",",
|
|
@@ -191,9 +191,16 @@ export class FoundationNetwork extends cdk.Stack {
|
|
|
191
191
|
// Interface endpoints sit in the isolated app tier when we created the
|
|
192
192
|
// VPC; on an imported VPC they land in its private subnets. Private DNS
|
|
193
193
|
// makes them authoritative for the whole VPC either way.
|
|
194
|
+
// One AZ by default (`network.endpointAzs`): the other AZ reaches the
|
|
195
|
+
// same endpoint through private DNS, for a little cross-AZ traffic
|
|
196
|
+
// instead of a second set of endpoint-hours.
|
|
194
197
|
const endpointSubnets: ec2.SubnetSelection = importedVpcId
|
|
195
|
-
? { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }
|
|
196
|
-
: { subnetGroupName: "app" };
|
|
198
|
+
? { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, onePerAz: true }
|
|
199
|
+
: { subnetGroupName: "app", onePerAz: true };
|
|
200
|
+
if (props.instance.network.endpointAzs === 1) {
|
|
201
|
+
const zones = this.vpc.selectSubnets(endpointSubnets).availabilityZones;
|
|
202
|
+
if (zones.length > 1) Object.assign(endpointSubnets, { availabilityZones: [zones[0]] });
|
|
203
|
+
}
|
|
197
204
|
// Gateway endpoints attach to every private route table (app + egress) so
|
|
198
205
|
// S3/DynamoDB traffic from the NAT tier also stays on AWS's network.
|
|
199
206
|
const gatewayEndpointSubnets: ec2.SubnetSelection[] = importedVpcId
|