From 1b18a192fab79c6f65cb9c554a7473e36aa67297 Mon Sep 17 00:00:00 2001 From: Joshua Weber <57131123+daschaa@users.noreply.github.com> Date: Tue, 18 Apr 2023 15:20:59 +0200 Subject: [PATCH 1/7] feat(kms): add required aliasname prefix to aliasnames with tokens (#25116) Closes #25033. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- .../TestStack.assets.json | 19 ++ .../TestStack.template.json | 95 +++++++++ .../test/integ.key-alias.js.snapshot/cdk.out | 1 + .../integ.key-alias.js.snapshot/integ.json | 12 ++ ...efaultTestDeployAssertB7F64730.assets.json | 19 ++ ...aultTestDeployAssertB7F64730.template.json | 36 ++++ .../integ.key-alias.js.snapshot/manifest.json | 117 +++++++++++ .../integ.key-alias.js.snapshot/tree.json | 192 ++++++++++++++++++ .../test/aws-kms/test/integ.key-alias.ts | 21 ++ packages/aws-cdk-lib/aws-kms/lib/alias.ts | 18 +- .../aws-cdk-lib/aws-kms/test/alias.test.ts | 101 ++++++++- 11 files changed, 626 insertions(+), 5 deletions(-) create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-kms/test/integ.key-alias.js.snapshot/TestStack.assets.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-kms/test/integ.key-alias.js.snapshot/TestStack.template.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-kms/test/integ.key-alias.js.snapshot/cdk.out create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-kms/test/integ.key-alias.js.snapshot/integ.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-kms/test/integ.key-alias.js.snapshot/kmskeyaliastokenizedDefaultTestDeployAssertB7F64730.assets.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-kms/test/integ.key-alias.js.snapshot/kmskeyaliastokenizedDefaultTestDeployAssertB7F64730.template.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-kms/test/integ.key-alias.js.snapshot/manifest.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-kms/test/integ.key-alias.js.snapshot/tree.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-kms/test/integ.key-alias.ts diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-kms/test/integ.key-alias.js.snapshot/TestStack.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-kms/test/integ.key-alias.js.snapshot/TestStack.assets.json new file mode 100644 index 0000000000000..277b85e4ee93d --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-kms/test/integ.key-alias.js.snapshot/TestStack.assets.json @@ -0,0 +1,19 @@ +{ + "version": "31.0.0", + "files": { + "a9ca98b70cfab72ff09e4071d78a7a0da7ba609be2b17443a68bd1750fa18069": { + "source": { + "path": "TestStack.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "a9ca98b70cfab72ff09e4071d78a7a0da7ba609be2b17443a68bd1750fa18069.json", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + } + }, + "dockerImages": {} +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-kms/test/integ.key-alias.js.snapshot/TestStack.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-kms/test/integ.key-alias.js.snapshot/TestStack.template.json new file mode 100644 index 0000000000000..33365a5f65ce6 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-kms/test/integ.key-alias.js.snapshot/TestStack.template.json @@ -0,0 +1,95 @@ +{ + "Resources": { + "keyFEDD6EC0": { + "Type": "AWS::KMS::Key", + "Properties": { + "KeyPolicy": { + "Statement": [ + { + "Action": "kms:*", + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":root" + ] + ] + } + }, + "Resource": "*" + } + ], + "Version": "2012-10-17" + } + }, + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" + }, + "keyAliasCEB16DF2": { + "Type": "AWS::KMS::Alias", + "Properties": { + "AliasName": { + "Fn::Join": [ + "", + [ + "alias/MyKey", + { + "Ref": "AWS::AccountId" + } + ] + ] + }, + "TargetKeyId": { + "Fn::GetAtt": [ + "keyFEDD6EC0", + "Arn" + ] + } + } + } + }, + "Parameters": { + "BootstrapVersion": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/cdk-bootstrap/hnb659fds/version", + "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]" + } + }, + "Rules": { + "CheckBootstrapVersion": { + "Assertions": [ + { + "Assert": { + "Fn::Not": [ + { + "Fn::Contains": [ + [ + "1", + "2", + "3", + "4", + "5" + ], + { + "Ref": "BootstrapVersion" + } + ] + } + ] + }, + "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI." + } + ] + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-kms/test/integ.key-alias.js.snapshot/cdk.out b/packages/@aws-cdk-testing/framework-integ/test/aws-kms/test/integ.key-alias.js.snapshot/cdk.out new file mode 100644 index 0000000000000..7925065efbcc4 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-kms/test/integ.key-alias.js.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"31.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-kms/test/integ.key-alias.js.snapshot/integ.json b/packages/@aws-cdk-testing/framework-integ/test/aws-kms/test/integ.key-alias.js.snapshot/integ.json new file mode 100644 index 0000000000000..84314db8bff1d --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-kms/test/integ.key-alias.js.snapshot/integ.json @@ -0,0 +1,12 @@ +{ + "version": "31.0.0", + "testCases": { + "kms-key-alias-tokenized/DefaultTest": { + "stacks": [ + "TestStack" + ], + "assertionStack": "kms-key-alias-tokenized/DefaultTest/DeployAssert", + "assertionStackName": "kmskeyaliastokenizedDefaultTestDeployAssertB7F64730" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-kms/test/integ.key-alias.js.snapshot/kmskeyaliastokenizedDefaultTestDeployAssertB7F64730.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-kms/test/integ.key-alias.js.snapshot/kmskeyaliastokenizedDefaultTestDeployAssertB7F64730.assets.json new file mode 100644 index 0000000000000..34e912d967c67 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-kms/test/integ.key-alias.js.snapshot/kmskeyaliastokenizedDefaultTestDeployAssertB7F64730.assets.json @@ -0,0 +1,19 @@ +{ + "version": "31.0.0", + "files": { + "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { + "source": { + "path": "kmskeyaliastokenizedDefaultTestDeployAssertB7F64730.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22.json", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + } + }, + "dockerImages": {} +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-kms/test/integ.key-alias.js.snapshot/kmskeyaliastokenizedDefaultTestDeployAssertB7F64730.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-kms/test/integ.key-alias.js.snapshot/kmskeyaliastokenizedDefaultTestDeployAssertB7F64730.template.json new file mode 100644 index 0000000000000..ad9d0fb73d1dd --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-kms/test/integ.key-alias.js.snapshot/kmskeyaliastokenizedDefaultTestDeployAssertB7F64730.template.json @@ -0,0 +1,36 @@ +{ + "Parameters": { + "BootstrapVersion": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/cdk-bootstrap/hnb659fds/version", + "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]" + } + }, + "Rules": { + "CheckBootstrapVersion": { + "Assertions": [ + { + "Assert": { + "Fn::Not": [ + { + "Fn::Contains": [ + [ + "1", + "2", + "3", + "4", + "5" + ], + { + "Ref": "BootstrapVersion" + } + ] + } + ] + }, + "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI." + } + ] + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-kms/test/integ.key-alias.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/aws-kms/test/integ.key-alias.js.snapshot/manifest.json new file mode 100644 index 0000000000000..5b9403d84460a --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-kms/test/integ.key-alias.js.snapshot/manifest.json @@ -0,0 +1,117 @@ +{ + "version": "31.0.0", + "artifacts": { + "TestStack.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "TestStack.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "TestStack": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "TestStack.template.json", + "validateOnSynth": false, + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", + "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/a9ca98b70cfab72ff09e4071d78a7a0da7ba609be2b17443a68bd1750fa18069.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "TestStack.assets" + ], + "lookupRole": { + "arn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-lookup-role-${AWS::AccountId}-${AWS::Region}", + "requiresBootstrapStackVersion": 8, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "dependencies": [ + "TestStack.assets" + ], + "metadata": { + "/TestStack/key/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "keyFEDD6EC0" + } + ], + "/TestStack/key/Alias/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "keyAliasCEB16DF2" + } + ], + "/TestStack/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/TestStack/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "TestStack" + }, + "kmskeyaliastokenizedDefaultTestDeployAssertB7F64730.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "kmskeyaliastokenizedDefaultTestDeployAssertB7F64730.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "kmskeyaliastokenizedDefaultTestDeployAssertB7F64730": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "kmskeyaliastokenizedDefaultTestDeployAssertB7F64730.template.json", + "validateOnSynth": false, + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", + "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "kmskeyaliastokenizedDefaultTestDeployAssertB7F64730.assets" + ], + "lookupRole": { + "arn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-lookup-role-${AWS::AccountId}-${AWS::Region}", + "requiresBootstrapStackVersion": 8, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "dependencies": [ + "kmskeyaliastokenizedDefaultTestDeployAssertB7F64730.assets" + ], + "metadata": { + "/kms-key-alias-tokenized/DefaultTest/DeployAssert/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/kms-key-alias-tokenized/DefaultTest/DeployAssert/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "kms-key-alias-tokenized/DefaultTest/DeployAssert" + }, + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + } + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-kms/test/integ.key-alias.js.snapshot/tree.json b/packages/@aws-cdk-testing/framework-integ/test/aws-kms/test/integ.key-alias.js.snapshot/tree.json new file mode 100644 index 0000000000000..a28eec8d6c735 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-kms/test/integ.key-alias.js.snapshot/tree.json @@ -0,0 +1,192 @@ +{ + "version": "tree-0.1", + "tree": { + "id": "App", + "path": "", + "children": { + "TestStack": { + "id": "TestStack", + "path": "TestStack", + "children": { + "key": { + "id": "key", + "path": "TestStack/key", + "children": { + "Resource": { + "id": "Resource", + "path": "TestStack/key/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::KMS::Key", + "aws:cdk:cloudformation:props": { + "keyPolicy": { + "Statement": [ + { + "Action": "kms:*", + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":root" + ] + ] + } + }, + "Resource": "*" + } + ], + "Version": "2012-10-17" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_kms.CfnKey", + "version": "0.0.0" + } + }, + "Alias": { + "id": "Alias", + "path": "TestStack/key/Alias", + "children": { + "Resource": { + "id": "Resource", + "path": "TestStack/key/Alias/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::KMS::Alias", + "aws:cdk:cloudformation:props": { + "aliasName": { + "Fn::Join": [ + "", + [ + "alias/MyKey", + { + "Ref": "AWS::AccountId" + } + ] + ] + }, + "targetKeyId": { + "Fn::GetAtt": [ + "keyFEDD6EC0", + "Arn" + ] + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_kms.CfnAlias", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_kms.Alias", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_kms.Key", + "version": "0.0.0" + } + }, + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "TestStack/BootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "TestStack/CheckBootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnRule", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.Stack", + "version": "0.0.0" + } + }, + "kms-key-alias-tokenized": { + "id": "kms-key-alias-tokenized", + "path": "kms-key-alias-tokenized", + "children": { + "DefaultTest": { + "id": "DefaultTest", + "path": "kms-key-alias-tokenized/DefaultTest", + "children": { + "Default": { + "id": "Default", + "path": "kms-key-alias-tokenized/DefaultTest/Default", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + }, + "DeployAssert": { + "id": "DeployAssert", + "path": "kms-key-alias-tokenized/DefaultTest/DeployAssert", + "children": { + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "kms-key-alias-tokenized/DefaultTest/DeployAssert/BootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "kms-key-alias-tokenized/DefaultTest/DeployAssert/CheckBootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnRule", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.Stack", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests-alpha.IntegTestCase", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests-alpha.IntegTest", + "version": "0.0.0" + } + }, + "Tree": { + "id": "Tree", + "path": "Tree", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.App", + "version": "0.0.0" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-kms/test/integ.key-alias.ts b/packages/@aws-cdk-testing/framework-integ/test/aws-kms/test/integ.key-alias.ts new file mode 100644 index 0000000000000..d8109cee5a76e --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-kms/test/integ.key-alias.ts @@ -0,0 +1,21 @@ +import { App, Stack } from 'aws-cdk-lib'; +import { Key } from 'aws-cdk-lib/aws-kms'; +import { IntegTest } from '@aws-cdk/integ-tests-alpha'; + +class TestStack extends Stack { + constructor(scope: App) { + super(scope, 'TestStack'); + new Key(this, 'key', { + alias: `MyKey${this.account}`, + }); + } +} + +const app = new App(); +const stack = new TestStack(app); + +new IntegTest(app, 'kms-key-alias-tokenized', { + testCases: [stack], +}); + +app.synth(); diff --git a/packages/aws-cdk-lib/aws-kms/lib/alias.ts b/packages/aws-cdk-lib/aws-kms/lib/alias.ts index f62e0fcca3e66..e26b20146a391 100644 --- a/packages/aws-cdk-lib/aws-kms/lib/alias.ts +++ b/packages/aws-cdk-lib/aws-kms/lib/alias.ts @@ -1,8 +1,8 @@ -import * as iam from '../../aws-iam'; -import { RemovalPolicy, Resource, Stack, Token } from '../../core'; import { Construct } from 'constructs'; import { IKey } from './key'; import { CfnAlias } from './kms.generated'; +import * as iam from '../../aws-iam'; +import { RemovalPolicy, Resource, Stack, Token, Tokenization } from '../../core'; const REQUIRED_ALIAS_PREFIX = 'alias/'; const DISALLOWED_PREFIX = REQUIRED_ALIAS_PREFIX + 'aws/'; @@ -197,6 +197,20 @@ export class Alias extends AliasBase { if (!aliasName.match(/^[a-zA-Z0-9:/_-]{1,256}$/)) { throw new Error('Alias name must be between 1 and 256 characters in a-zA-Z0-9:/_-'); } + } else if (Tokenization.reverseString(aliasName).firstValue && Tokenization.reverseString(aliasName).firstToken === undefined) { + const valueInToken = Tokenization.reverseString(aliasName).firstValue; + + if (!valueInToken.startsWith(REQUIRED_ALIAS_PREFIX)) { + aliasName = REQUIRED_ALIAS_PREFIX + aliasName; + } + + if (valueInToken.toLocaleLowerCase().startsWith(DISALLOWED_PREFIX)) { + throw new Error(`Alias cannot start with ${DISALLOWED_PREFIX}: ${aliasName}`); + } + + if (!valueInToken.match(/^[a-zA-Z0-9:/_-]{1,256}$/)) { + throw new Error('Alias name must be between 1 and 256 characters in a-zA-Z0-9:/_-'); + } } super(scope, id, { diff --git a/packages/aws-cdk-lib/aws-kms/test/alias.test.ts b/packages/aws-cdk-lib/aws-kms/test/alias.test.ts index fe98fa788697b..fa7d2bb763bb6 100644 --- a/packages/aws-cdk-lib/aws-kms/test/alias.test.ts +++ b/packages/aws-cdk-lib/aws-kms/test/alias.test.ts @@ -1,8 +1,8 @@ +import { Construct } from 'constructs'; import { Template } from '../../assertions'; -import { ArnPrincipal, PolicyStatement } from '../../aws-iam'; import * as iam from '../../aws-iam'; -import { App, CfnOutput, Stack } from '../../core'; -import { Construct } from 'constructs'; +import { ArnPrincipal, PolicyStatement } from '../../aws-iam'; +import { App, Aws, CfnOutput, Stack } from '../../core'; import { Alias } from '../lib/alias'; import { IKey, Key } from '../lib/key'; @@ -263,3 +263,98 @@ test('grants generate mac to the alias target key', () => { }); }); +test('adds alias prefix if its token with valid string prefix', () => { + const app = new App(); + const stack = new Stack(app, 'my-stack'); + new Key(stack, 'Key', { + alias: `MyKey${Aws.ACCOUNT_ID}`, + }); + + Template.fromStack(stack).hasResourceProperties('AWS::KMS::Alias', { + AliasName: { + 'Fn::Join': [ + '', + [ + 'alias/MyKey', + { + Ref: 'AWS::AccountId', + }, + ], + ], + }, + TargetKeyId: { + 'Fn::GetAtt': [ + 'Key961B73FD', + 'Arn', + ], + }, + }); +}); + +test('does not add alias again if already set', () => { + const app = new App(); + const stack = new Stack(app, 'my-stack'); + new Key(stack, 'Key', { + alias: `alias/MyKey${Aws.ACCOUNT_ID}`, + }); + + Template.fromStack(stack).hasResourceProperties('AWS::KMS::Alias', { + AliasName: { + 'Fn::Join': [ + '', + [ + 'alias/MyKey', + { + Ref: 'AWS::AccountId', + }, + ], + ], + }, + TargetKeyId: { + 'Fn::GetAtt': [ + 'Key961B73FD', + 'Arn', + ], + }, + }); +}); + +test('throws error when alias contains illegal characters', () => { + const app = new App(); + const stack = new Stack(app, 'my-stack'); + + expect(() => { + new Key(stack, 'Key', { + alias: `MyK*y${Aws.ACCOUNT_ID}`, + }); + }).toThrowError(); +}); + +test('does not add alias if starts with token', () => { + const app = new App(); + const stack = new Stack(app, 'my-stack'); + new Key(stack, 'Key', { + alias: `${Aws.ACCOUNT_ID}MyKey`, + }); + + Template.fromStack(stack).hasResourceProperties('AWS::KMS::Alias', { + AliasName: { + 'Fn::Join': [ + '', + [ + { + Ref: 'AWS::AccountId', + }, + 'MyKey', + ], + ], + }, + TargetKeyId: { + 'Fn::GetAtt': [ + 'Key961B73FD', + 'Arn', + ], + }, + }); +}); + From 2ea3e455712e175a914fd9362ce26137a75f4fc7 Mon Sep 17 00:00:00 2001 From: Joshua Weber <57131123+daschaa@users.noreply.github.com> Date: Tue, 18 Apr 2023 15:45:21 +0200 Subject: [PATCH 2/7] feat(rds): Support SQL Server for RDS proxy (#25102) Closes #22164 [As stated in the issue the iam auth has a third option with the support for sql server.](https://github.com/aws/aws-cdk/issues/22164#issuecomment-1297767306) I did not add it in this pull request, because replacing the boolean property iamAuth with a string property would lead to breaking changes. We should open up another issue for this and fix this separately. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- .../aws-cdk-rds-proxy-sql-server.assets.json | 19 + ...aws-cdk-rds-proxy-sql-server.template.json | 780 ++++++++++ .../cdk.out | 1 + .../integ.json | 19 + .../manifest.json | 322 ++++ ...efaultTestDeployAssert14B31776.assets.json | 19 + ...aultTestDeployAssert14B31776.template.json | 36 + .../tree.json | 1321 +++++++++++++++++ .../aws-rds/test/integ.proxy-sql-server.ts | 52 + .../aws-rds/lib/instance-engine.ts | 1 + .../aws-rds/test/instance-engine.test.ts | 11 + 11 files changed, 2581 insertions(+) create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.proxy-sql-server.js.snapshot/aws-cdk-rds-proxy-sql-server.assets.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.proxy-sql-server.js.snapshot/aws-cdk-rds-proxy-sql-server.template.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.proxy-sql-server.js.snapshot/cdk.out create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.proxy-sql-server.js.snapshot/integ.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.proxy-sql-server.js.snapshot/manifest.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.proxy-sql-server.js.snapshot/proxysqlserverintegtestDefaultTestDeployAssert14B31776.assets.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.proxy-sql-server.js.snapshot/proxysqlserverintegtestDefaultTestDeployAssert14B31776.template.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.proxy-sql-server.js.snapshot/tree.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.proxy-sql-server.ts diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.proxy-sql-server.js.snapshot/aws-cdk-rds-proxy-sql-server.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.proxy-sql-server.js.snapshot/aws-cdk-rds-proxy-sql-server.assets.json new file mode 100644 index 0000000000000..952974a39e693 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.proxy-sql-server.js.snapshot/aws-cdk-rds-proxy-sql-server.assets.json @@ -0,0 +1,19 @@ +{ + "version": "31.0.0", + "files": { + "b4a5559af4ad6c38f2ee9f74b53b1b86efd673d82a598a085654e2c921d8edda": { + "source": { + "path": "aws-cdk-rds-proxy-sql-server.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "b4a5559af4ad6c38f2ee9f74b53b1b86efd673d82a598a085654e2c921d8edda.json", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + } + }, + "dockerImages": {} +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.proxy-sql-server.js.snapshot/aws-cdk-rds-proxy-sql-server.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.proxy-sql-server.js.snapshot/aws-cdk-rds-proxy-sql-server.template.json new file mode 100644 index 0000000000000..fadcbd5802572 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.proxy-sql-server.js.snapshot/aws-cdk-rds-proxy-sql-server.template.json @@ -0,0 +1,780 @@ +{ + "Resources": { + "vpcA2121C38": { + "Type": "AWS::EC2::VPC", + "Properties": { + "CidrBlock": "10.0.0.0/16", + "EnableDnsHostnames": true, + "EnableDnsSupport": true, + "InstanceTenancy": "default", + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-rds-proxy-sql-server/vpc" + } + ] + } + }, + "vpcPublicSubnet1Subnet2E65531E": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "VpcId": { + "Ref": "vpcA2121C38" + }, + "AvailabilityZone": { + "Fn::Select": [ + 0, + { + "Fn::GetAZs": "" + } + ] + }, + "CidrBlock": "10.0.0.0/18", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-cdk-rds-proxy-sql-server/vpc/PublicSubnet1" + } + ] + } + }, + "vpcPublicSubnet1RouteTable48A2DF9B": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "vpcA2121C38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-rds-proxy-sql-server/vpc/PublicSubnet1" + } + ] + } + }, + "vpcPublicSubnet1RouteTableAssociation5D3F4579": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "vpcPublicSubnet1RouteTable48A2DF9B" + }, + "SubnetId": { + "Ref": "vpcPublicSubnet1Subnet2E65531E" + } + } + }, + "vpcPublicSubnet1DefaultRoute10708846": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "vpcPublicSubnet1RouteTable48A2DF9B" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "vpcIGWE57CBDCA" + } + }, + "DependsOn": [ + "vpcVPCGW7984C166" + ] + }, + "vpcPublicSubnet1EIPDA49DCBE": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-rds-proxy-sql-server/vpc/PublicSubnet1" + } + ] + } + }, + "vpcPublicSubnet1NATGateway9C16659E": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "SubnetId": { + "Ref": "vpcPublicSubnet1Subnet2E65531E" + }, + "AllocationId": { + "Fn::GetAtt": [ + "vpcPublicSubnet1EIPDA49DCBE", + "AllocationId" + ] + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-rds-proxy-sql-server/vpc/PublicSubnet1" + } + ] + }, + "DependsOn": [ + "vpcPublicSubnet1DefaultRoute10708846", + "vpcPublicSubnet1RouteTableAssociation5D3F4579" + ] + }, + "vpcPublicSubnet2Subnet009B674F": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "VpcId": { + "Ref": "vpcA2121C38" + }, + "AvailabilityZone": { + "Fn::Select": [ + 1, + { + "Fn::GetAZs": "" + } + ] + }, + "CidrBlock": "10.0.64.0/18", + "MapPublicIpOnLaunch": true, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Public" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Public" + }, + { + "Key": "Name", + "Value": "aws-cdk-rds-proxy-sql-server/vpc/PublicSubnet2" + } + ] + } + }, + "vpcPublicSubnet2RouteTableEB40D4CB": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "vpcA2121C38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-rds-proxy-sql-server/vpc/PublicSubnet2" + } + ] + } + }, + "vpcPublicSubnet2RouteTableAssociation21F81B59": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "vpcPublicSubnet2RouteTableEB40D4CB" + }, + "SubnetId": { + "Ref": "vpcPublicSubnet2Subnet009B674F" + } + } + }, + "vpcPublicSubnet2DefaultRouteA1EC0F60": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "vpcPublicSubnet2RouteTableEB40D4CB" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "GatewayId": { + "Ref": "vpcIGWE57CBDCA" + } + }, + "DependsOn": [ + "vpcVPCGW7984C166" + ] + }, + "vpcPublicSubnet2EIP9B3743B1": { + "Type": "AWS::EC2::EIP", + "Properties": { + "Domain": "vpc", + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-rds-proxy-sql-server/vpc/PublicSubnet2" + } + ] + } + }, + "vpcPublicSubnet2NATGateway9B8AE11A": { + "Type": "AWS::EC2::NatGateway", + "Properties": { + "SubnetId": { + "Ref": "vpcPublicSubnet2Subnet009B674F" + }, + "AllocationId": { + "Fn::GetAtt": [ + "vpcPublicSubnet2EIP9B3743B1", + "AllocationId" + ] + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-rds-proxy-sql-server/vpc/PublicSubnet2" + } + ] + }, + "DependsOn": [ + "vpcPublicSubnet2DefaultRouteA1EC0F60", + "vpcPublicSubnet2RouteTableAssociation21F81B59" + ] + }, + "vpcPrivateSubnet1Subnet934893E8": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "VpcId": { + "Ref": "vpcA2121C38" + }, + "AvailabilityZone": { + "Fn::Select": [ + 0, + { + "Fn::GetAZs": "" + } + ] + }, + "CidrBlock": "10.0.128.0/18", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-cdk-rds-proxy-sql-server/vpc/PrivateSubnet1" + } + ] + } + }, + "vpcPrivateSubnet1RouteTableB41A48CC": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "vpcA2121C38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-rds-proxy-sql-server/vpc/PrivateSubnet1" + } + ] + } + }, + "vpcPrivateSubnet1RouteTableAssociation67945127": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "vpcPrivateSubnet1RouteTableB41A48CC" + }, + "SubnetId": { + "Ref": "vpcPrivateSubnet1Subnet934893E8" + } + } + }, + "vpcPrivateSubnet1DefaultRoute1AA8E2E5": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "vpcPrivateSubnet1RouteTableB41A48CC" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "vpcPublicSubnet1NATGateway9C16659E" + } + } + }, + "vpcPrivateSubnet2Subnet7031C2BA": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "VpcId": { + "Ref": "vpcA2121C38" + }, + "AvailabilityZone": { + "Fn::Select": [ + 1, + { + "Fn::GetAZs": "" + } + ] + }, + "CidrBlock": "10.0.192.0/18", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "Private" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Private" + }, + { + "Key": "Name", + "Value": "aws-cdk-rds-proxy-sql-server/vpc/PrivateSubnet2" + } + ] + } + }, + "vpcPrivateSubnet2RouteTable7280F23E": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "vpcA2121C38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-rds-proxy-sql-server/vpc/PrivateSubnet2" + } + ] + } + }, + "vpcPrivateSubnet2RouteTableAssociation007E94D3": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "vpcPrivateSubnet2RouteTable7280F23E" + }, + "SubnetId": { + "Ref": "vpcPrivateSubnet2Subnet7031C2BA" + } + } + }, + "vpcPrivateSubnet2DefaultRouteB0E07F99": { + "Type": "AWS::EC2::Route", + "Properties": { + "RouteTableId": { + "Ref": "vpcPrivateSubnet2RouteTable7280F23E" + }, + "DestinationCidrBlock": "0.0.0.0/0", + "NatGatewayId": { + "Ref": "vpcPublicSubnet2NATGateway9B8AE11A" + } + } + }, + "vpcIGWE57CBDCA": { + "Type": "AWS::EC2::InternetGateway", + "Properties": { + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-rds-proxy-sql-server/vpc" + } + ] + } + }, + "vpcVPCGW7984C166": { + "Type": "AWS::EC2::VPCGatewayAttachment", + "Properties": { + "VpcId": { + "Ref": "vpcA2121C38" + }, + "InternetGatewayId": { + "Ref": "vpcIGWE57CBDCA" + } + } + }, + "SqlServerDbInstanceSubnetGroupAE46487C": { + "Type": "AWS::RDS::DBSubnetGroup", + "Properties": { + "DBSubnetGroupDescription": "Subnet group for SqlServerDbInstance database", + "SubnetIds": [ + { + "Ref": "vpcPrivateSubnet1Subnet934893E8" + }, + { + "Ref": "vpcPrivateSubnet2Subnet7031C2BA" + } + ] + } + }, + "SqlServerDbInstanceSecurityGroupAE784A28": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "Security group for SqlServerDbInstance database", + "SecurityGroupEgress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow all outbound traffic by default", + "IpProtocol": "-1" + } + ], + "VpcId": { + "Ref": "vpcA2121C38" + } + } + }, + "SqlServerDbInstanceSecurityGroupfromawscdkrdsproxysqlserverDbProxyProxySecurityGroupEA4A8A53IndirectPortB7F9EE50": { + "Type": "AWS::EC2::SecurityGroupIngress", + "Properties": { + "IpProtocol": "tcp", + "Description": "Allow connections to the database Instance from the Proxy", + "FromPort": { + "Fn::GetAtt": [ + "SqlServerDbInstance8422C0F9", + "Endpoint.Port" + ] + }, + "GroupId": { + "Fn::GetAtt": [ + "SqlServerDbInstanceSecurityGroupAE784A28", + "GroupId" + ] + }, + "SourceSecurityGroupId": { + "Fn::GetAtt": [ + "DbProxyProxySecurityGroupCFB8B534", + "GroupId" + ] + }, + "ToPort": { + "Fn::GetAtt": [ + "SqlServerDbInstance8422C0F9", + "Endpoint.Port" + ] + } + } + }, + "SqlServerDbInstanceSecretAC239A57": { + "Type": "AWS::SecretsManager::Secret", + "Properties": { + "Description": { + "Fn::Join": [ + "", + [ + "Generated by the CDK for stack: ", + { + "Ref": "AWS::StackName" + } + ] + ] + }, + "GenerateSecretString": { + "ExcludeCharacters": "\"@/\\", + "GenerateStringKey": "password", + "PasswordLength": 30, + "SecretStringTemplate": "{\"username\":\"master\"}" + } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "SqlServerDbInstanceSecretAttachment87AE8779": { + "Type": "AWS::SecretsManager::SecretTargetAttachment", + "Properties": { + "SecretId": { + "Ref": "SqlServerDbInstanceSecretAC239A57" + }, + "TargetId": { + "Ref": "SqlServerDbInstance8422C0F9" + }, + "TargetType": "AWS::RDS::DBInstance" + } + }, + "SqlServerDbInstance8422C0F9": { + "Type": "AWS::RDS::DBInstance", + "Properties": { + "AllocatedStorage": "100", + "CopyTagsToSnapshot": true, + "DBInstanceClass": "db.t3.small", + "DBSubnetGroupName": { + "Ref": "SqlServerDbInstanceSubnetGroupAE46487C" + }, + "Engine": "sqlserver-ex", + "EngineVersion": "15.00", + "LicenseModel": "license-included", + "MasterUsername": { + "Fn::Join": [ + "", + [ + "{{resolve:secretsmanager:", + { + "Ref": "SqlServerDbInstanceSecretAC239A57" + }, + ":SecretString:username::}}" + ] + ] + }, + "MasterUserPassword": { + "Fn::Join": [ + "", + [ + "{{resolve:secretsmanager:", + { + "Ref": "SqlServerDbInstanceSecretAC239A57" + }, + ":SecretString:password::}}" + ] + ] + }, + "StorageType": "gp2", + "VPCSecurityGroups": [ + { + "Fn::GetAtt": [ + "SqlServerDbInstanceSecurityGroupAE784A28", + "GroupId" + ] + } + ] + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "DbProxyIAMRoleDB6E75F4": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "rds.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "DbProxyIAMRoleDefaultPolicy3AB2F318": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "secretsmanager:DescribeSecret", + "secretsmanager:GetSecretValue" + ], + "Effect": "Allow", + "Resource": { + "Ref": "SqlServerDbInstanceSecretAttachment87AE8779" + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "DbProxyIAMRoleDefaultPolicy3AB2F318", + "Roles": [ + { + "Ref": "DbProxyIAMRoleDB6E75F4" + } + ] + } + }, + "DbProxyProxySecurityGroupCFB8B534": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "SecurityGroup for Database Proxy", + "SecurityGroupEgress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow all outbound traffic by default", + "IpProtocol": "-1" + } + ], + "VpcId": { + "Ref": "vpcA2121C38" + } + } + }, + "DbProxy471ABCB4": { + "Type": "AWS::RDS::DBProxy", + "Properties": { + "Auth": [ + { + "AuthScheme": "SECRETS", + "IAMAuth": "REQUIRED", + "SecretArn": { + "Ref": "SqlServerDbInstanceSecretAttachment87AE8779" + } + } + ], + "DBProxyName": "awscdkrdsproxysqlserverDbProxy3F5C6270", + "EngineFamily": "SQLSERVER", + "RoleArn": { + "Fn::GetAtt": [ + "DbProxyIAMRoleDB6E75F4", + "Arn" + ] + }, + "VpcSubnetIds": [ + { + "Ref": "vpcPrivateSubnet1Subnet934893E8" + }, + { + "Ref": "vpcPrivateSubnet2Subnet7031C2BA" + } + ], + "RequireTLS": true, + "VpcSecurityGroupIds": [ + { + "Fn::GetAtt": [ + "DbProxyProxySecurityGroupCFB8B534", + "GroupId" + ] + } + ] + } + }, + "DbProxyProxyTargetGroupE3127B9C": { + "Type": "AWS::RDS::DBProxyTargetGroup", + "Properties": { + "DBProxyName": { + "Ref": "DbProxy471ABCB4" + }, + "TargetGroupName": "default", + "ConnectionPoolConfigurationInfo": { + "ConnectionBorrowTimeout": 30, + "MaxConnectionsPercent": 50 + }, + "DBInstanceIdentifiers": [ + { + "Ref": "SqlServerDbInstance8422C0F9" + } + ] + } + }, + "SqlProxyRole0DC4DDBC": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":root" + ] + ] + } + } + } + ], + "Version": "2012-10-17" + } + } + }, + "SqlProxyRoleDefaultPolicy225DB22D": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": "rds-db:connect", + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":rds-db:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":dbuser:", + { + "Fn::Select": [ + 6, + { + "Fn::Split": [ + ":", + { + "Fn::GetAtt": [ + "DbProxy471ABCB4", + "DBProxyArn" + ] + } + ] + } + ] + }, + "/master" + ] + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "SqlProxyRoleDefaultPolicy225DB22D", + "Roles": [ + { + "Ref": "SqlProxyRole0DC4DDBC" + } + ] + } + } + }, + "Parameters": { + "BootstrapVersion": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/cdk-bootstrap/hnb659fds/version", + "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]" + } + }, + "Rules": { + "CheckBootstrapVersion": { + "Assertions": [ + { + "Assert": { + "Fn::Not": [ + { + "Fn::Contains": [ + [ + "1", + "2", + "3", + "4", + "5" + ], + { + "Ref": "BootstrapVersion" + } + ] + } + ] + }, + "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI." + } + ] + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.proxy-sql-server.js.snapshot/cdk.out b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.proxy-sql-server.js.snapshot/cdk.out new file mode 100644 index 0000000000000..7925065efbcc4 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.proxy-sql-server.js.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"31.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.proxy-sql-server.js.snapshot/integ.json b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.proxy-sql-server.js.snapshot/integ.json new file mode 100644 index 0000000000000..b5bfe50e7c826 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.proxy-sql-server.js.snapshot/integ.json @@ -0,0 +1,19 @@ +{ + "version": "31.0.0", + "testCases": { + "proxy-sql-server-integ-test/DefaultTest": { + "stacks": [ + "aws-cdk-rds-proxy-sql-server" + ], + "cdkCommandOptions": { + "deploy": { + "args": { + "rollback": true + } + } + }, + "assertionStack": "proxy-sql-server-integ-test/DefaultTest/DeployAssert", + "assertionStackName": "proxysqlserverintegtestDefaultTestDeployAssert14B31776" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.proxy-sql-server.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.proxy-sql-server.js.snapshot/manifest.json new file mode 100644 index 0000000000000..0796916f5da00 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.proxy-sql-server.js.snapshot/manifest.json @@ -0,0 +1,322 @@ +{ + "version": "31.0.0", + "artifacts": { + "aws-cdk-rds-proxy-sql-server.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "aws-cdk-rds-proxy-sql-server.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "aws-cdk-rds-proxy-sql-server": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "aws-cdk-rds-proxy-sql-server.template.json", + "terminationProtection": false, + "validateOnSynth": false, + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", + "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/b4a5559af4ad6c38f2ee9f74b53b1b86efd673d82a598a085654e2c921d8edda.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "aws-cdk-rds-proxy-sql-server.assets" + ], + "lookupRole": { + "arn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-lookup-role-${AWS::AccountId}-${AWS::Region}", + "requiresBootstrapStackVersion": 8, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "dependencies": [ + "aws-cdk-rds-proxy-sql-server.assets" + ], + "metadata": { + "/aws-cdk-rds-proxy-sql-server/vpc/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "vpcA2121C38" + } + ], + "/aws-cdk-rds-proxy-sql-server/vpc/PublicSubnet1/Subnet": [ + { + "type": "aws:cdk:logicalId", + "data": "vpcPublicSubnet1Subnet2E65531E" + } + ], + "/aws-cdk-rds-proxy-sql-server/vpc/PublicSubnet1/RouteTable": [ + { + "type": "aws:cdk:logicalId", + "data": "vpcPublicSubnet1RouteTable48A2DF9B" + } + ], + "/aws-cdk-rds-proxy-sql-server/vpc/PublicSubnet1/RouteTableAssociation": [ + { + "type": "aws:cdk:logicalId", + "data": "vpcPublicSubnet1RouteTableAssociation5D3F4579" + } + ], + "/aws-cdk-rds-proxy-sql-server/vpc/PublicSubnet1/DefaultRoute": [ + { + "type": "aws:cdk:logicalId", + "data": "vpcPublicSubnet1DefaultRoute10708846" + } + ], + "/aws-cdk-rds-proxy-sql-server/vpc/PublicSubnet1/EIP": [ + { + "type": "aws:cdk:logicalId", + "data": "vpcPublicSubnet1EIPDA49DCBE" + } + ], + "/aws-cdk-rds-proxy-sql-server/vpc/PublicSubnet1/NATGateway": [ + { + "type": "aws:cdk:logicalId", + "data": "vpcPublicSubnet1NATGateway9C16659E" + } + ], + "/aws-cdk-rds-proxy-sql-server/vpc/PublicSubnet2/Subnet": [ + { + "type": "aws:cdk:logicalId", + "data": "vpcPublicSubnet2Subnet009B674F" + } + ], + "/aws-cdk-rds-proxy-sql-server/vpc/PublicSubnet2/RouteTable": [ + { + "type": "aws:cdk:logicalId", + "data": "vpcPublicSubnet2RouteTableEB40D4CB" + } + ], + "/aws-cdk-rds-proxy-sql-server/vpc/PublicSubnet2/RouteTableAssociation": [ + { + "type": "aws:cdk:logicalId", + "data": "vpcPublicSubnet2RouteTableAssociation21F81B59" + } + ], + "/aws-cdk-rds-proxy-sql-server/vpc/PublicSubnet2/DefaultRoute": [ + { + "type": "aws:cdk:logicalId", + "data": "vpcPublicSubnet2DefaultRouteA1EC0F60" + } + ], + "/aws-cdk-rds-proxy-sql-server/vpc/PublicSubnet2/EIP": [ + { + "type": "aws:cdk:logicalId", + "data": "vpcPublicSubnet2EIP9B3743B1" + } + ], + "/aws-cdk-rds-proxy-sql-server/vpc/PublicSubnet2/NATGateway": [ + { + "type": "aws:cdk:logicalId", + "data": "vpcPublicSubnet2NATGateway9B8AE11A" + } + ], + "/aws-cdk-rds-proxy-sql-server/vpc/PrivateSubnet1/Subnet": [ + { + "type": "aws:cdk:logicalId", + "data": "vpcPrivateSubnet1Subnet934893E8" + } + ], + "/aws-cdk-rds-proxy-sql-server/vpc/PrivateSubnet1/RouteTable": [ + { + "type": "aws:cdk:logicalId", + "data": "vpcPrivateSubnet1RouteTableB41A48CC" + } + ], + "/aws-cdk-rds-proxy-sql-server/vpc/PrivateSubnet1/RouteTableAssociation": [ + { + "type": "aws:cdk:logicalId", + "data": "vpcPrivateSubnet1RouteTableAssociation67945127" + } + ], + "/aws-cdk-rds-proxy-sql-server/vpc/PrivateSubnet1/DefaultRoute": [ + { + "type": "aws:cdk:logicalId", + "data": "vpcPrivateSubnet1DefaultRoute1AA8E2E5" + } + ], + "/aws-cdk-rds-proxy-sql-server/vpc/PrivateSubnet2/Subnet": [ + { + "type": "aws:cdk:logicalId", + "data": "vpcPrivateSubnet2Subnet7031C2BA" + } + ], + "/aws-cdk-rds-proxy-sql-server/vpc/PrivateSubnet2/RouteTable": [ + { + "type": "aws:cdk:logicalId", + "data": "vpcPrivateSubnet2RouteTable7280F23E" + } + ], + "/aws-cdk-rds-proxy-sql-server/vpc/PrivateSubnet2/RouteTableAssociation": [ + { + "type": "aws:cdk:logicalId", + "data": "vpcPrivateSubnet2RouteTableAssociation007E94D3" + } + ], + "/aws-cdk-rds-proxy-sql-server/vpc/PrivateSubnet2/DefaultRoute": [ + { + "type": "aws:cdk:logicalId", + "data": "vpcPrivateSubnet2DefaultRouteB0E07F99" + } + ], + "/aws-cdk-rds-proxy-sql-server/vpc/IGW": [ + { + "type": "aws:cdk:logicalId", + "data": "vpcIGWE57CBDCA" + } + ], + "/aws-cdk-rds-proxy-sql-server/vpc/VPCGW": [ + { + "type": "aws:cdk:logicalId", + "data": "vpcVPCGW7984C166" + } + ], + "/aws-cdk-rds-proxy-sql-server/SqlServerDbInstance/SubnetGroup/Default": [ + { + "type": "aws:cdk:logicalId", + "data": "SqlServerDbInstanceSubnetGroupAE46487C" + } + ], + "/aws-cdk-rds-proxy-sql-server/SqlServerDbInstance/SecurityGroup/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "SqlServerDbInstanceSecurityGroupAE784A28" + } + ], + "/aws-cdk-rds-proxy-sql-server/SqlServerDbInstance/SecurityGroup/from awscdkrdsproxysqlserverDbProxyProxySecurityGroupEA4A8A53:{IndirectPort}": [ + { + "type": "aws:cdk:logicalId", + "data": "SqlServerDbInstanceSecurityGroupfromawscdkrdsproxysqlserverDbProxyProxySecurityGroupEA4A8A53IndirectPortB7F9EE50" + } + ], + "/aws-cdk-rds-proxy-sql-server/SqlServerDbInstance/Secret/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "SqlServerDbInstanceSecretAC239A57" + } + ], + "/aws-cdk-rds-proxy-sql-server/SqlServerDbInstance/Secret/Attachment/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "SqlServerDbInstanceSecretAttachment87AE8779" + } + ], + "/aws-cdk-rds-proxy-sql-server/SqlServerDbInstance/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "SqlServerDbInstance8422C0F9" + } + ], + "/aws-cdk-rds-proxy-sql-server/DbProxy/IAMRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "DbProxyIAMRoleDB6E75F4" + } + ], + "/aws-cdk-rds-proxy-sql-server/DbProxy/IAMRole/DefaultPolicy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "DbProxyIAMRoleDefaultPolicy3AB2F318" + } + ], + "/aws-cdk-rds-proxy-sql-server/DbProxy/ProxySecurityGroup/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "DbProxyProxySecurityGroupCFB8B534" + } + ], + "/aws-cdk-rds-proxy-sql-server/DbProxy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "DbProxy471ABCB4" + } + ], + "/aws-cdk-rds-proxy-sql-server/DbProxy/ProxyTargetGroup": [ + { + "type": "aws:cdk:logicalId", + "data": "DbProxyProxyTargetGroupE3127B9C" + } + ], + "/aws-cdk-rds-proxy-sql-server/SqlProxyRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "SqlProxyRole0DC4DDBC" + } + ], + "/aws-cdk-rds-proxy-sql-server/SqlProxyRole/DefaultPolicy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "SqlProxyRoleDefaultPolicy225DB22D" + } + ], + "/aws-cdk-rds-proxy-sql-server/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/aws-cdk-rds-proxy-sql-server/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "aws-cdk-rds-proxy-sql-server" + }, + "proxysqlserverintegtestDefaultTestDeployAssert14B31776.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "proxysqlserverintegtestDefaultTestDeployAssert14B31776.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "proxysqlserverintegtestDefaultTestDeployAssert14B31776": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "proxysqlserverintegtestDefaultTestDeployAssert14B31776.template.json", + "validateOnSynth": false, + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", + "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "proxysqlserverintegtestDefaultTestDeployAssert14B31776.assets" + ], + "lookupRole": { + "arn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-lookup-role-${AWS::AccountId}-${AWS::Region}", + "requiresBootstrapStackVersion": 8, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "dependencies": [ + "proxysqlserverintegtestDefaultTestDeployAssert14B31776.assets" + ], + "metadata": { + "/proxy-sql-server-integ-test/DefaultTest/DeployAssert/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/proxy-sql-server-integ-test/DefaultTest/DeployAssert/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "proxy-sql-server-integ-test/DefaultTest/DeployAssert" + }, + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + } + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.proxy-sql-server.js.snapshot/proxysqlserverintegtestDefaultTestDeployAssert14B31776.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.proxy-sql-server.js.snapshot/proxysqlserverintegtestDefaultTestDeployAssert14B31776.assets.json new file mode 100644 index 0000000000000..8e074aad8d36a --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.proxy-sql-server.js.snapshot/proxysqlserverintegtestDefaultTestDeployAssert14B31776.assets.json @@ -0,0 +1,19 @@ +{ + "version": "31.0.0", + "files": { + "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { + "source": { + "path": "proxysqlserverintegtestDefaultTestDeployAssert14B31776.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22.json", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + } + }, + "dockerImages": {} +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.proxy-sql-server.js.snapshot/proxysqlserverintegtestDefaultTestDeployAssert14B31776.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.proxy-sql-server.js.snapshot/proxysqlserverintegtestDefaultTestDeployAssert14B31776.template.json new file mode 100644 index 0000000000000..ad9d0fb73d1dd --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.proxy-sql-server.js.snapshot/proxysqlserverintegtestDefaultTestDeployAssert14B31776.template.json @@ -0,0 +1,36 @@ +{ + "Parameters": { + "BootstrapVersion": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/cdk-bootstrap/hnb659fds/version", + "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]" + } + }, + "Rules": { + "CheckBootstrapVersion": { + "Assertions": [ + { + "Assert": { + "Fn::Not": [ + { + "Fn::Contains": [ + [ + "1", + "2", + "3", + "4", + "5" + ], + { + "Ref": "BootstrapVersion" + } + ] + } + ] + }, + "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI." + } + ] + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.proxy-sql-server.js.snapshot/tree.json b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.proxy-sql-server.js.snapshot/tree.json new file mode 100644 index 0000000000000..a46ce6f7b23c6 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.proxy-sql-server.js.snapshot/tree.json @@ -0,0 +1,1321 @@ +{ + "version": "tree-0.1", + "tree": { + "id": "App", + "path": "", + "children": { + "aws-cdk-rds-proxy-sql-server": { + "id": "aws-cdk-rds-proxy-sql-server", + "path": "aws-cdk-rds-proxy-sql-server", + "children": { + "vpc": { + "id": "vpc", + "path": "aws-cdk-rds-proxy-sql-server/vpc", + "children": { + "Resource": { + "id": "Resource", + "path": "aws-cdk-rds-proxy-sql-server/vpc/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::VPC", + "aws:cdk:cloudformation:props": { + "cidrBlock": "10.0.0.0/16", + "enableDnsHostnames": true, + "enableDnsSupport": true, + "instanceTenancy": "default", + "tags": [ + { + "key": "Name", + "value": "aws-cdk-rds-proxy-sql-server/vpc" + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnVPC", + "version": "0.0.0" + } + }, + "PublicSubnet1": { + "id": "PublicSubnet1", + "path": "aws-cdk-rds-proxy-sql-server/vpc/PublicSubnet1", + "children": { + "Subnet": { + "id": "Subnet", + "path": "aws-cdk-rds-proxy-sql-server/vpc/PublicSubnet1/Subnet", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", + "aws:cdk:cloudformation:props": { + "vpcId": { + "Ref": "vpcA2121C38" + }, + "availabilityZone": { + "Fn::Select": [ + 0, + { + "Fn::GetAZs": "" + } + ] + }, + "cidrBlock": "10.0.0.0/18", + "mapPublicIpOnLaunch": true, + "tags": [ + { + "key": "aws-cdk:subnet-name", + "value": "Public" + }, + { + "key": "aws-cdk:subnet-type", + "value": "Public" + }, + { + "key": "Name", + "value": "aws-cdk-rds-proxy-sql-server/vpc/PublicSubnet1" + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnSubnet", + "version": "0.0.0" + } + }, + "Acl": { + "id": "Acl", + "path": "aws-cdk-rds-proxy-sql-server/vpc/PublicSubnet1/Acl", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" + } + }, + "RouteTable": { + "id": "RouteTable", + "path": "aws-cdk-rds-proxy-sql-server/vpc/PublicSubnet1/RouteTable", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", + "aws:cdk:cloudformation:props": { + "vpcId": { + "Ref": "vpcA2121C38" + }, + "tags": [ + { + "key": "Name", + "value": "aws-cdk-rds-proxy-sql-server/vpc/PublicSubnet1" + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnRouteTable", + "version": "0.0.0" + } + }, + "RouteTableAssociation": { + "id": "RouteTableAssociation", + "path": "aws-cdk-rds-proxy-sql-server/vpc/PublicSubnet1/RouteTableAssociation", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::SubnetRouteTableAssociation", + "aws:cdk:cloudformation:props": { + "routeTableId": { + "Ref": "vpcPublicSubnet1RouteTable48A2DF9B" + }, + "subnetId": { + "Ref": "vpcPublicSubnet1Subnet2E65531E" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnSubnetRouteTableAssociation", + "version": "0.0.0" + } + }, + "DefaultRoute": { + "id": "DefaultRoute", + "path": "aws-cdk-rds-proxy-sql-server/vpc/PublicSubnet1/DefaultRoute", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::Route", + "aws:cdk:cloudformation:props": { + "routeTableId": { + "Ref": "vpcPublicSubnet1RouteTable48A2DF9B" + }, + "destinationCidrBlock": "0.0.0.0/0", + "gatewayId": { + "Ref": "vpcIGWE57CBDCA" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnRoute", + "version": "0.0.0" + } + }, + "EIP": { + "id": "EIP", + "path": "aws-cdk-rds-proxy-sql-server/vpc/PublicSubnet1/EIP", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::EIP", + "aws:cdk:cloudformation:props": { + "domain": "vpc", + "tags": [ + { + "key": "Name", + "value": "aws-cdk-rds-proxy-sql-server/vpc/PublicSubnet1" + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnEIP", + "version": "0.0.0" + } + }, + "NATGateway": { + "id": "NATGateway", + "path": "aws-cdk-rds-proxy-sql-server/vpc/PublicSubnet1/NATGateway", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::NatGateway", + "aws:cdk:cloudformation:props": { + "subnetId": { + "Ref": "vpcPublicSubnet1Subnet2E65531E" + }, + "allocationId": { + "Fn::GetAtt": [ + "vpcPublicSubnet1EIPDA49DCBE", + "AllocationId" + ] + }, + "tags": [ + { + "key": "Name", + "value": "aws-cdk-rds-proxy-sql-server/vpc/PublicSubnet1" + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnNatGateway", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.PublicSubnet", + "version": "0.0.0" + } + }, + "PublicSubnet2": { + "id": "PublicSubnet2", + "path": "aws-cdk-rds-proxy-sql-server/vpc/PublicSubnet2", + "children": { + "Subnet": { + "id": "Subnet", + "path": "aws-cdk-rds-proxy-sql-server/vpc/PublicSubnet2/Subnet", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", + "aws:cdk:cloudformation:props": { + "vpcId": { + "Ref": "vpcA2121C38" + }, + "availabilityZone": { + "Fn::Select": [ + 1, + { + "Fn::GetAZs": "" + } + ] + }, + "cidrBlock": "10.0.64.0/18", + "mapPublicIpOnLaunch": true, + "tags": [ + { + "key": "aws-cdk:subnet-name", + "value": "Public" + }, + { + "key": "aws-cdk:subnet-type", + "value": "Public" + }, + { + "key": "Name", + "value": "aws-cdk-rds-proxy-sql-server/vpc/PublicSubnet2" + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnSubnet", + "version": "0.0.0" + } + }, + "Acl": { + "id": "Acl", + "path": "aws-cdk-rds-proxy-sql-server/vpc/PublicSubnet2/Acl", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" + } + }, + "RouteTable": { + "id": "RouteTable", + "path": "aws-cdk-rds-proxy-sql-server/vpc/PublicSubnet2/RouteTable", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", + "aws:cdk:cloudformation:props": { + "vpcId": { + "Ref": "vpcA2121C38" + }, + "tags": [ + { + "key": "Name", + "value": "aws-cdk-rds-proxy-sql-server/vpc/PublicSubnet2" + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnRouteTable", + "version": "0.0.0" + } + }, + "RouteTableAssociation": { + "id": "RouteTableAssociation", + "path": "aws-cdk-rds-proxy-sql-server/vpc/PublicSubnet2/RouteTableAssociation", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::SubnetRouteTableAssociation", + "aws:cdk:cloudformation:props": { + "routeTableId": { + "Ref": "vpcPublicSubnet2RouteTableEB40D4CB" + }, + "subnetId": { + "Ref": "vpcPublicSubnet2Subnet009B674F" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnSubnetRouteTableAssociation", + "version": "0.0.0" + } + }, + "DefaultRoute": { + "id": "DefaultRoute", + "path": "aws-cdk-rds-proxy-sql-server/vpc/PublicSubnet2/DefaultRoute", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::Route", + "aws:cdk:cloudformation:props": { + "routeTableId": { + "Ref": "vpcPublicSubnet2RouteTableEB40D4CB" + }, + "destinationCidrBlock": "0.0.0.0/0", + "gatewayId": { + "Ref": "vpcIGWE57CBDCA" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnRoute", + "version": "0.0.0" + } + }, + "EIP": { + "id": "EIP", + "path": "aws-cdk-rds-proxy-sql-server/vpc/PublicSubnet2/EIP", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::EIP", + "aws:cdk:cloudformation:props": { + "domain": "vpc", + "tags": [ + { + "key": "Name", + "value": "aws-cdk-rds-proxy-sql-server/vpc/PublicSubnet2" + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnEIP", + "version": "0.0.0" + } + }, + "NATGateway": { + "id": "NATGateway", + "path": "aws-cdk-rds-proxy-sql-server/vpc/PublicSubnet2/NATGateway", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::NatGateway", + "aws:cdk:cloudformation:props": { + "subnetId": { + "Ref": "vpcPublicSubnet2Subnet009B674F" + }, + "allocationId": { + "Fn::GetAtt": [ + "vpcPublicSubnet2EIP9B3743B1", + "AllocationId" + ] + }, + "tags": [ + { + "key": "Name", + "value": "aws-cdk-rds-proxy-sql-server/vpc/PublicSubnet2" + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnNatGateway", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.PublicSubnet", + "version": "0.0.0" + } + }, + "PrivateSubnet1": { + "id": "PrivateSubnet1", + "path": "aws-cdk-rds-proxy-sql-server/vpc/PrivateSubnet1", + "children": { + "Subnet": { + "id": "Subnet", + "path": "aws-cdk-rds-proxy-sql-server/vpc/PrivateSubnet1/Subnet", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", + "aws:cdk:cloudformation:props": { + "vpcId": { + "Ref": "vpcA2121C38" + }, + "availabilityZone": { + "Fn::Select": [ + 0, + { + "Fn::GetAZs": "" + } + ] + }, + "cidrBlock": "10.0.128.0/18", + "mapPublicIpOnLaunch": false, + "tags": [ + { + "key": "aws-cdk:subnet-name", + "value": "Private" + }, + { + "key": "aws-cdk:subnet-type", + "value": "Private" + }, + { + "key": "Name", + "value": "aws-cdk-rds-proxy-sql-server/vpc/PrivateSubnet1" + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnSubnet", + "version": "0.0.0" + } + }, + "Acl": { + "id": "Acl", + "path": "aws-cdk-rds-proxy-sql-server/vpc/PrivateSubnet1/Acl", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" + } + }, + "RouteTable": { + "id": "RouteTable", + "path": "aws-cdk-rds-proxy-sql-server/vpc/PrivateSubnet1/RouteTable", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", + "aws:cdk:cloudformation:props": { + "vpcId": { + "Ref": "vpcA2121C38" + }, + "tags": [ + { + "key": "Name", + "value": "aws-cdk-rds-proxy-sql-server/vpc/PrivateSubnet1" + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnRouteTable", + "version": "0.0.0" + } + }, + "RouteTableAssociation": { + "id": "RouteTableAssociation", + "path": "aws-cdk-rds-proxy-sql-server/vpc/PrivateSubnet1/RouteTableAssociation", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::SubnetRouteTableAssociation", + "aws:cdk:cloudformation:props": { + "routeTableId": { + "Ref": "vpcPrivateSubnet1RouteTableB41A48CC" + }, + "subnetId": { + "Ref": "vpcPrivateSubnet1Subnet934893E8" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnSubnetRouteTableAssociation", + "version": "0.0.0" + } + }, + "DefaultRoute": { + "id": "DefaultRoute", + "path": "aws-cdk-rds-proxy-sql-server/vpc/PrivateSubnet1/DefaultRoute", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::Route", + "aws:cdk:cloudformation:props": { + "routeTableId": { + "Ref": "vpcPrivateSubnet1RouteTableB41A48CC" + }, + "destinationCidrBlock": "0.0.0.0/0", + "natGatewayId": { + "Ref": "vpcPublicSubnet1NATGateway9C16659E" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnRoute", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.PrivateSubnet", + "version": "0.0.0" + } + }, + "PrivateSubnet2": { + "id": "PrivateSubnet2", + "path": "aws-cdk-rds-proxy-sql-server/vpc/PrivateSubnet2", + "children": { + "Subnet": { + "id": "Subnet", + "path": "aws-cdk-rds-proxy-sql-server/vpc/PrivateSubnet2/Subnet", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", + "aws:cdk:cloudformation:props": { + "vpcId": { + "Ref": "vpcA2121C38" + }, + "availabilityZone": { + "Fn::Select": [ + 1, + { + "Fn::GetAZs": "" + } + ] + }, + "cidrBlock": "10.0.192.0/18", + "mapPublicIpOnLaunch": false, + "tags": [ + { + "key": "aws-cdk:subnet-name", + "value": "Private" + }, + { + "key": "aws-cdk:subnet-type", + "value": "Private" + }, + { + "key": "Name", + "value": "aws-cdk-rds-proxy-sql-server/vpc/PrivateSubnet2" + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnSubnet", + "version": "0.0.0" + } + }, + "Acl": { + "id": "Acl", + "path": "aws-cdk-rds-proxy-sql-server/vpc/PrivateSubnet2/Acl", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" + } + }, + "RouteTable": { + "id": "RouteTable", + "path": "aws-cdk-rds-proxy-sql-server/vpc/PrivateSubnet2/RouteTable", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", + "aws:cdk:cloudformation:props": { + "vpcId": { + "Ref": "vpcA2121C38" + }, + "tags": [ + { + "key": "Name", + "value": "aws-cdk-rds-proxy-sql-server/vpc/PrivateSubnet2" + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnRouteTable", + "version": "0.0.0" + } + }, + "RouteTableAssociation": { + "id": "RouteTableAssociation", + "path": "aws-cdk-rds-proxy-sql-server/vpc/PrivateSubnet2/RouteTableAssociation", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::SubnetRouteTableAssociation", + "aws:cdk:cloudformation:props": { + "routeTableId": { + "Ref": "vpcPrivateSubnet2RouteTable7280F23E" + }, + "subnetId": { + "Ref": "vpcPrivateSubnet2Subnet7031C2BA" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnSubnetRouteTableAssociation", + "version": "0.0.0" + } + }, + "DefaultRoute": { + "id": "DefaultRoute", + "path": "aws-cdk-rds-proxy-sql-server/vpc/PrivateSubnet2/DefaultRoute", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::Route", + "aws:cdk:cloudformation:props": { + "routeTableId": { + "Ref": "vpcPrivateSubnet2RouteTable7280F23E" + }, + "destinationCidrBlock": "0.0.0.0/0", + "natGatewayId": { + "Ref": "vpcPublicSubnet2NATGateway9B8AE11A" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnRoute", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.PrivateSubnet", + "version": "0.0.0" + } + }, + "IGW": { + "id": "IGW", + "path": "aws-cdk-rds-proxy-sql-server/vpc/IGW", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::InternetGateway", + "aws:cdk:cloudformation:props": { + "tags": [ + { + "key": "Name", + "value": "aws-cdk-rds-proxy-sql-server/vpc" + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnInternetGateway", + "version": "0.0.0" + } + }, + "VPCGW": { + "id": "VPCGW", + "path": "aws-cdk-rds-proxy-sql-server/vpc/VPCGW", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::VPCGatewayAttachment", + "aws:cdk:cloudformation:props": { + "vpcId": { + "Ref": "vpcA2121C38" + }, + "internetGatewayId": { + "Ref": "vpcIGWE57CBDCA" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnVPCGatewayAttachment", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.Vpc", + "version": "0.0.0" + } + }, + "SqlServerDbInstance": { + "id": "SqlServerDbInstance", + "path": "aws-cdk-rds-proxy-sql-server/SqlServerDbInstance", + "children": { + "SubnetGroup": { + "id": "SubnetGroup", + "path": "aws-cdk-rds-proxy-sql-server/SqlServerDbInstance/SubnetGroup", + "children": { + "Default": { + "id": "Default", + "path": "aws-cdk-rds-proxy-sql-server/SqlServerDbInstance/SubnetGroup/Default", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::RDS::DBSubnetGroup", + "aws:cdk:cloudformation:props": { + "dbSubnetGroupDescription": "Subnet group for SqlServerDbInstance database", + "subnetIds": [ + { + "Ref": "vpcPrivateSubnet1Subnet934893E8" + }, + { + "Ref": "vpcPrivateSubnet2Subnet7031C2BA" + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_rds.CfnDBSubnetGroup", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_rds.SubnetGroup", + "version": "0.0.0" + } + }, + "SecurityGroup": { + "id": "SecurityGroup", + "path": "aws-cdk-rds-proxy-sql-server/SqlServerDbInstance/SecurityGroup", + "children": { + "Resource": { + "id": "Resource", + "path": "aws-cdk-rds-proxy-sql-server/SqlServerDbInstance/SecurityGroup/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::SecurityGroup", + "aws:cdk:cloudformation:props": { + "groupDescription": "Security group for SqlServerDbInstance database", + "securityGroupEgress": [ + { + "cidrIp": "0.0.0.0/0", + "description": "Allow all outbound traffic by default", + "ipProtocol": "-1" + } + ], + "vpcId": { + "Ref": "vpcA2121C38" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnSecurityGroup", + "version": "0.0.0" + } + }, + "from awscdkrdsproxysqlserverDbProxyProxySecurityGroupEA4A8A53:{IndirectPort}": { + "id": "from awscdkrdsproxysqlserverDbProxyProxySecurityGroupEA4A8A53:{IndirectPort}", + "path": "aws-cdk-rds-proxy-sql-server/SqlServerDbInstance/SecurityGroup/from awscdkrdsproxysqlserverDbProxyProxySecurityGroupEA4A8A53:{IndirectPort}", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::SecurityGroupIngress", + "aws:cdk:cloudformation:props": { + "ipProtocol": "tcp", + "description": "Allow connections to the database Instance from the Proxy", + "fromPort": { + "Fn::GetAtt": [ + "SqlServerDbInstance8422C0F9", + "Endpoint.Port" + ] + }, + "groupId": { + "Fn::GetAtt": [ + "SqlServerDbInstanceSecurityGroupAE784A28", + "GroupId" + ] + }, + "sourceSecurityGroupId": { + "Fn::GetAtt": [ + "DbProxyProxySecurityGroupCFB8B534", + "GroupId" + ] + }, + "toPort": { + "Fn::GetAtt": [ + "SqlServerDbInstance8422C0F9", + "Endpoint.Port" + ] + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnSecurityGroupIngress", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.SecurityGroup", + "version": "0.0.0" + } + }, + "Secret": { + "id": "Secret", + "path": "aws-cdk-rds-proxy-sql-server/SqlServerDbInstance/Secret", + "children": { + "Resource": { + "id": "Resource", + "path": "aws-cdk-rds-proxy-sql-server/SqlServerDbInstance/Secret/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::SecretsManager::Secret", + "aws:cdk:cloudformation:props": { + "description": { + "Fn::Join": [ + "", + [ + "Generated by the CDK for stack: ", + { + "Ref": "AWS::StackName" + } + ] + ] + }, + "generateSecretString": { + "passwordLength": 30, + "secretStringTemplate": "{\"username\":\"master\"}", + "generateStringKey": "password", + "excludeCharacters": "\"@/\\" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_secretsmanager.CfnSecret", + "version": "0.0.0" + } + }, + "Attachment": { + "id": "Attachment", + "path": "aws-cdk-rds-proxy-sql-server/SqlServerDbInstance/Secret/Attachment", + "children": { + "Resource": { + "id": "Resource", + "path": "aws-cdk-rds-proxy-sql-server/SqlServerDbInstance/Secret/Attachment/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::SecretsManager::SecretTargetAttachment", + "aws:cdk:cloudformation:props": { + "secretId": { + "Ref": "SqlServerDbInstanceSecretAC239A57" + }, + "targetId": { + "Ref": "SqlServerDbInstance8422C0F9" + }, + "targetType": "AWS::RDS::DBInstance" + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_secretsmanager.CfnSecretTargetAttachment", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_secretsmanager.SecretTargetAttachment", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_rds.DatabaseSecret", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "aws-cdk-rds-proxy-sql-server/SqlServerDbInstance/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::RDS::DBInstance", + "aws:cdk:cloudformation:props": { + "allocatedStorage": "100", + "copyTagsToSnapshot": true, + "dbInstanceClass": "db.t3.small", + "dbSubnetGroupName": { + "Ref": "SqlServerDbInstanceSubnetGroupAE46487C" + }, + "engine": "sqlserver-ex", + "engineVersion": "15.00", + "licenseModel": "license-included", + "masterUsername": { + "Fn::Join": [ + "", + [ + "{{resolve:secretsmanager:", + { + "Ref": "SqlServerDbInstanceSecretAC239A57" + }, + ":SecretString:username::}}" + ] + ] + }, + "masterUserPassword": { + "Fn::Join": [ + "", + [ + "{{resolve:secretsmanager:", + { + "Ref": "SqlServerDbInstanceSecretAC239A57" + }, + ":SecretString:password::}}" + ] + ] + }, + "storageType": "gp2", + "vpcSecurityGroups": [ + { + "Fn::GetAtt": [ + "SqlServerDbInstanceSecurityGroupAE784A28", + "GroupId" + ] + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_rds.CfnDBInstance", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_rds.DatabaseInstance", + "version": "0.0.0" + } + }, + "DbProxy": { + "id": "DbProxy", + "path": "aws-cdk-rds-proxy-sql-server/DbProxy", + "children": { + "IAMRole": { + "id": "IAMRole", + "path": "aws-cdk-rds-proxy-sql-server/DbProxy/IAMRole", + "children": { + "ImportIAMRole": { + "id": "ImportIAMRole", + "path": "aws-cdk-rds-proxy-sql-server/DbProxy/IAMRole/ImportIAMRole", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "aws-cdk-rds-proxy-sql-server/DbProxy/IAMRole/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Role", + "aws:cdk:cloudformation:props": { + "assumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "rds.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.CfnRole", + "version": "0.0.0" + } + }, + "DefaultPolicy": { + "id": "DefaultPolicy", + "path": "aws-cdk-rds-proxy-sql-server/DbProxy/IAMRole/DefaultPolicy", + "children": { + "Resource": { + "id": "Resource", + "path": "aws-cdk-rds-proxy-sql-server/DbProxy/IAMRole/DefaultPolicy/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Policy", + "aws:cdk:cloudformation:props": { + "policyDocument": { + "Statement": [ + { + "Action": [ + "secretsmanager:DescribeSecret", + "secretsmanager:GetSecretValue" + ], + "Effect": "Allow", + "Resource": { + "Ref": "SqlServerDbInstanceSecretAttachment87AE8779" + } + } + ], + "Version": "2012-10-17" + }, + "policyName": "DbProxyIAMRoleDefaultPolicy3AB2F318", + "roles": [ + { + "Ref": "DbProxyIAMRoleDB6E75F4" + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.CfnPolicy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.Policy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.Role", + "version": "0.0.0" + } + }, + "ProxySecurityGroup": { + "id": "ProxySecurityGroup", + "path": "aws-cdk-rds-proxy-sql-server/DbProxy/ProxySecurityGroup", + "children": { + "Resource": { + "id": "Resource", + "path": "aws-cdk-rds-proxy-sql-server/DbProxy/ProxySecurityGroup/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::SecurityGroup", + "aws:cdk:cloudformation:props": { + "groupDescription": "SecurityGroup for Database Proxy", + "securityGroupEgress": [ + { + "cidrIp": "0.0.0.0/0", + "description": "Allow all outbound traffic by default", + "ipProtocol": "-1" + } + ], + "vpcId": { + "Ref": "vpcA2121C38" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.CfnSecurityGroup", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_ec2.SecurityGroup", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "aws-cdk-rds-proxy-sql-server/DbProxy/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::RDS::DBProxy", + "aws:cdk:cloudformation:props": { + "auth": [ + { + "authScheme": "SECRETS", + "iamAuth": "REQUIRED", + "secretArn": { + "Ref": "SqlServerDbInstanceSecretAttachment87AE8779" + } + } + ], + "dbProxyName": "awscdkrdsproxysqlserverDbProxy3F5C6270", + "engineFamily": "SQLSERVER", + "roleArn": { + "Fn::GetAtt": [ + "DbProxyIAMRoleDB6E75F4", + "Arn" + ] + }, + "vpcSubnetIds": [ + { + "Ref": "vpcPrivateSubnet1Subnet934893E8" + }, + { + "Ref": "vpcPrivateSubnet2Subnet7031C2BA" + } + ], + "requireTls": true, + "vpcSecurityGroupIds": [ + { + "Fn::GetAtt": [ + "DbProxyProxySecurityGroupCFB8B534", + "GroupId" + ] + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_rds.CfnDBProxy", + "version": "0.0.0" + } + }, + "ProxyTargetGroup": { + "id": "ProxyTargetGroup", + "path": "aws-cdk-rds-proxy-sql-server/DbProxy/ProxyTargetGroup", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::RDS::DBProxyTargetGroup", + "aws:cdk:cloudformation:props": { + "dbProxyName": { + "Ref": "DbProxy471ABCB4" + }, + "targetGroupName": "default", + "connectionPoolConfigurationInfo": { + "connectionBorrowTimeout": 30, + "maxConnectionsPercent": 50 + }, + "dbInstanceIdentifiers": [ + { + "Ref": "SqlServerDbInstance8422C0F9" + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_rds.CfnDBProxyTargetGroup", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_rds.DatabaseProxy", + "version": "0.0.0" + } + }, + "SqlProxyRole": { + "id": "SqlProxyRole", + "path": "aws-cdk-rds-proxy-sql-server/SqlProxyRole", + "children": { + "ImportSqlProxyRole": { + "id": "ImportSqlProxyRole", + "path": "aws-cdk-rds-proxy-sql-server/SqlProxyRole/ImportSqlProxyRole", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "aws-cdk-rds-proxy-sql-server/SqlProxyRole/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Role", + "aws:cdk:cloudformation:props": { + "assumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":root" + ] + ] + } + } + } + ], + "Version": "2012-10-17" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.CfnRole", + "version": "0.0.0" + } + }, + "DefaultPolicy": { + "id": "DefaultPolicy", + "path": "aws-cdk-rds-proxy-sql-server/SqlProxyRole/DefaultPolicy", + "children": { + "Resource": { + "id": "Resource", + "path": "aws-cdk-rds-proxy-sql-server/SqlProxyRole/DefaultPolicy/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Policy", + "aws:cdk:cloudformation:props": { + "policyDocument": { + "Statement": [ + { + "Action": "rds-db:connect", + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":rds-db:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":dbuser:", + { + "Fn::Select": [ + 6, + { + "Fn::Split": [ + ":", + { + "Fn::GetAtt": [ + "DbProxy471ABCB4", + "DBProxyArn" + ] + } + ] + } + ] + }, + "/master" + ] + ] + } + } + ], + "Version": "2012-10-17" + }, + "policyName": "SqlProxyRoleDefaultPolicy225DB22D", + "roles": [ + { + "Ref": "SqlProxyRole0DC4DDBC" + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.CfnPolicy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.Policy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.Role", + "version": "0.0.0" + } + }, + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "aws-cdk-rds-proxy-sql-server/BootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "aws-cdk-rds-proxy-sql-server/CheckBootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnRule", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.Stack", + "version": "0.0.0" + } + }, + "proxy-sql-server-integ-test": { + "id": "proxy-sql-server-integ-test", + "path": "proxy-sql-server-integ-test", + "children": { + "DefaultTest": { + "id": "DefaultTest", + "path": "proxy-sql-server-integ-test/DefaultTest", + "children": { + "Default": { + "id": "Default", + "path": "proxy-sql-server-integ-test/DefaultTest/Default", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + }, + "DeployAssert": { + "id": "DeployAssert", + "path": "proxy-sql-server-integ-test/DefaultTest/DeployAssert", + "children": { + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "proxy-sql-server-integ-test/DefaultTest/DeployAssert/BootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "proxy-sql-server-integ-test/DefaultTest/DeployAssert/CheckBootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnRule", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.Stack", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests-alpha.IntegTestCase", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests-alpha.IntegTest", + "version": "0.0.0" + } + }, + "Tree": { + "id": "Tree", + "path": "Tree", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.270" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.App", + "version": "0.0.0" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.proxy-sql-server.ts b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.proxy-sql-server.ts new file mode 100644 index 0000000000000..9665d73c8ae57 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-rds/test/integ.proxy-sql-server.ts @@ -0,0 +1,52 @@ +import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as cdk from 'aws-cdk-lib/core'; +import { RemovalPolicy } from 'aws-cdk-lib/core'; +import { IntegTest } from '@aws-cdk/integ-tests-alpha'; +import * as rds from 'aws-cdk-lib/aws-rds'; +import { LicenseModel, SqlServerEngineVersion } from 'aws-cdk-lib/aws-rds'; + +const app = new cdk.App(); +const stack = new cdk.Stack(app, 'aws-cdk-rds-proxy-sql-server', { + terminationProtection: false, +}); + +const vpc = new ec2.Vpc(stack, 'vpc', { maxAzs: 2 }); + +const dbInstance = new rds.DatabaseInstance(stack, 'SqlServerDbInstance', { + engine: rds.DatabaseInstanceEngine.sqlServerEx({ + version: SqlServerEngineVersion.VER_15, + }), + instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE3, ec2.InstanceSize.SMALL), + credentials: rds.Credentials.fromUsername('master', { + excludeCharacters: '"@/\\', + }), + vpc, + licenseModel: LicenseModel.LICENSE_INCLUDED, + removalPolicy: RemovalPolicy.DESTROY, +}); + +const proxy = new rds.DatabaseProxy(stack, 'DbProxy', { + borrowTimeout: cdk.Duration.seconds(30), + maxConnectionsPercent: 50, + secrets: [dbInstance.secret!], + proxyTarget: rds.ProxyTarget.fromInstance(dbInstance), + vpc, + iamAuth: true, +}); + +const role = new iam.Role(stack, 'SqlProxyRole', { + assumedBy: new iam.AccountPrincipal(stack.account), +}); +proxy.grantConnect(role, 'master'); + +new IntegTest(app, 'proxy-sql-server-integ-test', { + testCases: [stack], + cdkCommandOptions: { + deploy: { + args: { + rollback: true, + }, + }, + }, +}); diff --git a/packages/aws-cdk-lib/aws-rds/lib/instance-engine.ts b/packages/aws-cdk-lib/aws-rds/lib/instance-engine.ts index ef00de1d20b66..e12833906324d 100644 --- a/packages/aws-cdk-lib/aws-rds/lib/instance-engine.ts +++ b/packages/aws-cdk-lib/aws-rds/lib/instance-engine.ts @@ -1825,6 +1825,7 @@ abstract class SqlServerInstanceEngineBase extends InstanceEngineBase { s3Import: 'S3_INTEGRATION', s3Export: 'S3_INTEGRATION', }, + engineFamily: 'SQLSERVER', }); } diff --git a/packages/aws-cdk-lib/aws-rds/test/instance-engine.test.ts b/packages/aws-cdk-lib/aws-rds/test/instance-engine.test.ts index 7011288790454..6da65fd2d64d3 100644 --- a/packages/aws-cdk-lib/aws-rds/test/instance-engine.test.ts +++ b/packages/aws-cdk-lib/aws-rds/test/instance-engine.test.ts @@ -242,6 +242,17 @@ describe('instance engine', () => { }); }); + describe('SQL Server engine family', () => { + test.each([ + ['SQL Server Standard Edition', rds.DatabaseInstanceEngine.sqlServerSe({ version: rds.SqlServerEngineVersion.VER_15_00_4153_1_V1 })], + ['SQL Server Enterprise Edition', rds.DatabaseInstanceEngine.sqlServerEe({ version: rds.SqlServerEngineVersion.VER_15_00_4153_1_V1 })], + ['SQL Server Web Edition', rds.DatabaseInstanceEngine.sqlServerWeb({ version: rds.SqlServerEngineVersion.VER_15_00_4153_1_V1 })], + ['SQL Server Express Edition', rds.DatabaseInstanceEngine.sqlServerEx({ version: rds.SqlServerEngineVersion.VER_15_00_4153_1_V1 })], + ])('is passed correctly for %s', (_, engine) => { + expect(engine.engineFamily).toEqual('SQLSERVER'); + }); + }); + describe('PostgreSQL engine bindToInstance', () => { test('returns s3 import/export feature if the version supports it', () => { const engineNewerVersion = rds.DatabaseInstanceEngine.postgres({ version: rds.PostgresEngineVersion.VER_15_2 }); From 8ca4c09817d03a094ac395f9ad1adace931f74b4 Mon Sep 17 00:00:00 2001 From: Luca Pizzini Date: Tue, 18 Apr 2023 16:10:08 +0200 Subject: [PATCH 3/7] fix(core): Duration.parse() doesn't parse milliseconds (#25010) Added millisecond parsing to [Duration](https://github.com/aws/aws-cdk/blob/main/packages/aws-cdk-lib/core/lib/duration.ts). `Duration.parse('PT0.005S').toMilliseconds()` is now correctly resolved to `5`. Closes #24971. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/aws-cdk-lib/core/lib/duration.ts | 14 ++++++++------ packages/aws-cdk-lib/core/test/duration.test.ts | 5 +++++ 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/packages/aws-cdk-lib/core/lib/duration.ts b/packages/aws-cdk-lib/core/lib/duration.ts index c53009b07aafa..9e32fbb89d391 100644 --- a/packages/aws-cdk-lib/core/lib/duration.ts +++ b/packages/aws-cdk-lib/core/lib/duration.ts @@ -67,16 +67,18 @@ export class Duration { * @returns the parsed `Duration`. */ public static parse(duration: string): Duration { - const matches = duration.match(/^P(?:(\d+)D)?(?:T(?:(\d+)H)?(?:(\d+)M)?(?:(\d+)S)?)?$/); + const matches = duration.match(/^P(?:(\d+)D)?(?:T(?:(\d+)H)?(?:(\d+)M)?(?:(\d+)\.?(\d{1,3})?S)?)?$/); if (!matches) { throw new Error(`Not a valid ISO duration: ${duration}`); } - const [, days, hours, minutes, seconds] = matches; - if (!days && !hours && !minutes && !seconds) { + const [, days, hours, minutes, seconds, milliseconds] = matches; + if (!days && !hours && !minutes && !seconds && !milliseconds) { throw new Error(`Not a valid ISO duration: ${duration}`); } + const millis = milliseconds ? milliseconds.padEnd(3, '0') : ''; return Duration.millis( - _toInt(seconds) * TimeUnit.Seconds.inMillis + _toInt(millis) + + _toInt(seconds) * TimeUnit.Seconds.inMillis + (_toInt(minutes) * TimeUnit.Minutes.inMillis) + (_toInt(hours) * TimeUnit.Hours.inMillis) + (_toInt(days) * TimeUnit.Days.inMillis), @@ -251,8 +253,8 @@ export class Duration { } } - // Remainder in millis - if (millis > 0) { + // Remainder in millis (keep only above threshold) + if (millis > 0.0001) { ret.push([millis, TimeUnit.Milliseconds]); } return ret; diff --git a/packages/aws-cdk-lib/core/test/duration.test.ts b/packages/aws-cdk-lib/core/test/duration.test.ts index c1144c53c43c2..75d45129010c3 100644 --- a/packages/aws-cdk-lib/core/test/duration.test.ts +++ b/packages/aws-cdk-lib/core/test/duration.test.ts @@ -98,20 +98,25 @@ describe('duration', () => { expect(Duration.seconds(65).toIsoString()).toEqual('PT1M5S'); expect(Duration.seconds(1 + 60 * (1 + 60 * (1 + 24))).toIsoString()).toEqual('P1DT1H1M1S'); + expect(Duration.millis(1 + (1000 * (1 + 60 * (1 + 60 * (1 + 24))))).toIsoString()).toEqual('P1DT1H1M1.001S'); }); test('parse', () => { + expect(Duration.parse('PT0.000S').toMilliseconds()).toEqual(0); expect(Duration.parse('PT0S').toSeconds()).toEqual(0); expect(Duration.parse('PT0M').toSeconds()).toEqual(0); expect(Duration.parse('PT0H').toSeconds()).toEqual(0); expect(Duration.parse('P0D').toSeconds()).toEqual(0); + expect(Duration.parse('PT0.005S').toMilliseconds()).toEqual(5); + expect(Duration.parse('PT0.5S').toMilliseconds()).toEqual(500); expect(Duration.parse('PT5S').toSeconds()).toEqual(5); expect(Duration.parse('PT5M').toSeconds()).toEqual(300); expect(Duration.parse('PT5H').toSeconds()).toEqual(18_000); expect(Duration.parse('P5D').toSeconds()).toEqual(432_000); expect(Duration.parse('P1DT1H1M1S').toSeconds()).toEqual(1 + 60 * (1 + 60 * (1 + 24))); + expect(Duration.parse('P1DT1H1M1.001S').toMilliseconds()).toEqual(1 + (1000 * (1 + 60 * (1 + 60 * (1 + 24))))); }); test('reject illegal parses', () => { From 2d4a60dee7892041786482ac001e858511ac0b40 Mon Sep 17 00:00:00 2001 From: Styerp <35037768+Styerp@users.noreply.github.com> Date: Tue, 18 Apr 2023 07:39:02 -0700 Subject: [PATCH 4/7] =?UTF-8?q?fix(assertions):=20nested=20stacks=20inside?= =?UTF-8?q?=20non-root=20stages=20don't=20resolve=20t=E2=80=A6=20(#25006)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit …emplates Templates are placed inside a path described by their closest assembly. Using this assembly lets nested stack templates resolve, regardless of their stage depth. Previously, they would fail to resolve if they were in a stage other than the app. Closes #24004. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- .../aws-cdk-lib/assertions/lib/template.ts | 6 +-- .../assertions/test/template.test.ts | 37 ++++++++++++++++++- 2 files changed, 39 insertions(+), 4 deletions(-) diff --git a/packages/aws-cdk-lib/assertions/lib/template.ts b/packages/aws-cdk-lib/assertions/lib/template.ts index b85b718c15f42..6dc609301291c 100644 --- a/packages/aws-cdk-lib/assertions/lib/template.ts +++ b/packages/aws-cdk-lib/assertions/lib/template.ts @@ -296,12 +296,12 @@ export interface TemplateParsingOptions { } function toTemplate(stack: Stack): any { - const root = stack.node.root; - if (!Stage.isStage(root)) { + const stage = Stage.of(stack); + if (!Stage.isStage(stage)) { throw new Error('unexpected: all stacks must be part of a Stage or an App'); } - const assembly = root.synth(); + const assembly = stage.synth(); if (stack.nestedStackParent) { // if this is a nested stack (it has a parent), then just read the template as a string return JSON.parse(fs.readFileSync(path.join(assembly.directory, stack.templateFile)).toString('utf-8')); diff --git a/packages/aws-cdk-lib/assertions/test/template.test.ts b/packages/aws-cdk-lib/assertions/test/template.test.ts index 2deb97c1e2197..eaced11409952 100644 --- a/packages/aws-cdk-lib/assertions/test/template.test.ts +++ b/packages/aws-cdk-lib/assertions/test/template.test.ts @@ -1,4 +1,16 @@ -import { App, CfnCondition, CfnMapping, CfnOutput, CfnParameter, CfnResource, Fn, LegacyStackSynthesizer, NestedStack, Stack } from '../../core'; +import { + App, + CfnCondition, + CfnMapping, + CfnOutput, + CfnParameter, + CfnResource, + Fn, + LegacyStackSynthesizer, + NestedStack, + Stack, + Stage +} from '../../core'; import { Construct } from 'constructs'; import { Capture, Match, Template } from '../lib'; @@ -1353,6 +1365,29 @@ describe('Template', () => { }); }).not.toThrow(/dependency cycle/); }); + + test('nested stack inside a Stage in an App', () => { + const app = new App(); + const stage = new Stage(app, 'Stage'); + const stack = new Stack(stage); + const nested = new NestedStack(stack, 'MyNestedStack'); + new CfnResource(nested, 'Bar', { + type: 'Bar::Baz', + properties: { + Qux: 'Foo', + }, + }); + const template = Template.fromStack(nested); + + expect(template.toJSON()).toEqual({ + Resources: { + Bar: { + Type: 'Bar::Baz', + Properties: { Qux: 'Foo' }, + }, + }, + }); + }); }); function expectToThrow(fn: () => void, msgs: (RegExp | string)[]): void { From 0d156a810a7a049e03f2d84582f12b7a231dea2e Mon Sep 17 00:00:00 2001 From: Ben Limmer <630449+blimmer@users.noreply.github.com> Date: Tue, 18 Apr 2023 09:20:18 -0600 Subject: [PATCH 5/7] fix(ecs): allow passing execution role to imported TaskDefinitions (#24987) See #24984 for details. TLDR; there's not a way currently exposed to define the `executionRole` on an imported `TaskDefinition`. This change allows optionally passing an `executionRole`. Fixes issue #24984. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- .../lib/base/_imported-task-definition.ts | 10 +++++++ .../aws-ecs/lib/base/task-definition.ts | 10 +++++++ .../aws-ecs/lib/ec2/ec2-task-definition.ts | 1 + .../lib/external/external-task-definition.ts | 1 + .../lib/fargate/fargate-task-definition.ts | 1 + .../test/ec2/ec2-task-definition.test.ts | 5 ++++ .../external/external-task-definition.test.ts | 29 +++++++++++++++++++ .../fargate/fargate-task-definition.test.ts | 7 ++++- .../aws-ecs/test/task-definition.test.ts | 6 +++- 9 files changed, 68 insertions(+), 2 deletions(-) diff --git a/packages/aws-cdk-lib/aws-ecs/lib/base/_imported-task-definition.ts b/packages/aws-cdk-lib/aws-ecs/lib/base/_imported-task-definition.ts index 9ee5eb50060f0..a4a02ba424ea2 100644 --- a/packages/aws-cdk-lib/aws-ecs/lib/base/_imported-task-definition.ts +++ b/packages/aws-cdk-lib/aws-ecs/lib/base/_imported-task-definition.ts @@ -34,6 +34,15 @@ export interface ImportedTaskDefinitionProps { * @default Permissions cannot be granted to the imported task. */ readonly taskRole?: IRole; + + /** + * The IAM role that grants containers and Fargate agents permission to make AWS API calls on your behalf. + * + * Some tasks do not have an execution role. + * + * @default - undefined + */ + readonly executionRole?: IRole; } /** @@ -70,6 +79,7 @@ export class ImportedTaskDefinition extends Resource implements IEc2TaskDefiniti this.compatibility = props.compatibility ?? Compatibility.EC2_AND_FARGATE; this.taskDefinitionArn = props.taskDefinitionArn; + this.executionRole = props.executionRole; this._taskRole = props.taskRole; this._networkMode = props.networkMode; } diff --git a/packages/aws-cdk-lib/aws-ecs/lib/base/task-definition.ts b/packages/aws-cdk-lib/aws-ecs/lib/base/task-definition.ts index 365299bbbbced..e56de0dac93da 100644 --- a/packages/aws-cdk-lib/aws-ecs/lib/base/task-definition.ts +++ b/packages/aws-cdk-lib/aws-ecs/lib/base/task-definition.ts @@ -250,6 +250,15 @@ export interface CommonTaskDefinitionAttributes { * @default Permissions cannot be granted to the imported task. */ readonly taskRole?: iam.IRole; + + /** + * The IAM role that grants containers and Fargate agents permission to make AWS API calls on your behalf. + * + * Some tasks do not have an execution role. + * + * @default - undefined + */ + readonly executionRole?: iam.IRole; } /** @@ -317,6 +326,7 @@ export class TaskDefinition extends TaskDefinitionBase { compatibility: attrs.compatibility, networkMode: attrs.networkMode, taskRole: attrs.taskRole, + executionRole: attrs.executionRole, }); } diff --git a/packages/aws-cdk-lib/aws-ecs/lib/ec2/ec2-task-definition.ts b/packages/aws-cdk-lib/aws-ecs/lib/ec2/ec2-task-definition.ts index 6056682b73666..dbcd8fe099ad6 100644 --- a/packages/aws-cdk-lib/aws-ecs/lib/ec2/ec2-task-definition.ts +++ b/packages/aws-cdk-lib/aws-ecs/lib/ec2/ec2-task-definition.ts @@ -106,6 +106,7 @@ export class Ec2TaskDefinition extends TaskDefinition implements IEc2TaskDefinit compatibility: Compatibility.EC2, networkMode: attrs.networkMode, taskRole: attrs.taskRole, + executionRole: attrs.executionRole, }); } diff --git a/packages/aws-cdk-lib/aws-ecs/lib/external/external-task-definition.ts b/packages/aws-cdk-lib/aws-ecs/lib/external/external-task-definition.ts index 99029c6d9589d..16af3a90b94b3 100644 --- a/packages/aws-cdk-lib/aws-ecs/lib/external/external-task-definition.ts +++ b/packages/aws-cdk-lib/aws-ecs/lib/external/external-task-definition.ts @@ -66,6 +66,7 @@ export class ExternalTaskDefinition extends TaskDefinition implements IExternalT compatibility: Compatibility.EXTERNAL, networkMode: attrs.networkMode, taskRole: attrs.taskRole, + executionRole: attrs.executionRole, }); } diff --git a/packages/aws-cdk-lib/aws-ecs/lib/fargate/fargate-task-definition.ts b/packages/aws-cdk-lib/aws-ecs/lib/fargate/fargate-task-definition.ts index edeb85fa823fc..56615529c3656 100644 --- a/packages/aws-cdk-lib/aws-ecs/lib/fargate/fargate-task-definition.ts +++ b/packages/aws-cdk-lib/aws-ecs/lib/fargate/fargate-task-definition.ts @@ -120,6 +120,7 @@ export class FargateTaskDefinition extends TaskDefinition implements IFargateTas compatibility: Compatibility.FARGATE, networkMode: attrs.networkMode, taskRole: attrs.taskRole, + executionRole: attrs.executionRole, }); } diff --git a/packages/aws-cdk-lib/aws-ecs/test/ec2/ec2-task-definition.test.ts b/packages/aws-cdk-lib/aws-ecs/test/ec2/ec2-task-definition.test.ts index c57aad2859195..ba22bd0f95861 100644 --- a/packages/aws-cdk-lib/aws-ecs/test/ec2/ec2-task-definition.test.ts +++ b/packages/aws-cdk-lib/aws-ecs/test/ec2/ec2-task-definition.test.ts @@ -1201,12 +1201,16 @@ describe('ec2 task definition', () => { const expectTaskRole = new iam.Role(stack, 'TaskRole', { assumedBy: new iam.ServicePrincipal('ecs-tasks.amazonaws.com'), }); + const expectExecutionRole = new iam.Role(stack, 'ExecutionRole', { + assumedBy: new iam.ServicePrincipal('ecs-tasks.amazonaws.com'), + }); // WHEN const taskDefinition = ecs.Ec2TaskDefinition.fromEc2TaskDefinitionAttributes(stack, 'TD_ID', { taskDefinitionArn: expectTaskDefinitionArn, networkMode: expectNetworkMode, taskRole: expectTaskRole, + executionRole: expectExecutionRole, }); // THEN @@ -1216,6 +1220,7 @@ describe('ec2 task definition', () => { expect(taskDefinition.isFargateCompatible).toBeFalsy(); expect(taskDefinition.networkMode).toBe(expectNetworkMode); expect(taskDefinition.taskRole).toBe(expectTaskRole); + expect(taskDefinition.executionRole).toEqual(expectExecutionRole); }); test('returns an Ec2 TaskDefinition that will throw an error when trying to access its yet to defined networkMode', () => { diff --git a/packages/aws-cdk-lib/aws-ecs/test/external/external-task-definition.test.ts b/packages/aws-cdk-lib/aws-ecs/test/external/external-task-definition.test.ts index 4c6105575927a..681e525c1b8f0 100644 --- a/packages/aws-cdk-lib/aws-ecs/test/external/external-task-definition.test.ts +++ b/packages/aws-cdk-lib/aws-ecs/test/external/external-task-definition.test.ts @@ -617,4 +617,33 @@ describe('external task definition', () => { deviceType: 'eia2.medium', })).toThrow('Cannot use inference accelerators on tasks that run on External service'); }); + + test('can import an External Task Definition using attributes', () => { + // GIVEN + const stack = new cdk.Stack(); + const expectTaskDefinitionArn = 'TD_ARN'; + const expectCompatibility = ecs.Compatibility.EXTERNAL; + const expectNetworkMode = ecs.NetworkMode.AWS_VPC; + const expectTaskRole = new iam.Role(stack, 'TaskRole', { + assumedBy: new iam.ServicePrincipal('ecs-tasks.amazonaws.com'), + }); + const expectExecutionRole = new iam.Role(stack, 'ExecutionRole', { + assumedBy: new iam.ServicePrincipal('ecs-tasks.amazonaws.com'), + }); + + // WHEN + const taskDefinition = ecs.ExternalTaskDefinition.fromExternalTaskDefinitionAttributes(stack, 'TD_ID', { + taskDefinitionArn: expectTaskDefinitionArn, + networkMode: expectNetworkMode, + taskRole: expectTaskRole, + executionRole: expectExecutionRole, + }); + + // THEN + expect(taskDefinition.taskDefinitionArn).toEqual(expectTaskDefinitionArn); + expect(taskDefinition.compatibility).toEqual(expectCompatibility); + expect(taskDefinition.executionRole).toEqual(expectExecutionRole); + expect(taskDefinition.networkMode).toEqual(expectNetworkMode); + expect(taskDefinition.taskRole).toEqual(expectTaskRole); + }); }); diff --git a/packages/aws-cdk-lib/aws-ecs/test/fargate/fargate-task-definition.test.ts b/packages/aws-cdk-lib/aws-ecs/test/fargate/fargate-task-definition.test.ts index ef80331aa1344..32ee9fe90b084 100644 --- a/packages/aws-cdk-lib/aws-ecs/test/fargate/fargate-task-definition.test.ts +++ b/packages/aws-cdk-lib/aws-ecs/test/fargate/fargate-task-definition.test.ts @@ -190,12 +190,16 @@ describe('fargate task definition', () => { const expectTaskRole = new iam.Role(stack, 'TaskRole', { assumedBy: new iam.ServicePrincipal('ecs-tasks.amazonaws.com'), }); + const expectExecutionRole = new iam.Role(stack, 'ExecutionRole', { + assumedBy: new iam.ServicePrincipal('ecs-tasks.amazonaws.com'), + }); // WHEN const taskDefinition = ecs.FargateTaskDefinition.fromFargateTaskDefinitionAttributes(stack, 'TD_ID', { taskDefinitionArn: expectTaskDefinitionArn, networkMode: expectNetworkMode, taskRole: expectTaskRole, + executionRole: expectExecutionRole, }); // THEN @@ -205,6 +209,7 @@ describe('fargate task definition', () => { expect(taskDefinition.isEc2Compatible).toEqual(false); expect(taskDefinition.networkMode).toEqual(expectNetworkMode); expect(taskDefinition.taskRole).toEqual(expectTaskRole); + expect(taskDefinition.executionRole).toEqual(expectExecutionRole); }); @@ -380,4 +385,4 @@ describe('fargate task definition', () => { }); }); -}); \ No newline at end of file +}); diff --git a/packages/aws-cdk-lib/aws-ecs/test/task-definition.test.ts b/packages/aws-cdk-lib/aws-ecs/test/task-definition.test.ts index be12a120fa68e..f94a1fa17745b 100644 --- a/packages/aws-cdk-lib/aws-ecs/test/task-definition.test.ts +++ b/packages/aws-cdk-lib/aws-ecs/test/task-definition.test.ts @@ -303,6 +303,9 @@ describe('task definition', () => { const expectTaskRole = new iam.Role(stack, 'TaskRole', { assumedBy: new iam.ServicePrincipal('ecs-tasks.amazonaws.com'), }); + const expectExecutionRole = new iam.Role(stack, 'ExecutionRole', { + assumedBy: new iam.ServicePrincipal('ecs-tasks.amazonaws.com'), + }); // WHEN const taskDefinition = ecs.TaskDefinition.fromTaskDefinitionAttributes(stack, 'TD_ID', { @@ -310,12 +313,13 @@ describe('task definition', () => { compatibility: expectCompatibility, networkMode: expectNetworkMode, taskRole: expectTaskRole, + executionRole: expectExecutionRole, }); // THEN expect(taskDefinition.taskDefinitionArn).toEqual(expectTaskDefinitionArn); expect(taskDefinition.compatibility).toEqual(expectCompatibility); - expect(taskDefinition.executionRole).toEqual(undefined); + expect(taskDefinition.executionRole).toEqual(expectExecutionRole); expect(taskDefinition.networkMode).toEqual(expectNetworkMode); expect(taskDefinition.taskRole).toEqual(expectTaskRole); From 567247a3ba4762d93dcbb5476f1e7a5bfab0d8dc Mon Sep 17 00:00:00 2001 From: Pahud Hsieh Date: Tue, 18 Apr 2023 13:18:59 -0400 Subject: [PATCH 6/7] docs(rds): improve the doc for deletionProtection (#25169) The undefined default of `deletionProtection` property is confusing especially when we update the cluster by removing this property. This PR improves the description. Closes https://github.com/aws/aws-cdk/issues/24236 ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/aws-cdk-lib/aws-rds/lib/cluster.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/aws-cdk-lib/aws-rds/lib/cluster.ts b/packages/aws-cdk-lib/aws-rds/lib/cluster.ts index ca2f1341f1f2d..59528f6d8892b 100644 --- a/packages/aws-cdk-lib/aws-rds/lib/cluster.ts +++ b/packages/aws-cdk-lib/aws-rds/lib/cluster.ts @@ -103,7 +103,8 @@ interface DatabaseClusterBaseProps { /** * Indicates whether the DB cluster should have deletion protection enabled. * - * @default - true if ``removalPolicy`` is RETAIN, false otherwise + * @default - true if `removalPolicy` is RETAIN, `undefined` otherwise, which will not enable deletion protection. + * To disable deletion protection after it has been enabled, you must explicitly set this value to `false`. */ readonly deletionProtection?: boolean; From e3bc59a7ca8fc282051d97123f4d5a8bdd660db7 Mon Sep 17 00:00:00 2001 From: Ryan Batchelder Date: Tue, 18 Apr 2023 13:42:57 -0400 Subject: [PATCH 7/7] feat(events-targets): Add tagging for ECS tasks triggered by an event (#23838) This adds the ability to pass a tagList and the propagateTags flag to EC2 and Fargate ECS tasks triggered by an event. Users can leverage either or both of these attributes to apply tags an ECS task that's triggered through an Event. Both of these attributes are defined in the EcsParameters for a Rule https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-events-rule-ecsparameters.html. This closes https://github.com/aws/aws-cdk/issues/9823. This is a non-breaking change. These new fields are added as optional with default values such that it won't impact existing stacks. Also note that these are two separate fields: a user can pass either or both but they're not dependent on each other since they have different uses. `propagateTags` will copy tags from the task definition, while `tagList` provides an explicit set of tags to be applied to the task but that are not on the task definition. In either case, these tags are separate from the tags on the EventBridge bus or Rule. I did see that there was previously a PR opened for this in the past which was closed for staleness (https://github.com/aws/aws-cdk/pull/19583). There was a comment on there asking if this could be added to the existing tag system (https://github.com/aws/aws-cdk/pull/19583#pullrequestreview-936428722). I'm not sure if that would make sense in this case since the resource being created at deploy-time by CloudFormation isn't the resource being tagged. The event rule itself is instead being given the flag to pass along tags onto the Task that it's creating at some time in the future when the schedule triggers.I did see that there was previously a PR opened for this in the past which was closed for staleness (https://github.com/aws/aws-cdk/pull/19583). There was a comment on there asking if this could be added to the existing tag system (https://github.com/aws/aws-cdk/pull/19583#pullrequestreview-936428722). I'm not sure if that would make sense in this case since the resource being created at deploy-time by CloudFormation isn't the resource being tagged. The event rule itself is instead being given the flag to pass along tags onto the Task that it's creating at some time in the future when the schedule triggers. ---- ### All Submissions: * [x ] Have you followed the guidelines in our [Contributing guide?](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md) ### Adding new Construct Runtime Dependencies: * [ ] This PR adds new construct runtime dependencies following the process described [here](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md/#adding-construct-runtime-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* --- .../cdk.out | 2 +- ...efaultTestDeployAssert8B2741C4.assets.json | 2 +- .../aws-ecs-integ-ecs.assets.json | 6 +- .../aws-ecs-integ-ecs.template.json | 7 ++ .../integ.json | 2 +- .../manifest.json | 16 +-- .../tree.json | 111 ++++++++++++++++-- .../test/ecs/integ.event-ec2-task.ts | 7 ++ ...efaultTestDeployAssert36341BFB.assets.json | 2 +- .../aws-ecs-integ-fargate.assets.json | 6 +- .../aws-ecs-integ-fargate.template.json | 7 ++ .../integ.json | 5 +- .../manifest.json | 21 ++-- .../tree.json | 107 +++++++++++++---- .../test/ecs/integ.event-fargate-task.ts | 7 ++ .../aws-cdk-lib/aws-events-targets/README.md | 40 +++++++ .../aws-events-targets/lib/ecs-task.ts | 42 ++++++- .../test/ecs/event-rule-target.test.ts | 109 ++++++++++++++++- 18 files changed, 433 insertions(+), 66 deletions(-) diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.api-definition.asset.js.snapshot/cdk.out b/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.api-definition.asset.js.snapshot/cdk.out index 8ecc185e9dbee..d8b441d447f8a 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.api-definition.asset.js.snapshot/cdk.out +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.api-definition.asset.js.snapshot/cdk.out @@ -1 +1 @@ -{"version":"21.0.0"} \ No newline at end of file +{"version":"29.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/ecs/integ.event-ec2-task.js.snapshot/EcsTestDefaultTestDeployAssert8B2741C4.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/ecs/integ.event-ec2-task.js.snapshot/EcsTestDefaultTestDeployAssert8B2741C4.assets.json index 3f1f9a15a2698..24f9c5f3d4cf1 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/ecs/integ.event-ec2-task.js.snapshot/EcsTestDefaultTestDeployAssert8B2741C4.assets.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/ecs/integ.event-ec2-task.js.snapshot/EcsTestDefaultTestDeployAssert8B2741C4.assets.json @@ -1,5 +1,5 @@ { - "version": "21.0.0", + "version": "29.0.0", "files": { "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { "source": { diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/ecs/integ.event-ec2-task.js.snapshot/aws-ecs-integ-ecs.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/ecs/integ.event-ec2-task.js.snapshot/aws-ecs-integ-ecs.assets.json index 96fcd217c5d52..43973cfbde2ce 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/ecs/integ.event-ec2-task.js.snapshot/aws-ecs-integ-ecs.assets.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/ecs/integ.event-ec2-task.js.snapshot/aws-ecs-integ-ecs.assets.json @@ -1,7 +1,7 @@ { - "version": "21.0.0", + "version": "29.0.0", "files": { - "0872557613b8f4b6c7ef173ce71b7a0f06895bacc709f34d5a62ffabcc0f5700": { + "07b921a20dfe7af7de139cb4595c2f46d90f9625f61d13cff19dffca84918cd7": { "source": { "path": "aws-ecs-integ-ecs.template.json", "packaging": "file" @@ -9,7 +9,7 @@ "destinations": { "current_account-current_region": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "0872557613b8f4b6c7ef173ce71b7a0f06895bacc709f34d5a62ffabcc0f5700.json", + "objectKey": "07b921a20dfe7af7de139cb4595c2f46d90f9625f61d13cff19dffca84918cd7.json", "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" } } diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/ecs/integ.event-ec2-task.js.snapshot/aws-ecs-integ-ecs.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/ecs/integ.event-ec2-task.js.snapshot/aws-ecs-integ-ecs.template.json index 5c9ce38c39ba3..38ee6a82f1477 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/ecs/integ.event-ec2-task.js.snapshot/aws-ecs-integ-ecs.template.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/ecs/integ.event-ec2-task.js.snapshot/aws-ecs-integ-ecs.template.json @@ -942,6 +942,13 @@ } }, "EcsParameters": { + "PropagateTags": "TASK_DEFINITION", + "TagList": [ + { + "Key": "my-tag", + "Value": "my-tag-value" + } + ], "TaskCount": 1, "TaskDefinitionArn": { "Ref": "TaskDef54694570" diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/ecs/integ.event-ec2-task.js.snapshot/integ.json b/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/ecs/integ.event-ec2-task.js.snapshot/integ.json index 03733012df53e..34309bf0f9864 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/ecs/integ.event-ec2-task.js.snapshot/integ.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/ecs/integ.event-ec2-task.js.snapshot/integ.json @@ -1,5 +1,5 @@ { - "version": "21.0.0", + "version": "29.0.0", "testCases": { "EcsTest/DefaultTest": { "stacks": [ diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/ecs/integ.event-ec2-task.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/ecs/integ.event-ec2-task.js.snapshot/manifest.json index 47826f5c69888..83e9d3a754ee3 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/ecs/integ.event-ec2-task.js.snapshot/manifest.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/ecs/integ.event-ec2-task.js.snapshot/manifest.json @@ -1,12 +1,6 @@ { - "version": "21.0.0", + "version": "29.0.0", "artifacts": { - "Tree": { - "type": "cdk:tree", - "properties": { - "file": "tree.json" - } - }, "aws-ecs-integ-ecs.assets": { "type": "cdk:asset-manifest", "properties": { @@ -23,7 +17,7 @@ "validateOnSynth": false, "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", - "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/0872557613b8f4b6c7ef173ce71b7a0f06895bacc709f34d5a62ffabcc0f5700.json", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/07b921a20dfe7af7de139cb4595c2f46d90f9625f61d13cff19dffca84918cd7.json", "requiresBootstrapStackVersion": 6, "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", "additionalDependencies": [ @@ -340,6 +334,12 @@ ] }, "displayName": "EcsTest/DefaultTest/DeployAssert" + }, + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + } } } } \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/ecs/integ.event-ec2-task.js.snapshot/tree.json b/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/ecs/integ.event-ec2-task.js.snapshot/tree.json index 37a5409d87188..c9f0698ba2b68 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/ecs/integ.event-ec2-task.js.snapshot/tree.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/ecs/integ.event-ec2-task.js.snapshot/tree.json @@ -4,14 +4,6 @@ "id": "App", "path": "", "children": { - "Tree": { - "id": "Tree", - "path": "Tree", - "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.140" - } - }, "aws-ecs-integ-ecs": { "id": "aws-ecs-integ-ecs", "path": "aws-ecs-integ-ecs", @@ -437,6 +429,14 @@ "id": "InstanceRole", "path": "aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/InstanceRole", "children": { + "ImportInstanceRole": { + "id": "ImportInstanceRole", + "path": "aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/InstanceRole/ImportInstanceRole", + "constructInfo": { + "fqn": "@aws-cdk/core.Resource", + "version": "0.0.0" + } + }, "Resource": { "id": "Resource", "path": "aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/InstanceRole/Resource", @@ -652,6 +652,14 @@ "id": "ServiceRole", "path": "aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/ServiceRole", "children": { + "ImportServiceRole": { + "id": "ImportServiceRole", + "path": "aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/ServiceRole/ImportServiceRole", + "constructInfo": { + "fqn": "@aws-cdk/core.Resource", + "version": "0.0.0" + } + }, "Resource": { "id": "Resource", "path": "aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/DrainECSHook/Function/ServiceRole/Resource", @@ -912,7 +920,7 @@ }, "constructInfo": { "fqn": "constructs.Construct", - "version": "10.1.140" + "version": "10.1.216" } }, "LifecycleHookDrainHook": { @@ -952,6 +960,14 @@ "id": "Role", "path": "aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/Role", "children": { + "ImportRole": { + "id": "ImportRole", + "path": "aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/Role/ImportRole", + "constructInfo": { + "fqn": "@aws-cdk/core.Resource", + "version": "0.0.0" + } + }, "Resource": { "id": "Resource", "path": "aws-ecs-integ-ecs/EcsCluster/DefaultAutoScalingGroup/LifecycleHookDrainHook/Role/Resource", @@ -1179,6 +1195,14 @@ "id": "TaskRole", "path": "aws-ecs-integ-ecs/TaskDef/TaskRole", "children": { + "ImportTaskRole": { + "id": "ImportTaskRole", + "path": "aws-ecs-integ-ecs/TaskDef/TaskRole/ImportTaskRole", + "constructInfo": { + "fqn": "@aws-cdk/core.Resource", + "version": "0.0.0" + } + }, "Resource": { "id": "Resource", "path": "aws-ecs-integ-ecs/TaskDef/TaskRole/Resource", @@ -1324,6 +1348,14 @@ "id": "ExecutionRole", "path": "aws-ecs-integ-ecs/TaskDef/ExecutionRole", "children": { + "ImportExecutionRole": { + "id": "ImportExecutionRole", + "path": "aws-ecs-integ-ecs/TaskDef/ExecutionRole/ImportExecutionRole", + "constructInfo": { + "fqn": "@aws-cdk/core.Resource", + "version": "0.0.0" + } + }, "Resource": { "id": "Resource", "path": "aws-ecs-integ-ecs/TaskDef/ExecutionRole/Resource", @@ -1442,6 +1474,14 @@ "id": "EventsRole", "path": "aws-ecs-integ-ecs/TaskDef/EventsRole", "children": { + "ImportEventsRole": { + "id": "ImportEventsRole", + "path": "aws-ecs-integ-ecs/TaskDef/EventsRole/ImportEventsRole", + "constructInfo": { + "fqn": "@aws-cdk/core.Resource", + "version": "0.0.0" + } + }, "Resource": { "id": "Resource", "path": "aws-ecs-integ-ecs/TaskDef/EventsRole/Resource", @@ -1571,7 +1611,14 @@ "taskCount": 1, "taskDefinitionArn": { "Ref": "TaskDef54694570" - } + }, + "propagateTags": "TASK_DEFINITION", + "tagList": [ + { + "key": "my-tag", + "value": "my-tag-value" + } + ] }, "deadLetterConfig": { "arn": { @@ -1596,6 +1643,22 @@ "fqn": "@aws-cdk/aws-events.Rule", "version": "0.0.0" } + }, + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "aws-ecs-integ-ecs/BootstrapVersion", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "aws-ecs-integ-ecs/CheckBootstrapVersion", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnRule", + "version": "0.0.0" + } } }, "constructInfo": { @@ -1616,12 +1679,30 @@ "path": "EcsTest/DefaultTest/Default", "constructInfo": { "fqn": "constructs.Construct", - "version": "10.1.140" + "version": "10.1.216" } }, "DeployAssert": { "id": "DeployAssert", "path": "EcsTest/DefaultTest/DeployAssert", + "children": { + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "EcsTest/DefaultTest/DeployAssert/BootstrapVersion", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "EcsTest/DefaultTest/DeployAssert/CheckBootstrapVersion", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnRule", + "version": "0.0.0" + } + } + }, "constructInfo": { "fqn": "@aws-cdk/core.Stack", "version": "0.0.0" @@ -1638,6 +1719,14 @@ "fqn": "@aws-cdk/integ-tests.IntegTest", "version": "0.0.0" } + }, + "Tree": { + "id": "Tree", + "path": "Tree", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.216" + } } }, "constructInfo": { diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/ecs/integ.event-ec2-task.ts b/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/ecs/integ.event-ec2-task.ts index 9803c8c172e44..d97ebfdaeac88 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/ecs/integ.event-ec2-task.ts +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/ecs/integ.event-ec2-task.ts @@ -45,6 +45,13 @@ rule.addTarget(new targets.EcsTask({ ], }], deadLetterQueue, + propagateTags: ecs.PropagatedTagSource.TASK_DEFINITION, + tags: [ + { + key: 'my-tag', + value: 'my-tag-value', + }, + ], })); new integ.IntegTest(app, 'EcsTest', { diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/ecs/integ.event-fargate-task.js.snapshot/EcsFargateTestDefaultTestDeployAssert36341BFB.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/ecs/integ.event-fargate-task.js.snapshot/EcsFargateTestDefaultTestDeployAssert36341BFB.assets.json index e92ac72eede43..8b8277844242b 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/ecs/integ.event-fargate-task.js.snapshot/EcsFargateTestDefaultTestDeployAssert36341BFB.assets.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/ecs/integ.event-fargate-task.js.snapshot/EcsFargateTestDefaultTestDeployAssert36341BFB.assets.json @@ -1,5 +1,5 @@ { - "version": "20.0.0", + "version": "29.0.0", "files": { "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { "source": { diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/ecs/integ.event-fargate-task.js.snapshot/aws-ecs-integ-fargate.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/ecs/integ.event-fargate-task.js.snapshot/aws-ecs-integ-fargate.assets.json index db5d2093cfca5..1e6aabf49fca3 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/ecs/integ.event-fargate-task.js.snapshot/aws-ecs-integ-fargate.assets.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/ecs/integ.event-fargate-task.js.snapshot/aws-ecs-integ-fargate.assets.json @@ -1,7 +1,7 @@ { - "version": "20.0.0", + "version": "29.0.0", "files": { - "21e73448eb441396f1651456a83004f72f1f50583a8c6e054fc95fc99118d943": { + "30cd2908bd974e2e1f17ce2fd217f78c8377a301b45a4b7a471e00c77fdff513": { "source": { "path": "aws-ecs-integ-fargate.template.json", "packaging": "file" @@ -9,7 +9,7 @@ "destinations": { "current_account-current_region": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "21e73448eb441396f1651456a83004f72f1f50583a8c6e054fc95fc99118d943.json", + "objectKey": "30cd2908bd974e2e1f17ce2fd217f78c8377a301b45a4b7a471e00c77fdff513.json", "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" } } diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/ecs/integ.event-fargate-task.js.snapshot/aws-ecs-integ-fargate.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/ecs/integ.event-fargate-task.js.snapshot/aws-ecs-integ-fargate.template.json index 0b0870dfece7a..164d932674e9f 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/ecs/integ.event-fargate-task.js.snapshot/aws-ecs-integ-fargate.template.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/ecs/integ.event-fargate-task.js.snapshot/aws-ecs-integ-fargate.template.json @@ -535,6 +535,13 @@ ] } }, + "PropagateTags": "TASK_DEFINITION", + "TagList": [ + { + "Key": "my-tag", + "Value": "my-tag-value" + } + ], "TaskCount": 1, "TaskDefinitionArn": { "Ref": "TaskDef54694570" diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/ecs/integ.event-fargate-task.js.snapshot/integ.json b/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/ecs/integ.event-fargate-task.js.snapshot/integ.json index bcf64cee1d1b5..0602053494e16 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/ecs/integ.event-fargate-task.js.snapshot/integ.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/ecs/integ.event-fargate-task.js.snapshot/integ.json @@ -1,11 +1,12 @@ { - "version": "20.0.0", + "version": "29.0.0", "testCases": { "EcsFargateTest/DefaultTest": { "stacks": [ "aws-ecs-integ-fargate" ], - "assertionStack": "EcsFargateTest/DefaultTest/DeployAssert" + "assertionStack": "EcsFargateTest/DefaultTest/DeployAssert", + "assertionStackName": "EcsFargateTestDefaultTestDeployAssert36341BFB" } } } \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/ecs/integ.event-fargate-task.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/ecs/integ.event-fargate-task.js.snapshot/manifest.json index eedaea2fc2e20..ff1ef8c7311e4 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/ecs/integ.event-fargate-task.js.snapshot/manifest.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/ecs/integ.event-fargate-task.js.snapshot/manifest.json @@ -1,12 +1,6 @@ { - "version": "20.0.0", + "version": "29.0.0", "artifacts": { - "Tree": { - "type": "cdk:tree", - "properties": { - "file": "tree.json" - } - }, "aws-ecs-integ-fargate.assets": { "type": "cdk:asset-manifest", "properties": { @@ -23,7 +17,7 @@ "validateOnSynth": false, "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", - "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/21e73448eb441396f1651456a83004f72f1f50583a8c6e054fc95fc99118d943.json", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/30cd2908bd974e2e1f17ce2fd217f78c8377a301b45a4b7a471e00c77fdff513.json", "requiresBootstrapStackVersion": 6, "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", "additionalDependencies": [ @@ -144,10 +138,7 @@ "/aws-ecs-integ-fargate/TaskDef/Resource": [ { "type": "aws:cdk:logicalId", - "data": "TaskDef54694570", - "trace": [ - "!!DESTRUCTIVE_CHANGES: WILL_REPLACE" - ] + "data": "TaskDef54694570" } ], "/aws-ecs-integ-fargate/TaskDef/TheContainer/LogGroup/Resource": [ @@ -253,6 +244,12 @@ ] }, "displayName": "EcsFargateTest/DefaultTest/DeployAssert" + }, + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + } } } } \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/ecs/integ.event-fargate-task.js.snapshot/tree.json b/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/ecs/integ.event-fargate-task.js.snapshot/tree.json index bc82dac404bd5..6acf636748337 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/ecs/integ.event-fargate-task.js.snapshot/tree.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/ecs/integ.event-fargate-task.js.snapshot/tree.json @@ -4,14 +4,6 @@ "id": "App", "path": "", "children": { - "Tree": { - "id": "Tree", - "path": "Tree", - "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.85" - } - }, "aws-ecs-integ-fargate": { "id": "aws-ecs-integ-fargate", "path": "aws-ecs-integ-fargate", @@ -91,8 +83,8 @@ "id": "Acl", "path": "aws-ecs-integ-fargate/Vpc/PublicSubnet1/Acl", "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.85" + "fqn": "@aws-cdk/core.Resource", + "version": "0.0.0" } }, "RouteTable": { @@ -258,8 +250,8 @@ "id": "Acl", "path": "aws-ecs-integ-fargate/Vpc/PrivateSubnet1/Acl", "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.85" + "fqn": "@aws-cdk/core.Resource", + "version": "0.0.0" } }, "RouteTable": { @@ -482,6 +474,14 @@ "id": "TaskRole", "path": "aws-ecs-integ-fargate/TaskDef/TaskRole", "children": { + "ImportTaskRole": { + "id": "ImportTaskRole", + "path": "aws-ecs-integ-fargate/TaskDef/TaskRole/ImportTaskRole", + "constructInfo": { + "fqn": "@aws-cdk/core.Resource", + "version": "0.0.0" + } + }, "Resource": { "id": "Resource", "path": "aws-ecs-integ-fargate/TaskDef/TaskRole/Resource", @@ -578,8 +578,8 @@ "id": "Staging", "path": "aws-ecs-integ-fargate/TaskDef/TheContainer/AssetImage/Staging", "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.85" + "fqn": "@aws-cdk/core.AssetStaging", + "version": "0.0.0" } }, "Repository": { @@ -628,6 +628,14 @@ "id": "ExecutionRole", "path": "aws-ecs-integ-fargate/TaskDef/ExecutionRole", "children": { + "ImportExecutionRole": { + "id": "ImportExecutionRole", + "path": "aws-ecs-integ-fargate/TaskDef/ExecutionRole/ImportExecutionRole", + "constructInfo": { + "fqn": "@aws-cdk/core.Resource", + "version": "0.0.0" + } + }, "Resource": { "id": "Resource", "path": "aws-ecs-integ-fargate/TaskDef/ExecutionRole/Resource", @@ -746,6 +754,14 @@ "id": "EventsRole", "path": "aws-ecs-integ-fargate/TaskDef/EventsRole", "children": { + "ImportEventsRole": { + "id": "ImportEventsRole", + "path": "aws-ecs-integ-fargate/TaskDef/EventsRole/ImportEventsRole", + "constructInfo": { + "fqn": "@aws-cdk/core.Resource", + "version": "0.0.0" + } + }, "Resource": { "id": "Resource", "path": "aws-ecs-integ-fargate/TaskDef/EventsRole/Resource", @@ -918,6 +934,13 @@ "taskDefinitionArn": { "Ref": "TaskDef54694570" }, + "propagateTags": "TASK_DEFINITION", + "tagList": [ + { + "key": "my-tag", + "value": "my-tag-value" + } + ], "launchType": "FARGATE", "networkConfiguration": { "awsVpcConfiguration": { @@ -961,11 +984,27 @@ "fqn": "@aws-cdk/aws-events.Rule", "version": "0.0.0" } + }, + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "aws-ecs-integ-fargate/BootstrapVersion", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "aws-ecs-integ-fargate/CheckBootstrapVersion", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnRule", + "version": "0.0.0" + } } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.85" + "fqn": "@aws-cdk/core.Stack", + "version": "0.0.0" } }, "EcsFargateTest": { @@ -981,15 +1020,33 @@ "path": "EcsFargateTest/DefaultTest/Default", "constructInfo": { "fqn": "constructs.Construct", - "version": "10.1.85" + "version": "10.1.216" } }, "DeployAssert": { "id": "DeployAssert", "path": "EcsFargateTest/DefaultTest/DeployAssert", + "children": { + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "EcsFargateTest/DefaultTest/DeployAssert/BootstrapVersion", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "EcsFargateTest/DefaultTest/DeployAssert/CheckBootstrapVersion", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnRule", + "version": "0.0.0" + } + } + }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.85" + "fqn": "@aws-cdk/core.Stack", + "version": "0.0.0" } } }, @@ -1003,11 +1060,19 @@ "fqn": "@aws-cdk/integ-tests.IntegTest", "version": "0.0.0" } + }, + "Tree": { + "id": "Tree", + "path": "Tree", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.216" + } } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.85" + "fqn": "@aws-cdk/core.App", + "version": "0.0.0" } } } \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/ecs/integ.event-fargate-task.ts b/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/ecs/integ.event-fargate-task.ts index 81af86efa0825..8afda14fc48d6 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/ecs/integ.event-fargate-task.ts +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-events-targets/test/ecs/integ.event-fargate-task.ts @@ -41,6 +41,13 @@ rule.addTarget(new targets.EcsTask({ ], }], deadLetterQueue, + propagateTags: ecs.PropagatedTagSource.TASK_DEFINITION, + tags: [ + { + key: 'my-tag', + value: 'my-tag-value', + }, + ], })); new integ.IntegTest(app, 'EcsFargateTest', { diff --git a/packages/aws-cdk-lib/aws-events-targets/README.md b/packages/aws-cdk-lib/aws-events-targets/README.md index 62da5179fbab0..b73e4a905c8f1 100644 --- a/packages/aws-cdk-lib/aws-events-targets/README.md +++ b/packages/aws-cdk-lib/aws-events-targets/README.md @@ -337,3 +337,43 @@ rule.addTarget(new targets.EventBus( ), )); ``` + +## Run an ECS Task + +Use the `EcsTask` target to run an ECS Task. + +The code snippet below creates a scheduled event rule that will run the task described in `taskDefinition` every hour. + +### Tagging Tasks + +By default, ECS tasks run from EventBridge targets will not have tags applied to +them. You can set the `propagateTags` field to propagate the tags set on the task +definition to the task initialized by the event trigger. + +If you want to set tags independent of those applied to the TaskDefinition, you +can use the `tags` array. Both of these fields can be used together or separately +to set tags on the triggered task. + +```ts +import * as ecs from "@aws-cdk/aws-ecs" +declare const cluster: ecs.ICluster +declare const taskDefinition: ecs.TaskDefinition + +const rule = new events.Rule(this, 'Rule', { + schedule: events.Schedule.rate(cdk.Duration.hours(1)), +}); + +rule.addTarget( + new targets.EcsTask( { + cluster: cluster, + taskDefinition: taskDefinition, + propagateTags: ecs.PropagatedTagSource.TASK_DEFINITION, + tags: [ + { + key: 'my-tag', + value: 'my-tag-value', + }, + ], + }) +); +``` diff --git a/packages/aws-cdk-lib/aws-events-targets/lib/ecs-task.ts b/packages/aws-cdk-lib/aws-events-targets/lib/ecs-task.ts index ff5d53bd752a5..cfe84d9d04e49 100644 --- a/packages/aws-cdk-lib/aws-events-targets/lib/ecs-task.ts +++ b/packages/aws-cdk-lib/aws-events-targets/lib/ecs-task.ts @@ -7,6 +7,20 @@ import { Construct } from 'constructs'; import { ContainerOverride } from './ecs-task-properties'; import { addToDeadLetterQueueResourcePolicy, bindBaseTargetConfig, singletonEventRole, TargetBaseProps } from './util'; +/** + * Metadata that you apply to a resource to help categorize and organize the resource. Each tag consists of a key and an optional value, both of which you define. + */ +export interface Tag { + + /** + * Key is the name of the tag + */ + readonly key: string; + /** + * Value is the metadata contents of the tag + */ + readonly value: string; +} /** * Properties to define an ECS Event Task */ @@ -81,6 +95,20 @@ export interface EcsTaskProps extends TargetBaseProps { * @default - ECS will set the Fargate platform version to 'LATEST' */ readonly platformVersion?: ecs.FargatePlatformVersion; + + /** + * Specifies whether to propagate the tags from the task definition to the task. If no value is specified, the tags are not propagated. + * + * @default - Tags will not be propagated + */ + readonly propagateTags?: ecs.PropagatedTagSource + + /** + * The metadata that you apply to the task to help you categorize and organize them. Each tag consists of a key and an optional value, both of which you define. + * + * @default - No additional tags are applied to the task + */ + readonly tags?: Tag[] } /** @@ -108,6 +136,8 @@ export class EcsTask implements events.IRuleTarget { private readonly taskCount: number; private readonly role: iam.IRole; private readonly platformVersion?: ecs.FargatePlatformVersion; + private readonly propagateTags?: ecs.PropagatedTagSource; + private readonly tags?: Tag[] constructor(private readonly props: EcsTaskProps) { if (props.securityGroup !== undefined && props.securityGroups !== undefined) { @@ -119,11 +149,19 @@ export class EcsTask implements events.IRuleTarget { this.taskCount = props.taskCount ?? 1; this.platformVersion = props.platformVersion; + const propagateTagsValidValues = [ecs.PropagatedTagSource.TASK_DEFINITION, ecs.PropagatedTagSource.NONE]; + if (props.propagateTags && !propagateTagsValidValues.includes(props.propagateTags)) { + throw new Error('When propagateTags is passed, it must be set to TASK_DEFINITION or NONE.'); + } + this.propagateTags = props.propagateTags; + this.role = props.role ?? singletonEventRole(this.taskDefinition); for (const stmt of this.createEventRolePolicyStatements()) { this.role.addToPrincipalPolicy(stmt); } + this.tags = props.tags; + // Security groups are only configurable with the "awsvpc" network mode. if (this.taskDefinition.networkMode !== ecs.NetworkMode.AWS_VPC) { if (props.securityGroup !== undefined || props.securityGroups !== undefined) { @@ -159,11 +197,13 @@ export class EcsTask implements events.IRuleTarget { const input = { containerOverrides }; const taskCount = this.taskCount; const taskDefinitionArn = this.taskDefinition.taskDefinitionArn; + const propagateTags = this.propagateTags; + const tagList = this.tags; const subnetSelection = this.props.subnetSelection || { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }; const assignPublicIp = subnetSelection.subnetType === ec2.SubnetType.PUBLIC ? 'ENABLED' : 'DISABLED'; - const baseEcsParameters = { taskCount, taskDefinitionArn }; + const baseEcsParameters = { taskCount, taskDefinitionArn, propagateTags, tagList }; const ecsParameters: events.CfnRule.EcsParametersProperty = this.taskDefinition.networkMode === ecs.NetworkMode.AWS_VPC ? { diff --git a/packages/aws-cdk-lib/aws-events-targets/test/ecs/event-rule-target.test.ts b/packages/aws-cdk-lib/aws-events-targets/test/ecs/event-rule-target.test.ts index 86029762a9623..5f4944bd8014a 100644 --- a/packages/aws-cdk-lib/aws-events-targets/test/ecs/event-rule-target.test.ts +++ b/packages/aws-cdk-lib/aws-events-targets/test/ecs/event-rule-target.test.ts @@ -1,4 +1,5 @@ -import { Template } from '../../../assertions'; + +import { Match, Template } from '../../../assertions'; import * as autoscaling from '../../../aws-autoscaling'; import * as ec2 from '../../../aws-ec2'; import * as ecs from '../../../aws-ecs'; @@ -778,3 +779,109 @@ test('uses the specific fargate platform version', () => { ], }); }); + +test('sets the propagate tags flag', () => { + // GIVEN + const taskDefinition = new ecs.FargateTaskDefinition(stack, 'TaskDef'); + taskDefinition.addContainer('TheContainer', { + image: ecs.ContainerImage.fromRegistry('henk'), + }); + + const rule = new events.Rule(stack, 'Rule', { + schedule: events.Schedule.expression('rate(1 min)'), + }); + + // WHEN + rule.addTarget(new targets.EcsTask({ + cluster, + taskDefinition, + taskCount: 1, + containerOverrides: [{ + containerName: 'TheContainer', + command: ['echo', events.EventField.fromPath('$.detail.event')], + }], + propagateTags: ecs.PropagatedTagSource.TASK_DEFINITION, + })); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { + Targets: [ + Match.objectLike({ + EcsParameters: Match.objectLike({ + PropagateTags: ecs.PropagatedTagSource.TASK_DEFINITION, + }), + }), + ], + }); +}); + +test('throws an error when trying to pass a disallowed value for propagateTags', () => { + // GIVEN + const taskDefinition = new ecs.FargateTaskDefinition(stack, 'TaskDef'); + taskDefinition.addContainer('TheContainer', { + image: ecs.ContainerImage.fromRegistry('henk'), + }); + + const rule = new events.Rule(stack, 'Rule', { + schedule: events.Schedule.expression('rate(1 min)'), + }); + + // THEN + expect(() => { + rule.addTarget(new targets.EcsTask({ + cluster, + taskDefinition, + taskCount: 1, + containerOverrides: [{ + containerName: 'TheContainer', + command: ['echo', events.EventField.fromPath('$.detail.event')], + }], + propagateTags: ecs.PropagatedTagSource.SERVICE, // propagateTags must be TASK_DEFINITION or NONE + })); + }).toThrowError('When propagateTags is passed, it must be set to TASK_DEFINITION or NONE.'); +}); + +test('sets tag lists', () => { + // GIVEN + const taskDefinition = new ecs.FargateTaskDefinition(stack, 'TaskDef'); + taskDefinition.addContainer('TheContainer', { + image: ecs.ContainerImage.fromRegistry('henk'), + }); + + const rule = new events.Rule(stack, 'Rule', { + schedule: events.Schedule.expression('rate(1 min)'), + }); + + // WHEN + rule.addTarget(new targets.EcsTask({ + cluster, + taskDefinition, + taskCount: 1, + containerOverrides: [{ + containerName: 'TheContainer', + command: ['echo', events.EventField.fromPath('$.detail.event')], + }], + tags: [ + { + key: 'my-tag', + value: 'my-tag-value', + }, + ], + })); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', { + Targets: [ + Match.objectLike({ + EcsParameters: Match.objectLike({ + TagList: [ + { + Key: 'my-tag', + Value: 'my-tag-value', + }, + ], + }), + }), + ], + }); +});