diff --git a/packages/@aws-cdk/aws-ecs/README.md b/packages/@aws-cdk/aws-ecs/README.md index 44386b2bcbaf6..738187aa31731 100644 --- a/packages/@aws-cdk/aws-ecs/README.md +++ b/packages/@aws-cdk/aws-ecs/README.md @@ -243,6 +243,7 @@ taskDefinition.addContainer('container', { }, secrets: { // Retrieved from AWS Secrets Manager or AWS Systems Manager Parameter Store at container start-up. SECRET: ecs.Secret.fromSecretsManager(secret), + DB_PASSWORD: ecs.Secret.fromSecretsManager(dbSecret, 'password'), // Reference a specific JSON field PARAMETER: ecs.Secret.fromSsmParameter(parameter), } }); diff --git a/packages/@aws-cdk/aws-ecs/lib/container-definition.ts b/packages/@aws-cdk/aws-ecs/lib/container-definition.ts index 2687e6ad9cdb9..e876f31fc730e 100644 --- a/packages/@aws-cdk/aws-ecs/lib/container-definition.ts +++ b/packages/@aws-cdk/aws-ecs/lib/container-definition.ts @@ -26,10 +26,16 @@ export abstract class Secret { /** * Creates a environment variable value from a secret stored in AWS Secrets * Manager. + * + * @param secret the secret stored in AWS Secrets Manager + * @param field the name of the field with the value that you want to set as + * the environment variable value. Only values in JSON format are supported. + * If you do not specify a JSON field, then the full content of the secret is + * used. */ - public static fromSecretsManager(secret: secretsmanager.ISecret): Secret { + public static fromSecretsManager(secret: secretsmanager.ISecret, field?: string): Secret { return { - arn: secret.secretArn, + arn: field ? `${secret.secretArn}:${field}::` : secret.secretArn, grantRead: grantee => secret.grantRead(grantee), }; } diff --git a/packages/@aws-cdk/aws-ecs/test/fargate/integ.secret-json-key.expected.json b/packages/@aws-cdk/aws-ecs/test/fargate/integ.secret-json-key.expected.json new file mode 100644 index 0000000000000..1a8e791bff7e1 --- /dev/null +++ b/packages/@aws-cdk/aws-ecs/test/fargate/integ.secret-json-key.expected.json @@ -0,0 +1,117 @@ +{ + "Resources": { + "SecretA720EF05": { + "Type": "AWS::SecretsManager::Secret", + "Properties": { + "GenerateSecretString": { + "GenerateStringKey": "password", + "SecretStringTemplate": "{\"username\":\"user\"}" + } + } + }, + "TaskDefTaskRole1EDB4A67": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "ecs-tasks.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "TaskDef54694570": { + "Type": "AWS::ECS::TaskDefinition", + "Properties": { + "ContainerDefinitions": [ + { + "Essential": true, + "Image": "amazon/amazon-ecs-sample", + "Name": "web", + "Secrets": [ + { + "Name": "PASSWORD", + "ValueFrom": { + "Fn::Join": [ + "", + [ + { + "Ref": "SecretA720EF05" + }, + ":password::" + ] + ] + } + } + ] + } + ], + "Cpu": "512", + "ExecutionRoleArn": { + "Fn::GetAtt": [ + "TaskDefExecutionRoleB4775C97", + "Arn" + ] + }, + "Family": "awsecsintegsecretjsonkeyTaskDefC01C0E99", + "Memory": "1024", + "NetworkMode": "awsvpc", + "RequiresCompatibilities": [ + "FARGATE" + ], + "TaskRoleArn": { + "Fn::GetAtt": [ + "TaskDefTaskRole1EDB4A67", + "Arn" + ] + } + } + }, + "TaskDefExecutionRoleB4775C97": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "ecs-tasks.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "TaskDefExecutionRoleDefaultPolicy0DBB737A": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": "secretsmanager:GetSecretValue", + "Effect": "Allow", + "Resource": { + "Ref": "SecretA720EF05" + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "TaskDefExecutionRoleDefaultPolicy0DBB737A", + "Roles": [ + { + "Ref": "TaskDefExecutionRoleB4775C97" + } + ] + } + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-ecs/test/fargate/integ.secret-json-key.ts b/packages/@aws-cdk/aws-ecs/test/fargate/integ.secret-json-key.ts new file mode 100644 index 0000000000000..c7f7073512b98 --- /dev/null +++ b/packages/@aws-cdk/aws-ecs/test/fargate/integ.secret-json-key.ts @@ -0,0 +1,27 @@ +import * as secretsmanager from '@aws-cdk/aws-secretsmanager'; +import * as cdk from '@aws-cdk/core'; +import * as ecs from '../../lib'; + +const app = new cdk.App(); +const stack = new cdk.Stack(app, 'aws-ecs-integ-secret-json-key'); + +const secret = new secretsmanager.Secret(stack, 'Secret', { + generateSecretString: { + generateStringKey: 'password', + secretStringTemplate: JSON.stringify({ username: 'user' }) + } +}); + +const taskDefinition = new ecs.FargateTaskDefinition(stack, 'TaskDef', { + memoryLimitMiB: 1024, + cpu: 512 +}); + +taskDefinition.addContainer('web', { + image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), + secrets: { + PASSWORD: ecs.Secret.fromSecretsManager(secret, 'password') + } +}); + +app.synth(); diff --git a/packages/@aws-cdk/aws-ecs/test/test.container-definition.ts b/packages/@aws-cdk/aws-ecs/test/test.container-definition.ts index f5da5559c5d1b..69809a149d6fd 100644 --- a/packages/@aws-cdk/aws-ecs/test/test.container-definition.ts +++ b/packages/@aws-cdk/aws-ecs/test/test.container-definition.ts @@ -799,6 +799,50 @@ export = { }, + 'use a specific secret JSON key as environment variable'(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef'); + + const secret = new secretsmanager.Secret(stack, 'Secret'); + + // WHEN + taskDefinition.addContainer('cont', { + image: ecs.ContainerImage.fromRegistry('test'), + memoryLimitMiB: 1024, + secrets: { + SECRET_KEY: ecs.Secret.fromSecretsManager(secret, 'specificKey'), + } + }); + + // THEN + expect(stack).to(haveResourceLike('AWS::ECS::TaskDefinition', { + ContainerDefinitions: [ + { + Secrets: [ + { + Name: 'SECRET_KEY', + ValueFrom: { + 'Fn::Join': [ + '', + [ + { + Ref: 'SecretA720EF05' + }, + ':specificKey::' + ] + ] + } + }, + ] + } + ] + })); + + test.done(); + + }, + 'can add AWS logging to container definition'(test: Test) { // GIVEN const stack = new cdk.Stack();