Skip to content

Commit 572f781

Browse files
authoredSep 2, 2022
feat(ecs): add function for adding secrets to containers after instantiating them (#21826)
### Description Similar to `addEnvironment()`, an `addSecret()` method is useful to add secrets to ECS Containers after instantiating them via the constructor. ### Use Case The most important use-case is when writing Task Definition Extensions or Aspects to augment ECS services. For example, setting environment variables and secrets for a logging or monitoring solution. Right now, this can be done only using Escape Hatches and there is no higher level functionality to obtain this behaviour. ### Proposed Solution ```typescript const container = taskDefinition.addContainer('nginx', { image: ecs.ContainerImage.fromRegistry('nginx'), }); container.addSecret('SECRET_1', ecs.Secret.fromSecretsManager(secret)); container.addSecret('SECRET_2', ecs.Secret.fromSecretsManager(secretField, 'password')); ``` closes #18959 ---- ### All Submissions: * [X] Have you followed the guidelines in our [Contributing guide?](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md) ### Adding new Unconventional Dependencies: * [ ] This PR adds new unconventional dependencies following the process described [here](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md/#adding-new-unconventional-dependencies) ### New Features * [X] Have you added the new feature to an [integration test](https://github.com/aws/aws-cdk/blob/main/INTEGRATION_TESTS.md)? * [X] Did you use `yarn integ` to deploy the infrastructure and generate the snapshot (i.e. `yarn integ` without `--dry-run`)? *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
1 parent 3adf841 commit 572f781

25 files changed

+469
-86
lines changed
 

‎packages/@aws-cdk/aws-ecs/README.md

+2
Original file line numberDiff line numberDiff line change
@@ -479,6 +479,8 @@ const newContainer = taskDefinition.addContainer('container', {
479479
},
480480
});
481481
newContainer.addEnvironment('QUEUE_NAME', 'MyQueue');
482+
newContainer.addSecret('API_KEY', ecs.Secret.fromSecretsManager(secret));
483+
newContainer.addSecret('DB_PASSWORD', ecs.Secret.fromSecretsManager(secret, 'password'));
482484
```
483485

484486
The task execution role is automatically granted read permissions on the secrets/parameters. Support for environment

‎packages/@aws-cdk/aws-ecs/lib/base/task-definition.ts

+6-6
Original file line numberDiff line numberDiff line change
@@ -379,8 +379,6 @@ export class TaskDefinition extends TaskDefinitionBase {
379379

380380
private _passRoleStatement?: iam.PolicyStatement;
381381

382-
private _referencesSecretJsonField?: boolean;
383-
384382
private runtimePlatform?: RuntimePlatform;
385383

386384
/**
@@ -614,9 +612,6 @@ export class TaskDefinition extends TaskDefinitionBase {
614612
if (this.defaultContainer === undefined && container.essential) {
615613
this.defaultContainer = container;
616614
}
617-
if (container.referencesSecretJsonField) {
618-
this._referencesSecretJsonField = true;
619-
}
620615
}
621616

622617
/**
@@ -695,7 +690,12 @@ export class TaskDefinition extends TaskDefinitionBase {
695690
* specific JSON field of a secret stored in Secrets Manager.
696691
*/
697692
public get referencesSecretJsonField(): boolean | undefined {
698-
return this._referencesSecretJsonField;
693+
for (const container of this.containers) {
694+
if (container.referencesSecretJsonField) {
695+
return true;
696+
}
697+
}
698+
return false;
699699
}
700700

701701
/**

‎packages/@aws-cdk/aws-ecs/lib/container-definition.ts

+28-17
Original file line numberDiff line numberDiff line change
@@ -435,12 +435,6 @@ export class ContainerDefinition extends Construct {
435435
*/
436436
public readonly logDriverConfig?: LogDriverConfig;
437437

438-
/**
439-
* Whether this container definition references a specific JSON field of a secret
440-
* stored in Secrets Manager.
441-
*/
442-
public readonly referencesSecretJsonField?: boolean;
443-
444438
/**
445439
* The name of the image referenced by this container.
446440
*/
@@ -458,7 +452,7 @@ export class ContainerDefinition extends Construct {
458452

459453
private readonly imageConfig: ContainerImageConfig;
460454

461-
private readonly secrets?: CfnTaskDefinition.SecretProperty[];
455+
private readonly secrets: CfnTaskDefinition.SecretProperty[] = [];
462456

463457
private readonly environment: { [key: string]: string };
464458

@@ -486,16 +480,8 @@ export class ContainerDefinition extends Construct {
486480
}
487481

488482
if (props.secrets) {
489-
this.secrets = [];
490483
for (const [name, secret] of Object.entries(props.secrets)) {
491-
if (secret.hasField) {
492-
this.referencesSecretJsonField = true;
493-
}
494-
secret.grantRead(this.taskDefinition.obtainExecutionRole());
495-
this.secrets.push({
496-
name,
497-
valueFrom: secret.arn,
498-
});
484+
this.addSecret(name, secret);
499485
}
500486
}
501487

@@ -602,6 +588,18 @@ export class ContainerDefinition extends Construct {
602588
this.environment[name] = value;
603589
}
604590

591+
/**
592+
* This method adds a secret as environment variable to the container.
593+
*/
594+
public addSecret(name: string, secret: Secret) {
595+
secret.grantRead(this.taskDefinition.obtainExecutionRole());
596+
597+
this.secrets.push({
598+
name,
599+
valueFrom: secret.arn,
600+
});
601+
}
602+
605603
/**
606604
* This method adds one or more resources to the container.
607605
*/
@@ -658,6 +656,19 @@ export class ContainerDefinition extends Construct {
658656
return undefined;
659657
}
660658

659+
/**
660+
* Whether this container definition references a specific JSON field of a secret
661+
* stored in Secrets Manager.
662+
*/
663+
public get referencesSecretJsonField(): boolean | undefined {
664+
for (const secret of this.secrets) {
665+
if (secret.valueFrom.endsWith('::')) {
666+
return true;
667+
}
668+
}
669+
return false;
670+
}
671+
661672
/**
662673
* The inbound rules associated with the security group the task or service will use.
663674
*
@@ -726,7 +737,7 @@ export class ContainerDefinition extends Construct {
726737
logConfiguration: this.logDriverConfig,
727738
environment: this.environment && Object.keys(this.environment).length ? renderKV(this.environment, 'name', 'value') : undefined,
728739
environmentFiles: this.environmentFiles && renderEnvironmentFiles(cdk.Stack.of(this).partition, this.environmentFiles),
729-
secrets: this.secrets,
740+
secrets: this.secrets.length ? this.secrets : undefined,
730741
extraHosts: this.props.extraHosts && renderKV(this.props.extraHosts, 'hostname', 'ipAddress'),
731742
healthCheck: this.props.healthCheck && renderHealthCheck(this.props.healthCheck),
732743
links: cdk.Lazy.list({ produce: () => this.links }, { omitEmpty: true }),

‎packages/@aws-cdk/aws-ecs/lib/fargate/fargate-service.ts

+8-5
Original file line numberDiff line numberDiff line change
@@ -128,11 +128,6 @@ export class FargateService extends BaseService implements IFargateService {
128128
throw new Error('Only one of SecurityGroup or SecurityGroups can be populated.');
129129
}
130130

131-
if (props.taskDefinition.referencesSecretJsonField
132-
&& props.platformVersion
133-
&& SECRET_JSON_FIELD_UNSUPPORTED_PLATFORM_VERSIONS.includes(props.platformVersion)) {
134-
throw new Error(`The task definition of this service uses at least one container that references a secret JSON field. This feature requires platform version ${FargatePlatformVersion.VERSION1_4} or later.`);
135-
}
136131
super(scope, id, {
137132
...props,
138133
desiredCount: props.desiredCount,
@@ -154,6 +149,14 @@ export class FargateService extends BaseService implements IFargateService {
154149

155150
this.configureAwsVpcNetworkingWithSecurityGroups(props.cluster.vpc, props.assignPublicIp, props.vpcSubnets, securityGroups);
156151

152+
this.node.addValidation({
153+
validate: () => this.taskDefinition.referencesSecretJsonField
154+
&& props.platformVersion
155+
&& SECRET_JSON_FIELD_UNSUPPORTED_PLATFORM_VERSIONS.includes(props.platformVersion)
156+
? [`The task definition of this service uses at least one container that references a secret JSON field. This feature requires platform version ${FargatePlatformVersion.VERSION1_4} or later.`]
157+
: [],
158+
});
159+
157160
this.node.addValidation({
158161
validate: () => !this.taskDefinition.defaultContainer ? ['A TaskDefinition must have at least one essential container'] : [],
159162
});

‎packages/@aws-cdk/aws-ecs/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@
8585
"@aws-cdk/aws-efs": "0.0.0",
8686
"@aws-cdk/cdk-build-tools": "0.0.0",
8787
"@aws-cdk/integ-runner": "0.0.0",
88+
"@aws-cdk/integ-tests": "0.0.0",
8889
"@aws-cdk/cfn2ts": "0.0.0",
8990
"@aws-cdk/cx-api": "0.0.0",
9091
"@aws-cdk/pkglint": "0.0.0",

‎packages/@aws-cdk/aws-ecs/test/container-definition.test.ts

+18-3
Original file line numberDiff line numberDiff line change
@@ -548,7 +548,7 @@ describe('container definition', () => {
548548
const actual = container.containerPort;
549549
const expected = 8080;
550550
expect(actual).toEqual(expected);
551-
}).toThrow(/Container MyContainer hasn't defined any ports. Call addPortMappings()./);
551+
}).toThrow(/Container MyContainer hasn't defined any ports. Call addPortMappings\(\)./);
552552

553553

554554
});
@@ -597,7 +597,7 @@ describe('container definition', () => {
597597
const actual = container.ingressPort;
598598
const expected = 8080;
599599
expect(actual).toEqual(expected);
600-
}).toThrow(/Container MyContainer hasn't defined any ports. Call addPortMappings()./);
600+
}).toThrow(/Container MyContainer hasn't defined any ports. Call addPortMappings\(\)./);
601601

602602

603603
});
@@ -1258,7 +1258,7 @@ describe('container definition', () => {
12581258
});
12591259

12601260
// WHEN
1261-
taskDefinition.addContainer('cont', {
1261+
const container = taskDefinition.addContainer('cont', {
12621262
image: ecs.ContainerImage.fromRegistry('test'),
12631263
memoryLimitMiB: 1024,
12641264
secrets: {
@@ -1268,6 +1268,7 @@ describe('container definition', () => {
12681268
SECRET_STAGE: ecs.Secret.fromSecretsManagerVersion(secret, { versionStage: 'version-stage' }),
12691269
},
12701270
});
1271+
container.addSecret('LATER_SECRET', ecs.Secret.fromSecretsManager(secret, 'field'));
12711272

12721273
// THEN
12731274
Template.fromStack(stack).hasResourceProperties('AWS::ECS::TaskDefinition', {
@@ -1331,6 +1332,20 @@ describe('container definition', () => {
13311332
],
13321333
},
13331334
},
1335+
{
1336+
Name: 'LATER_SECRET',
1337+
ValueFrom: {
1338+
'Fn::Join': [
1339+
'',
1340+
[
1341+
{
1342+
Ref: 'SecretA720EF05',
1343+
},
1344+
':field::',
1345+
],
1346+
],
1347+
},
1348+
},
13341349
],
13351350
}),
13361351
],

‎packages/@aws-cdk/aws-ecs/test/ec2/integ.secret-json-field.ts

+8-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import * as secretsmanager from '@aws-cdk/aws-secretsmanager';
22
import * as cdk from '@aws-cdk/core';
3+
import * as integ from '@aws-cdk/integ-tests';
34
import * as ecs from '../../lib';
45

56
const app = new cdk.App();
@@ -14,12 +15,18 @@ const secret = new secretsmanager.Secret(stack, 'Secret', {
1415

1516
const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef');
1617

17-
taskDefinition.addContainer('web', {
18+
const container = taskDefinition.addContainer('web', {
1819
image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'),
1920
memoryLimitMiB: 256,
2021
secrets: {
2122
PASSWORD: ecs.Secret.fromSecretsManager(secret, 'password'),
2223
},
2324
});
2425

26+
container.addSecret('APIKEY', ecs.Secret.fromSecretsManager(secret, 'apikey'));
27+
28+
new integ.IntegTest(app, 'aws-ecs-ec2-integ-secret-json-field', {
29+
testCases: [stack],
30+
});
31+
2532
app.synth();

‎packages/@aws-cdk/aws-ecs/test/ec2/secret-json-field.integ.snapshot/aws-ecs-integ-secret-json-field.assets.json

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
{
2-
"version": "20.0.0",
2+
"version": "21.0.0",
33
"files": {
4-
"b5f76aca81afb4973dcb922e825af78755db9cb1eb4fe457a9cd07c05e8bf0c7": {
4+
"df25aa5385ee86c1e4753a1f126bc9ed3bd97ffd266ccb980e6bc49e8c32f124": {
55
"source": {
66
"path": "aws-ecs-integ-secret-json-field.template.json",
77
"packaging": "file"
88
},
99
"destinations": {
1010
"current_account-current_region": {
1111
"bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}",
12-
"objectKey": "b5f76aca81afb4973dcb922e825af78755db9cb1eb4fe457a9cd07c05e8bf0c7.json",
12+
"objectKey": "df25aa5385ee86c1e4753a1f126bc9ed3bd97ffd266ccb980e6bc49e8c32f124.json",
1313
"assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}"
1414
}
1515
}

‎packages/@aws-cdk/aws-ecs/test/ec2/secret-json-field.integ.snapshot/aws-ecs-integ-secret-json-field.template.json

+14
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,20 @@
5151
]
5252
]
5353
}
54+
},
55+
{
56+
"Name": "APIKEY",
57+
"ValueFrom": {
58+
"Fn::Join": [
59+
"",
60+
[
61+
{
62+
"Ref": "SecretA720EF05"
63+
},
64+
":apikey::"
65+
]
66+
]
67+
}
5468
}
5569
]
5670
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"version": "21.0.0",
3+
"files": {
4+
"21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": {
5+
"source": {
6+
"path": "awsecsec2integsecretjsonfieldDefaultTestDeployAssert5B8058F0.template.json",
7+
"packaging": "file"
8+
},
9+
"destinations": {
10+
"current_account-current_region": {
11+
"bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}",
12+
"objectKey": "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22.json",
13+
"assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}"
14+
}
15+
}
16+
}
17+
},
18+
"dockerImages": {}
19+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
{
2+
"Parameters": {
3+
"BootstrapVersion": {
4+
"Type": "AWS::SSM::Parameter::Value<String>",
5+
"Default": "/cdk-bootstrap/hnb659fds/version",
6+
"Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]"
7+
}
8+
},
9+
"Rules": {
10+
"CheckBootstrapVersion": {
11+
"Assertions": [
12+
{
13+
"Assert": {
14+
"Fn::Not": [
15+
{
16+
"Fn::Contains": [
17+
[
18+
"1",
19+
"2",
20+
"3",
21+
"4",
22+
"5"
23+
],
24+
{
25+
"Ref": "BootstrapVersion"
26+
}
27+
]
28+
}
29+
]
30+
},
31+
"AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI."
32+
}
33+
]
34+
}
35+
}
36+
}
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{"version":"20.0.0"}
1+
{"version":"21.0.0"}
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
11
{
2-
"version": "20.0.0",
2+
"version": "21.0.0",
33
"testCases": {
4-
"integ.secret-json-field": {
4+
"aws-ecs-ec2-integ-secret-json-field/DefaultTest": {
55
"stacks": [
66
"aws-ecs-integ-secret-json-field"
77
],
8-
"diffAssets": false,
9-
"stackUpdateWorkflow": true
8+
"assertionStack": "aws-ecs-ec2-integ-secret-json-field/DefaultTest/DeployAssert",
9+
"assertionStackName": "awsecsec2integsecretjsonfieldDefaultTestDeployAssert5B8058F0"
1010
}
11-
},
12-
"synthContext": {},
13-
"enableLookups": false
11+
}
1412
}

‎packages/@aws-cdk/aws-ecs/test/ec2/secret-json-field.integ.snapshot/manifest.json

+53-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"version": "20.0.0",
2+
"version": "21.0.0",
33
"artifacts": {
44
"Tree": {
55
"type": "cdk:tree",
@@ -23,7 +23,7 @@
2323
"validateOnSynth": false,
2424
"assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}",
2525
"cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}",
26-
"stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/b5f76aca81afb4973dcb922e825af78755db9cb1eb4fe457a9cd07c05e8bf0c7.json",
26+
"stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/df25aa5385ee86c1e4753a1f126bc9ed3bd97ffd266ccb980e6bc49e8c32f124.json",
2727
"requiresBootstrapStackVersion": 6,
2828
"bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version",
2929
"additionalDependencies": [
@@ -54,7 +54,10 @@
5454
"/aws-ecs-integ-secret-json-field/TaskDef/Resource": [
5555
{
5656
"type": "aws:cdk:logicalId",
57-
"data": "TaskDef54694570"
57+
"data": "TaskDef54694570",
58+
"trace": [
59+
"!!DESTRUCTIVE_CHANGES: WILL_REPLACE"
60+
]
5861
}
5962
],
6063
"/aws-ecs-integ-secret-json-field/TaskDef/ExecutionRole/Resource": [
@@ -83,6 +86,53 @@
8386
]
8487
},
8588
"displayName": "aws-ecs-integ-secret-json-field"
89+
},
90+
"awsecsec2integsecretjsonfieldDefaultTestDeployAssert5B8058F0.assets": {
91+
"type": "cdk:asset-manifest",
92+
"properties": {
93+
"file": "awsecsec2integsecretjsonfieldDefaultTestDeployAssert5B8058F0.assets.json",
94+
"requiresBootstrapStackVersion": 6,
95+
"bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version"
96+
}
97+
},
98+
"awsecsec2integsecretjsonfieldDefaultTestDeployAssert5B8058F0": {
99+
"type": "aws:cloudformation:stack",
100+
"environment": "aws://unknown-account/unknown-region",
101+
"properties": {
102+
"templateFile": "awsecsec2integsecretjsonfieldDefaultTestDeployAssert5B8058F0.template.json",
103+
"validateOnSynth": false,
104+
"assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}",
105+
"cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}",
106+
"stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22.json",
107+
"requiresBootstrapStackVersion": 6,
108+
"bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version",
109+
"additionalDependencies": [
110+
"awsecsec2integsecretjsonfieldDefaultTestDeployAssert5B8058F0.assets"
111+
],
112+
"lookupRole": {
113+
"arn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-lookup-role-${AWS::AccountId}-${AWS::Region}",
114+
"requiresBootstrapStackVersion": 8,
115+
"bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version"
116+
}
117+
},
118+
"dependencies": [
119+
"awsecsec2integsecretjsonfieldDefaultTestDeployAssert5B8058F0.assets"
120+
],
121+
"metadata": {
122+
"/aws-ecs-ec2-integ-secret-json-field/DefaultTest/DeployAssert/BootstrapVersion": [
123+
{
124+
"type": "aws:cdk:logicalId",
125+
"data": "BootstrapVersion"
126+
}
127+
],
128+
"/aws-ecs-ec2-integ-secret-json-field/DefaultTest/DeployAssert/CheckBootstrapVersion": [
129+
{
130+
"type": "aws:cdk:logicalId",
131+
"data": "CheckBootstrapVersion"
132+
}
133+
]
134+
},
135+
"displayName": "aws-ecs-ec2-integ-secret-json-field/DefaultTest/DeployAssert"
86136
}
87137
}
88138
}

‎packages/@aws-cdk/aws-ecs/test/ec2/secret-json-field.integ.snapshot/tree.json

+59-9
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
"path": "Tree",
1010
"constructInfo": {
1111
"fqn": "constructs.Construct",
12-
"version": "10.1.85"
12+
"version": "10.1.92"
1313
}
1414
},
1515
"aws-ecs-integ-secret-json-field": {
@@ -108,6 +108,20 @@
108108
]
109109
]
110110
}
111+
},
112+
{
113+
"name": "APIKEY",
114+
"valueFrom": {
115+
"Fn::Join": [
116+
"",
117+
[
118+
{
119+
"Ref": "SecretA720EF05"
120+
},
121+
":apikey::"
122+
]
123+
]
124+
}
111125
}
112126
]
113127
}
@@ -132,16 +146,16 @@
132146
}
133147
},
134148
"constructInfo": {
135-
"fqn": "@aws-cdk/aws-ecs.CfnTaskDefinition",
149+
"fqn": "@aws-cdk/core.CfnResource",
136150
"version": "0.0.0"
137151
}
138152
},
139153
"web": {
140154
"id": "web",
141155
"path": "aws-ecs-integ-secret-json-field/TaskDef/web",
142156
"constructInfo": {
143-
"fqn": "@aws-cdk/aws-ecs.ContainerDefinition",
144-
"version": "0.0.0"
157+
"fqn": "constructs.Construct",
158+
"version": "10.1.92"
145159
}
146160
},
147161
"ExecutionRole": {
@@ -225,20 +239,56 @@
225239
}
226240
},
227241
"constructInfo": {
228-
"fqn": "@aws-cdk/aws-ecs.Ec2TaskDefinition",
242+
"fqn": "@aws-cdk/core.Resource",
229243
"version": "0.0.0"
230244
}
231245
}
232246
},
233247
"constructInfo": {
234-
"fqn": "constructs.Construct",
235-
"version": "10.1.85"
248+
"fqn": "@aws-cdk/core.Stack",
249+
"version": "0.0.0"
250+
}
251+
},
252+
"aws-ecs-ec2-integ-secret-json-field": {
253+
"id": "aws-ecs-ec2-integ-secret-json-field",
254+
"path": "aws-ecs-ec2-integ-secret-json-field",
255+
"children": {
256+
"DefaultTest": {
257+
"id": "DefaultTest",
258+
"path": "aws-ecs-ec2-integ-secret-json-field/DefaultTest",
259+
"children": {
260+
"Default": {
261+
"id": "Default",
262+
"path": "aws-ecs-ec2-integ-secret-json-field/DefaultTest/Default",
263+
"constructInfo": {
264+
"fqn": "constructs.Construct",
265+
"version": "10.1.92"
266+
}
267+
},
268+
"DeployAssert": {
269+
"id": "DeployAssert",
270+
"path": "aws-ecs-ec2-integ-secret-json-field/DefaultTest/DeployAssert",
271+
"constructInfo": {
272+
"fqn": "@aws-cdk/core.Stack",
273+
"version": "0.0.0"
274+
}
275+
}
276+
},
277+
"constructInfo": {
278+
"fqn": "@aws-cdk/integ-tests.IntegTestCase",
279+
"version": "0.0.0"
280+
}
281+
}
282+
},
283+
"constructInfo": {
284+
"fqn": "@aws-cdk/integ-tests.IntegTest",
285+
"version": "0.0.0"
236286
}
237287
}
238288
},
239289
"constructInfo": {
240-
"fqn": "constructs.Construct",
241-
"version": "10.1.85"
290+
"fqn": "@aws-cdk/core.App",
291+
"version": "0.0.0"
242292
}
243293
}
244294
}

‎packages/@aws-cdk/aws-ecs/test/fargate/fargate-service.test.ts

+10-7
Original file line numberDiff line numberDiff line change
@@ -587,13 +587,16 @@ describe('fargate service', () => {
587587
},
588588
});
589589

590+
// Errors on validation, not on construction.
591+
new ecs.FargateService(stack, 'FargateService', {
592+
cluster,
593+
taskDefinition,
594+
platformVersion: ecs.FargatePlatformVersion.VERSION1_3,
595+
});
596+
590597
// THEN
591598
expect(() => {
592-
new ecs.FargateService(stack, 'FargateService', {
593-
cluster,
594-
taskDefinition,
595-
platformVersion: ecs.FargatePlatformVersion.VERSION1_3,
596-
});
599+
Template.fromStack(stack);
597600
}).toThrow(new RegExp(`uses at least one container that references a secret JSON field.+platform version ${ecs.FargatePlatformVersion.VERSION1_4} or later`));
598601
});
599602

@@ -1262,7 +1265,7 @@ describe('fargate service', () => {
12621265
containerPort: 8001,
12631266
})],
12641267
});
1265-
}).toThrow(/No container named 'SideContainer'. Did you call "addContainer()"?/);
1268+
}).toThrow(/No container named 'SideContainer'. Did you call "addContainer\(\)"?/);
12661269
});
12671270
});
12681271

@@ -2178,7 +2181,7 @@ describe('fargate service', () => {
21782181
],
21792182
});
21802183
});
2181-
}),
2184+
});
21822185

21832186
test('with serviceArn old format', () => {
21842187
// GIVEN

‎packages/@aws-cdk/aws-ecs/test/fargate/integ.secret.ts

+8-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import * as secretsmanager from '@aws-cdk/aws-secretsmanager';
22
import * as cdk from '@aws-cdk/core';
3+
import * as integ from '@aws-cdk/integ-tests';
34
import * as ecs from '../../lib';
45

56
const app = new cdk.App();
@@ -14,12 +15,18 @@ const secret = new secretsmanager.Secret(stack, 'Secret', {
1415

1516
const taskDefinition = new ecs.FargateTaskDefinition(stack, 'TaskDef');
1617

17-
taskDefinition.addContainer('web', {
18+
const container = taskDefinition.addContainer('web', {
1819
image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'),
1920
secrets: {
2021
SECRET: ecs.Secret.fromSecretsManager(secret),
2122
PASSWORD: ecs.Secret.fromSecretsManager(secret, 'password'),
2223
},
2324
});
2425

26+
container.addSecret('APIKEY', ecs.Secret.fromSecretsManager(secret, 'apikey'));
27+
28+
new integ.IntegTest(app, 'aws-ecs-fargate-integ-secret', {
29+
testCases: [stack],
30+
});
31+
2532
app.synth();

‎packages/@aws-cdk/aws-ecs/test/fargate/secret.integ.snapshot/aws-ecs-integ-secret.assets.json

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
{
2-
"version": "20.0.0",
2+
"version": "21.0.0",
33
"files": {
4-
"1b68069d3b5ede524bed6fa719e69d034d31abf105b94943e5f9af1a18a44d3e": {
4+
"4727087105a7e5f98c1d902ecfbeea59f5f9ae4a5dfef11195a6fa3e21f5e4f5": {
55
"source": {
66
"path": "aws-ecs-integ-secret.template.json",
77
"packaging": "file"
88
},
99
"destinations": {
1010
"current_account-current_region": {
1111
"bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}",
12-
"objectKey": "1b68069d3b5ede524bed6fa719e69d034d31abf105b94943e5f9af1a18a44d3e.json",
12+
"objectKey": "4727087105a7e5f98c1d902ecfbeea59f5f9ae4a5dfef11195a6fa3e21f5e4f5.json",
1313
"assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}"
1414
}
1515
}

‎packages/@aws-cdk/aws-ecs/test/fargate/secret.integ.snapshot/aws-ecs-integ-secret.template.json

+14
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,20 @@
5656
]
5757
]
5858
}
59+
},
60+
{
61+
"Name": "APIKEY",
62+
"ValueFrom": {
63+
"Fn::Join": [
64+
"",
65+
[
66+
{
67+
"Ref": "SecretA720EF05"
68+
},
69+
":apikey::"
70+
]
71+
]
72+
}
5973
}
6074
]
6175
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"version": "21.0.0",
3+
"files": {
4+
"21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": {
5+
"source": {
6+
"path": "awsecsfargateintegsecretDefaultTestDeployAssert3A9C52E8.template.json",
7+
"packaging": "file"
8+
},
9+
"destinations": {
10+
"current_account-current_region": {
11+
"bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}",
12+
"objectKey": "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22.json",
13+
"assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}"
14+
}
15+
}
16+
}
17+
},
18+
"dockerImages": {}
19+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
{
2+
"Parameters": {
3+
"BootstrapVersion": {
4+
"Type": "AWS::SSM::Parameter::Value<String>",
5+
"Default": "/cdk-bootstrap/hnb659fds/version",
6+
"Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]"
7+
}
8+
},
9+
"Rules": {
10+
"CheckBootstrapVersion": {
11+
"Assertions": [
12+
{
13+
"Assert": {
14+
"Fn::Not": [
15+
{
16+
"Fn::Contains": [
17+
[
18+
"1",
19+
"2",
20+
"3",
21+
"4",
22+
"5"
23+
],
24+
{
25+
"Ref": "BootstrapVersion"
26+
}
27+
]
28+
}
29+
]
30+
},
31+
"AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI."
32+
}
33+
]
34+
}
35+
}
36+
}
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{"version":"20.0.0"}
1+
{"version":"21.0.0"}
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
11
{
2-
"version": "20.0.0",
2+
"version": "21.0.0",
33
"testCases": {
4-
"integ.secret": {
4+
"aws-ecs-fargate-integ-secret/DefaultTest": {
55
"stacks": [
66
"aws-ecs-integ-secret"
77
],
8-
"diffAssets": false,
9-
"stackUpdateWorkflow": true
8+
"assertionStack": "aws-ecs-fargate-integ-secret/DefaultTest/DeployAssert",
9+
"assertionStackName": "awsecsfargateintegsecretDefaultTestDeployAssert3A9C52E8"
1010
}
11-
},
12-
"synthContext": {},
13-
"enableLookups": false
11+
}
1412
}

‎packages/@aws-cdk/aws-ecs/test/fargate/secret.integ.snapshot/manifest.json

+53-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"version": "20.0.0",
2+
"version": "21.0.0",
33
"artifacts": {
44
"Tree": {
55
"type": "cdk:tree",
@@ -23,7 +23,7 @@
2323
"validateOnSynth": false,
2424
"assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}",
2525
"cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}",
26-
"stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/1b68069d3b5ede524bed6fa719e69d034d31abf105b94943e5f9af1a18a44d3e.json",
26+
"stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/4727087105a7e5f98c1d902ecfbeea59f5f9ae4a5dfef11195a6fa3e21f5e4f5.json",
2727
"requiresBootstrapStackVersion": 6,
2828
"bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version",
2929
"additionalDependencies": [
@@ -54,7 +54,10 @@
5454
"/aws-ecs-integ-secret/TaskDef/Resource": [
5555
{
5656
"type": "aws:cdk:logicalId",
57-
"data": "TaskDef54694570"
57+
"data": "TaskDef54694570",
58+
"trace": [
59+
"!!DESTRUCTIVE_CHANGES: WILL_REPLACE"
60+
]
5861
}
5962
],
6063
"/aws-ecs-integ-secret/TaskDef/ExecutionRole/Resource": [
@@ -83,6 +86,53 @@
8386
]
8487
},
8588
"displayName": "aws-ecs-integ-secret"
89+
},
90+
"awsecsfargateintegsecretDefaultTestDeployAssert3A9C52E8.assets": {
91+
"type": "cdk:asset-manifest",
92+
"properties": {
93+
"file": "awsecsfargateintegsecretDefaultTestDeployAssert3A9C52E8.assets.json",
94+
"requiresBootstrapStackVersion": 6,
95+
"bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version"
96+
}
97+
},
98+
"awsecsfargateintegsecretDefaultTestDeployAssert3A9C52E8": {
99+
"type": "aws:cloudformation:stack",
100+
"environment": "aws://unknown-account/unknown-region",
101+
"properties": {
102+
"templateFile": "awsecsfargateintegsecretDefaultTestDeployAssert3A9C52E8.template.json",
103+
"validateOnSynth": false,
104+
"assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}",
105+
"cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}",
106+
"stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22.json",
107+
"requiresBootstrapStackVersion": 6,
108+
"bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version",
109+
"additionalDependencies": [
110+
"awsecsfargateintegsecretDefaultTestDeployAssert3A9C52E8.assets"
111+
],
112+
"lookupRole": {
113+
"arn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-lookup-role-${AWS::AccountId}-${AWS::Region}",
114+
"requiresBootstrapStackVersion": 8,
115+
"bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version"
116+
}
117+
},
118+
"dependencies": [
119+
"awsecsfargateintegsecretDefaultTestDeployAssert3A9C52E8.assets"
120+
],
121+
"metadata": {
122+
"/aws-ecs-fargate-integ-secret/DefaultTest/DeployAssert/BootstrapVersion": [
123+
{
124+
"type": "aws:cdk:logicalId",
125+
"data": "BootstrapVersion"
126+
}
127+
],
128+
"/aws-ecs-fargate-integ-secret/DefaultTest/DeployAssert/CheckBootstrapVersion": [
129+
{
130+
"type": "aws:cdk:logicalId",
131+
"data": "CheckBootstrapVersion"
132+
}
133+
]
134+
},
135+
"displayName": "aws-ecs-fargate-integ-secret/DefaultTest/DeployAssert"
86136
}
87137
}
88138
}

‎packages/@aws-cdk/aws-ecs/test/fargate/secret.integ.snapshot/tree.json

+59-9
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
"path": "Tree",
1010
"constructInfo": {
1111
"fqn": "constructs.Construct",
12-
"version": "10.1.85"
12+
"version": "10.1.92"
1313
}
1414
},
1515
"aws-ecs-integ-secret": {
@@ -113,6 +113,20 @@
113113
]
114114
]
115115
}
116+
},
117+
{
118+
"name": "APIKEY",
119+
"valueFrom": {
120+
"Fn::Join": [
121+
"",
122+
[
123+
{
124+
"Ref": "SecretA720EF05"
125+
},
126+
":apikey::"
127+
]
128+
]
129+
}
116130
}
117131
]
118132
}
@@ -139,16 +153,16 @@
139153
}
140154
},
141155
"constructInfo": {
142-
"fqn": "@aws-cdk/aws-ecs.CfnTaskDefinition",
156+
"fqn": "@aws-cdk/core.CfnResource",
143157
"version": "0.0.0"
144158
}
145159
},
146160
"web": {
147161
"id": "web",
148162
"path": "aws-ecs-integ-secret/TaskDef/web",
149163
"constructInfo": {
150-
"fqn": "@aws-cdk/aws-ecs.ContainerDefinition",
151-
"version": "0.0.0"
164+
"fqn": "constructs.Construct",
165+
"version": "10.1.92"
152166
}
153167
},
154168
"ExecutionRole": {
@@ -232,20 +246,56 @@
232246
}
233247
},
234248
"constructInfo": {
235-
"fqn": "@aws-cdk/aws-ecs.FargateTaskDefinition",
249+
"fqn": "@aws-cdk/core.Resource",
236250
"version": "0.0.0"
237251
}
238252
}
239253
},
240254
"constructInfo": {
241-
"fqn": "constructs.Construct",
242-
"version": "10.1.85"
255+
"fqn": "@aws-cdk/core.Stack",
256+
"version": "0.0.0"
257+
}
258+
},
259+
"aws-ecs-fargate-integ-secret": {
260+
"id": "aws-ecs-fargate-integ-secret",
261+
"path": "aws-ecs-fargate-integ-secret",
262+
"children": {
263+
"DefaultTest": {
264+
"id": "DefaultTest",
265+
"path": "aws-ecs-fargate-integ-secret/DefaultTest",
266+
"children": {
267+
"Default": {
268+
"id": "Default",
269+
"path": "aws-ecs-fargate-integ-secret/DefaultTest/Default",
270+
"constructInfo": {
271+
"fqn": "constructs.Construct",
272+
"version": "10.1.92"
273+
}
274+
},
275+
"DeployAssert": {
276+
"id": "DeployAssert",
277+
"path": "aws-ecs-fargate-integ-secret/DefaultTest/DeployAssert",
278+
"constructInfo": {
279+
"fqn": "@aws-cdk/core.Stack",
280+
"version": "0.0.0"
281+
}
282+
}
283+
},
284+
"constructInfo": {
285+
"fqn": "@aws-cdk/integ-tests.IntegTestCase",
286+
"version": "0.0.0"
287+
}
288+
}
289+
},
290+
"constructInfo": {
291+
"fqn": "@aws-cdk/integ-tests.IntegTest",
292+
"version": "0.0.0"
243293
}
244294
}
245295
},
246296
"constructInfo": {
247-
"fqn": "constructs.Construct",
248-
"version": "10.1.85"
297+
"fqn": "@aws-cdk/core.App",
298+
"version": "0.0.0"
249299
}
250300
}
251301
}

0 commit comments

Comments
 (0)
Please sign in to comment.