From ce385322616aed7ee38a72791a0c117fd4b9c854 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=F0=9F=91=A8=F0=9F=8F=BC=E2=80=8D=F0=9F=92=BB=20Romain=20M?= =?UTF-8?q?arcadier-Muller?= Date: Thu, 10 Jan 2019 17:07:30 +0100 Subject: [PATCH 1/3] feat(ssm): Add L2 resource for SSM Parameters Specialized classes for StringParameter and StringListParameter, and their interface counterparts. --- packages/@aws-cdk/aws-ssm/README.md | 23 ++ packages/@aws-cdk/aws-ssm/lib/index.ts | 1 + packages/@aws-cdk/aws-ssm/lib/parameter.ts | 220 ++++++++++++++++++ packages/@aws-cdk/aws-ssm/package.json | 17 ++ .../test/integ.parameter.lit.expected.json | 97 ++++++++ .../aws-ssm/test/integ.parameter.lit.ts | 33 +++ .../@aws-cdk/aws-ssm/test/test.parameter.ts | 103 ++++++++ 7 files changed, 494 insertions(+) create mode 100644 packages/@aws-cdk/aws-ssm/lib/parameter.ts create mode 100644 packages/@aws-cdk/aws-ssm/test/integ.parameter.lit.expected.json create mode 100644 packages/@aws-cdk/aws-ssm/test/integ.parameter.lit.ts create mode 100644 packages/@aws-cdk/aws-ssm/test/test.parameter.ts diff --git a/packages/@aws-cdk/aws-ssm/README.md b/packages/@aws-cdk/aws-ssm/README.md index 393827933993f..a292d7a8d441e 100644 --- a/packages/@aws-cdk/aws-ssm/README.md +++ b/packages/@aws-cdk/aws-ssm/README.md @@ -1,2 +1,25 @@ ## The CDK Construct Library for AWS Systems Manager This module is part of the [AWS Cloud Development Kit](https://github.com/awslabs/aws-cdk) project. + +### Installation +Install the module: + +```console +$ npm i @aws-cdk/aws-ssm +``` + +Import it into your code: + +```ts +import ssm = require('@aws-cdk/aws-ssm'); +``` + +### Creating SSM Parameters +You can use either the `ssm.StringParameter` or `ssm.StringListParameter` (AWS CloudFormation does not support creating +*Secret-String* SSM parameters, as those would require the secret value to be inlined in the template document) classes +to register new SSM Parameters into your application: + +[creating SSM parameters](test/integ.parameter.lit.ts) + +When specifying an `allowedPattern`, the values provided as string literals are validated against the pattern and an +exception is raised if a value provided does not comply. diff --git a/packages/@aws-cdk/aws-ssm/lib/index.ts b/packages/@aws-cdk/aws-ssm/lib/index.ts index 7555a57315970..e1ed1ca33b93a 100644 --- a/packages/@aws-cdk/aws-ssm/lib/index.ts +++ b/packages/@aws-cdk/aws-ssm/lib/index.ts @@ -1,3 +1,4 @@ +export * from './parameter'; export * from './parameter-store-string'; // AWS::SSM CloudFormation Resources: diff --git a/packages/@aws-cdk/aws-ssm/lib/parameter.ts b/packages/@aws-cdk/aws-ssm/lib/parameter.ts new file mode 100644 index 0000000000000..0ac30159b28d4 --- /dev/null +++ b/packages/@aws-cdk/aws-ssm/lib/parameter.ts @@ -0,0 +1,220 @@ +import iam = require('@aws-cdk/aws-iam'); +import cdk = require('@aws-cdk/cdk'); +import ssm = require('./ssm.generated'); + +/** + * An SSM Parameter reference. + */ +export interface IParameter extends cdk.IConstruct { + /** + * The ARN of the SSM Parameter resource. + */ + readonly parameterArn: string; + + /** + * The name of the SSM Parameter resource. + */ + readonly parameterName: string; + + /** + * The type of the SSM Parameter resource. + */ + readonly parameterType: string; + + /** + * Grants read (DescribeParameter, GetParameter, GetParameterHistory) permissions on the SSM Parameter. + * + * @param grantee the role to be granted read-only access to the parameter. + */ + grantRead(grantee: iam.IRole): IParameter; + + /** + * Grants write (PutParameter) permissions on the SSM Parameter. + * + * @param grantee the role to be granted write access to the parameter. + */ + grantWrite(grantee: iam.IRole): IParameter; +} + +/** + * A String SSM Parameter. + */ +export interface IStringParameter extends IParameter { + /** + * A reference to the value of the SSM Parameter resource. + */ + readonly parameterValue: string; +} + +/** + * A StringList SSM Parameter. + */ +export interface IStringListParameter extends IParameter { + /** + * A reference to the value of the SSM Parameter resource. + */ + readonly parameterValue: string[]; +} + +/** + * Properties needed to create a new SSM Parameter. + */ +export interface ParameterProps { + /** + * The allowed pattern for values of this parameter. + * + * @default no validation is performed + */ + allowedPattern?: string; + + /** + * A user-friendly description for the parameter. + * + * @default none + */ + description?: string; + + /** + * Name of the parameter. + * + * @default a name will be generated by CloudFormation + */ + name?: string; +} + +/** + * Properties needed to create a String SSM parameter. + */ +export interface StringParameterProps extends ParameterProps { + /** + * The value of the parameter. It may not reference another parameter and ``{{}}`` cannot be used in the value. + */ + value: string; +} + +/** + * Properties needed to create a StringList SSM Parameter + */ +export interface StringListParameterProps extends ParameterProps { + /** + * The values of the parameter. It may not reference another parameter and ``{{}}`` cannot be used in the value. + */ + value: string[]; +} + +/** + * Basic features shared across all types of SSM Parameters. + */ +export abstract class Parameter extends cdk.Construct implements IParameter { + public abstract readonly parameterName: string; + public abstract readonly parameterType: string; + + constructor(scope: cdk.Construct, id: string, _props: ParameterProps) { + super(scope, id); + } + + public get parameterArn(): string { + return cdk.Stack.find(this).formatArn({ + service: 'ssm', + resource: 'parameter', + resourceName: this.parameterName, + }); + } + + public grantRead(grantee: iam.IRole): IParameter { + grantee.addToPolicy(new iam.PolicyStatement() + .allow() + .addActions('ssm:DescribeParameters', 'ssm:GetParameter', 'ssm:GetParameterHistory') + .addResource(this.parameterArn)); + return this; + } + + public grantWrite(grantee: iam.IRole): IParameter { + grantee.addToPolicy(new iam.PolicyStatement() + .allow() + .addAction('ssm:PutParameter') + .addResource(this.parameterArn)); + return this; + } +} + +/** + * Creates a new String SSM Parameter. + */ +export class StringParameter extends Parameter implements IStringParameter { + public readonly parameterName: string; + public readonly parameterType: string; + public readonly parameterValue: string; + + constructor(scope: cdk.Construct, id: string, props: StringParameterProps) { + super(scope, id, props); + + if (props.allowedPattern) { + _assertValidValue(props.value, props.allowedPattern); + } + + const resource = new ssm.CfnParameter(this, 'Resource', { + allowedPattern: props.allowedPattern, + description: props.description, + name: props.name, + type: 'String', + value: props.value, + }); + + this.parameterName = resource.parameterName; + this.parameterType = resource.parameterType; + this.parameterValue = resource.parameterValue; + } +} + +/** + * Creates a new StringList SSM Parameter. + */ +export class StringListParameter extends Parameter implements IStringListParameter { + public readonly parameterName: string; + public readonly parameterType: string; + public readonly parameterValue: string[]; + + constructor(scope: cdk.Construct, id: string, props: StringListParameterProps) { + super(scope, id, props); + + if (props.value.find(str => str.indexOf(',') !== -1)) { + throw new Error('Values of a StringList SSM Parameter cannot contain the \',\' character. Use a string parameter instead.'); + } + + if (props.allowedPattern) { + props.value.forEach(str => _assertValidValue(str, props.allowedPattern!)); + } + + const resource = new ssm.CfnParameter(this, 'Resource', { + allowedPattern: props.allowedPattern, + description: props.description, + name: props.name, + type: 'StringList', + value: props.value.join(','), + }); + + this.parameterName = resource.parameterName; + this.parameterType = resource.parameterType; + this.parameterValue = [resource.parameterValue]; + } +} + +/** + * Validates whether a supplied value conforms to the allowedPattern, granted neither is an unresolved token. + * + * @param value the value to be validated. + * @param allowedPattern the regular expression to use for validation. + * + * @throws if the ``value`` does not conform to the ``allowedPattern`` and neither is an unresolved token (per + * ``cdk.unresolved``). + */ +function _assertValidValue(value: string, allowedPattern: string): void { + if (cdk.unresolved(value) || cdk.unresolved(allowedPattern)) { + // Unable to perform validations against unresolved tokens + return; + } + if (!new RegExp(allowedPattern).test(value)) { + throw new Error(`The supplied value (${value}) does not match the specified allowedPattern (${allowedPattern})`); + } +} diff --git a/packages/@aws-cdk/aws-ssm/package.json b/packages/@aws-cdk/aws-ssm/package.json index ac3683dc56aaf..0311cdd773e66 100644 --- a/packages/@aws-cdk/aws-ssm/package.json +++ b/packages/@aws-cdk/aws-ssm/package.json @@ -54,8 +54,10 @@ }, "license": "Apache-2.0", "devDependencies": { + "@aws-cdk/aws-iam": "^0.21.0", "@aws-cdk/assert": "^0.21.0", "cdk-build-tools": "^0.21.0", + "cdk-integ-tools": "^0.21.0", "cfn2ts": "^0.21.0", "pkglint": "^0.21.0" }, @@ -64,9 +66,24 @@ }, "homepage": "https://github.com/awslabs/aws-cdk", "peerDependencies": { + "@aws-cdk/aws-iam": "^0.21.0", "@aws-cdk/cdk": "^0.21.0" }, "engines": { "node": ">= 8.10.0" + }, + "awslint": { + "exclude": [ + "export:@aws-cdk/aws-ssm.IParameter", + "import-props-interface:@aws-cdk/aws-ssm.ParameterImportProps", + "resource-attribute:@aws-cdk/aws-ssm.IParameter.parameterValue", + + "*:@aws-cdk/aws-ssm.Association", + "*:@aws-cdk/aws-ssm.Document", + "*:@aws-cdk/aws-ssm.MaintenanceWindow", + "*:@aws-cdk/aws-ssm.MaintenanceWindowTask", + "*:@aws-cdk/aws-ssm.PatchBaseline", + "*:@aws-cdk/aws-ssm.ResourceDataSync" + ] } } diff --git a/packages/@aws-cdk/aws-ssm/test/integ.parameter.lit.expected.json b/packages/@aws-cdk/aws-ssm/test/integ.parameter.lit.expected.json new file mode 100644 index 0000000000000..367e4e8d3ab32 --- /dev/null +++ b/packages/@aws-cdk/aws-ssm/test/integ.parameter.lit.expected.json @@ -0,0 +1,97 @@ +{ + "Resources": { + "UserRoleB7C3739B": { + "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" + } + } + }, + "UserRoleDefaultPolicyBC5E062B": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "ssm:DescribeParameters", + "ssm:GetParameter", + "ssm:GetParameterHistory" + ], + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":ssm:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":parameter/", + { + "Ref": "StringParameter472EED0E" + } + ] + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "UserRoleDefaultPolicyBC5E062B", + "Roles": [ + { + "Ref": "UserRoleB7C3739B" + } + ] + } + }, + "StringParameter472EED0E": { + "Type": "AWS::SSM::Parameter", + "Properties": { + "Type": "String", + "Value": "Initial parameter value" + } + }, + "StringListParameterFAC8EDDC": { + "Type": "AWS::SSM::Parameter", + "Properties": { + "Type": "StringList", + "Value": "Initial parameter value A,Initial parameter value B" + } + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-ssm/test/integ.parameter.lit.ts b/packages/@aws-cdk/aws-ssm/test/integ.parameter.lit.ts new file mode 100644 index 0000000000000..8044160a51f23 --- /dev/null +++ b/packages/@aws-cdk/aws-ssm/test/integ.parameter.lit.ts @@ -0,0 +1,33 @@ +import iam = require('@aws-cdk/aws-iam'); +import cdk = require('@aws-cdk/cdk'); +import ssm = require('../lib'); + +const app = new cdk.App(); +const stack = new cdk.Stack(app, 'SSM-Parameter'); + +const role = new iam.Role(stack, 'UserRole', { + assumedBy: new iam.AccountRootPrincipal(), +}); + +/// !show +// Create a new SSM Parameter holding a String +const param = new ssm.StringParameter(stack, 'StringParameter', { + // description: 'Some user-friendly description', + // name: 'ParameterName', + value: 'Initial parameter value', + // allowedPattern: '.*', +}); + +// Grant read access to some Role +param.grantRead(role); + +// Create a new SSM Parameter holding a StringList +new ssm.StringListParameter(stack, 'StringListParameter', { + // description: 'Some user-friendly description', + // name: 'ParameterName', + value: ['Initial parameter value A', 'Initial parameter value B'], + // allowedPattern: '.*', +}); +/// !hide + +app.run(); diff --git a/packages/@aws-cdk/aws-ssm/test/test.parameter.ts b/packages/@aws-cdk/aws-ssm/test/test.parameter.ts new file mode 100644 index 0000000000000..fb985eea620de --- /dev/null +++ b/packages/@aws-cdk/aws-ssm/test/test.parameter.ts @@ -0,0 +1,103 @@ +import { expect, haveResource } from '@aws-cdk/assert'; +import cdk = require('@aws-cdk/cdk'); +import { Test } from 'nodeunit'; +import ssm = require('../lib'); + +export = { + 'creating a String SSM Parameter'(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new ssm.StringParameter(stack, 'Parameter', { + allowedPattern: '.*', + description: 'The value Foo', + name: 'FooParameter', + value: 'Foo', + }); + + // THEN + expect(stack).to(haveResource('AWS::SSM::Parameter', { + AllowedPattern: '.*', + Description: 'The value Foo', + Name: 'FooParameter', + Type: 'String', + Value: 'Foo', + })); + test.done(); + }, + + 'String SSM Parameter rejects invalid values'(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + + // THEN + test.throws(() => new ssm.StringParameter(stack, 'Parameter', { allowedPattern: '^Bar$', value: 'FooBar' }), + /does not match the specified allowedPattern/); + test.done(); + }, + + 'String SSM Parameter allows unresolved tokens'(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + + // THEN + test.doesNotThrow(() => new ssm.StringParameter(stack, 'Parameter', { allowedPattern: '^Bar$', value: new cdk.Token(() => 'Foo!').toString() })); + test.done(); + }, + + 'creating a StringList SSM Parameter'(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + + // WHEN + new ssm.StringListParameter(stack, 'Parameter', { + allowedPattern: '(Foo|Bar)', + description: 'The values Foo and Bar', + name: 'FooParameter', + value: ['Foo', 'Bar'], + }); + + // THEN + expect(stack).to(haveResource('AWS::SSM::Parameter', { + AllowedPattern: '(Foo|Bar)', + Description: 'The values Foo and Bar', + Name: 'FooParameter', + Type: 'StringList', + Value: 'Foo,Bar', + })); + test.done(); + }, + + 'StringList SSM Parameter values cannot contain commas'(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + + // THEN + test.throws(() => new ssm.StringListParameter(stack, 'Parameter', { value: ['Foo,Bar'] }), + /cannot contain the ',' character/); + test.done(); + }, + + 'StringList SSM Parameter rejects invalid values'(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + + // THEN + test.throws(() => new ssm.StringListParameter(stack, 'Parameter', { allowedPattern: '^(Foo|Bar)$', value: ['Foo', 'FooBar'] }), + /does not match the specified allowedPattern/); + test.done(); + }, + + 'StringList SSM Parameter allows unresolved tokens'(test: Test) { + // GIVEN + const stack = new cdk.Stack(); + + // THEN + test.doesNotThrow(() => new ssm.StringListParameter(stack, 'Parameter', { + allowedPattern: '^(Foo|Bar)$', + value: ['Foo', new cdk.Token(() => 'Baz!').toString()] + })); + test.done(); + }, +}; From d7a1c323a0b26f9f0a127aac660e50ff6888c1a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=F0=9F=91=A8=F0=9F=8F=BC=E2=80=8D=F0=9F=92=BB=20Romain=20M?= =?UTF-8?q?arcadier-Muller?= Date: Mon, 4 Feb 2019 18:21:29 +0100 Subject: [PATCH 2/3] PR feedback --- packages/@aws-cdk/aws-ssm/lib/parameter.ts | 32 +++++++++---------- .../test/integ.parameter.lit.expected.json | 23 +++++++++++++ .../aws-ssm/test/integ.parameter.lit.ts | 6 +++- 3 files changed, 44 insertions(+), 17 deletions(-) diff --git a/packages/@aws-cdk/aws-ssm/lib/parameter.ts b/packages/@aws-cdk/aws-ssm/lib/parameter.ts index 0ac30159b28d4..948b40104167b 100644 --- a/packages/@aws-cdk/aws-ssm/lib/parameter.ts +++ b/packages/@aws-cdk/aws-ssm/lib/parameter.ts @@ -26,14 +26,14 @@ export interface IParameter extends cdk.IConstruct { * * @param grantee the role to be granted read-only access to the parameter. */ - grantRead(grantee: iam.IRole): IParameter; + grantRead(grantee: iam.IPrincipal): void; /** * Grants write (PutParameter) permissions on the SSM Parameter. * * @param grantee the role to be granted write access to the parameter. */ - grantWrite(grantee: iam.IRole): IParameter; + grantWrite(grantee: iam.IPrincipal): void; } /** @@ -41,7 +41,7 @@ export interface IParameter extends cdk.IConstruct { */ export interface IStringParameter extends IParameter { /** - * A reference to the value of the SSM Parameter resource. + * The parameter value. Value must not nest another parameter. Do not use {{}} in the value. */ readonly parameterValue: string; } @@ -51,7 +51,8 @@ export interface IStringParameter extends IParameter { */ export interface IStringListParameter extends IParameter { /** - * A reference to the value of the SSM Parameter resource. + * The parameter value. Value must not nest another parameter. Do not use {{}} in the value. Values in the array + * cannot contain commas (``,``). */ readonly parameterValue: string[]; } @@ -61,21 +62,22 @@ export interface IStringListParameter extends IParameter { */ export interface ParameterProps { /** - * The allowed pattern for values of this parameter. + * A regular expression used to validate the parameter value. For example, for String types with values restricted to + * numbers, you can specify the following: ``^\d+$`` * * @default no validation is performed */ allowedPattern?: string; /** - * A user-friendly description for the parameter. + * Information about the parameter that you want to add to the system. * * @default none */ description?: string; /** - * Name of the parameter. + * The name of the parameter. * * @default a name will be generated by CloudFormation */ @@ -105,7 +107,7 @@ export interface StringListParameterProps extends ParameterProps { /** * Basic features shared across all types of SSM Parameters. */ -export abstract class Parameter extends cdk.Construct implements IParameter { +export abstract class ParameterBase extends cdk.Construct implements IParameter { public abstract readonly parameterName: string; public abstract readonly parameterType: string; @@ -121,27 +123,25 @@ export abstract class Parameter extends cdk.Construct implements IParameter { }); } - public grantRead(grantee: iam.IRole): IParameter { + public grantRead(grantee: iam.IPrincipal): void { grantee.addToPolicy(new iam.PolicyStatement() .allow() .addActions('ssm:DescribeParameters', 'ssm:GetParameter', 'ssm:GetParameterHistory') .addResource(this.parameterArn)); - return this; } - public grantWrite(grantee: iam.IRole): IParameter { + public grantWrite(grantee: iam.IPrincipal): void { grantee.addToPolicy(new iam.PolicyStatement() .allow() .addAction('ssm:PutParameter') .addResource(this.parameterArn)); - return this; } } /** * Creates a new String SSM Parameter. */ -export class StringParameter extends Parameter implements IStringParameter { +export class StringParameter extends ParameterBase implements IStringParameter { public readonly parameterName: string; public readonly parameterType: string; public readonly parameterValue: string; @@ -170,7 +170,7 @@ export class StringParameter extends Parameter implements IStringParameter { /** * Creates a new StringList SSM Parameter. */ -export class StringListParameter extends Parameter implements IStringListParameter { +export class StringListParameter extends ParameterBase implements IStringListParameter { public readonly parameterName: string; public readonly parameterType: string; public readonly parameterValue: string[]; @@ -178,7 +178,7 @@ export class StringListParameter extends Parameter implements IStringListParamet constructor(scope: cdk.Construct, id: string, props: StringListParameterProps) { super(scope, id, props); - if (props.value.find(str => str.indexOf(',') !== -1)) { + if (props.value.find(str => !cdk.unresolved(str) && str.indexOf(',') !== -1)) { throw new Error('Values of a StringList SSM Parameter cannot contain the \',\' character. Use a string parameter instead.'); } @@ -196,7 +196,7 @@ export class StringListParameter extends Parameter implements IStringListParamet this.parameterName = resource.parameterName; this.parameterType = resource.parameterType; - this.parameterValue = [resource.parameterValue]; + this.parameterValue = cdk.Fn.split(',', resource.parameterValue); } } diff --git a/packages/@aws-cdk/aws-ssm/test/integ.parameter.lit.expected.json b/packages/@aws-cdk/aws-ssm/test/integ.parameter.lit.expected.json index 367e4e8d3ab32..63a0524cb13e2 100644 --- a/packages/@aws-cdk/aws-ssm/test/integ.parameter.lit.expected.json +++ b/packages/@aws-cdk/aws-ssm/test/integ.parameter.lit.expected.json @@ -93,5 +93,28 @@ "Value": "Initial parameter value A,Initial parameter value B" } } + }, + "Outputs": { + "StringListOutput": { + "Value": { + "Fn::Join": [ + "+", + { + "Fn::Split": [ + ",", + { + "Fn::GetAtt": [ + "StringListParameterFAC8EDDC", + "Value" + ] + } + ] + } + ] + }, + "Export": { + "Name": "SSM-Parameter:StringListOutput" + } + } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-ssm/test/integ.parameter.lit.ts b/packages/@aws-cdk/aws-ssm/test/integ.parameter.lit.ts index 8044160a51f23..8719f2bee9c8b 100644 --- a/packages/@aws-cdk/aws-ssm/test/integ.parameter.lit.ts +++ b/packages/@aws-cdk/aws-ssm/test/integ.parameter.lit.ts @@ -22,7 +22,7 @@ const param = new ssm.StringParameter(stack, 'StringParameter', { param.grantRead(role); // Create a new SSM Parameter holding a StringList -new ssm.StringListParameter(stack, 'StringListParameter', { +const listParameter = new ssm.StringListParameter(stack, 'StringListParameter', { // description: 'Some user-friendly description', // name: 'ParameterName', value: ['Initial parameter value A', 'Initial parameter value B'], @@ -30,4 +30,8 @@ new ssm.StringListParameter(stack, 'StringListParameter', { }); /// !hide +new cdk.Output(stack, 'StringListOutput', { + value: cdk.Fn.join('+', listParameter.parameterValue), +}); + app.run(); From b4f94c81c6e1feb31d2d5902e8ff3d7d11e43f8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=F0=9F=91=A8=F0=9F=8F=BC=E2=80=8D=F0=9F=92=BB=20Romain=20M?= =?UTF-8?q?arcadier-Muller?= Date: Tue, 5 Feb 2019 09:23:35 +0100 Subject: [PATCH 3/3] Add'l fix --- packages/@aws-cdk/aws-ssm/lib/parameter.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/@aws-cdk/aws-ssm/lib/parameter.ts b/packages/@aws-cdk/aws-ssm/lib/parameter.ts index 948b40104167b..c45a74e3b82c0 100644 --- a/packages/@aws-cdk/aws-ssm/lib/parameter.ts +++ b/packages/@aws-cdk/aws-ssm/lib/parameter.ts @@ -182,7 +182,7 @@ export class StringListParameter extends ParameterBase implements IStringListPar throw new Error('Values of a StringList SSM Parameter cannot contain the \',\' character. Use a string parameter instead.'); } - if (props.allowedPattern) { + if (props.allowedPattern && !cdk.unresolved(props.value)) { props.value.forEach(str => _assertValidValue(str, props.allowedPattern!)); }