Skip to content

Commit

Permalink
fix(ssm): StringParameter.fromStringParameterAttributes cannot accept…
Browse files Browse the repository at this point in the history
… version as a numeric Token (#16048)

In `StringParameter.fromStringParameterAttributes()` and `StringParameter.fromSecureStringParameterAttributes()` the version of a parameter can be specified using data type number.
If a token value (e.g. CloudFormation Parameter) was used here, the token was not resolved correctly.

The conversion of property `version` was corrected by using method `Tokenization.stringifyNumber()`.

Fixes #11913.

----

*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
  • Loading branch information
jumic authored Aug 24, 2021
1 parent a1a65bc commit eb54cd4
Show file tree
Hide file tree
Showing 4 changed files with 109 additions and 2 deletions.
5 changes: 3 additions & 2 deletions packages/@aws-cdk/aws-ssm/lib/parameter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import * as cxschema from '@aws-cdk/cloud-assembly-schema';
import {
CfnDynamicReference, CfnDynamicReferenceService, CfnParameter,
Construct as CompatConstruct, ContextProvider, Fn, IResource, Resource, Stack, Token,
Tokenization,
} from '@aws-cdk/core';
import { Construct } from 'constructs';
import * as ssm from './ssm.generated';
Expand Down Expand Up @@ -324,7 +325,7 @@ export class StringParameter extends ParameterBase implements IStringParameter {
const type = attrs.type || ParameterType.STRING;

const stringValue = attrs.version
? new CfnDynamicReference(CfnDynamicReferenceService.SSM, `${attrs.parameterName}:${attrs.version}`).toString()
? new CfnDynamicReference(CfnDynamicReferenceService.SSM, `${attrs.parameterName}:${Tokenization.stringifyNumber(attrs.version)}`).toString()
: new CfnParameter(scope as CompatConstruct, `${id}.Parameter`, { type: `AWS::SSM::Parameter::Value<${type}>`, default: attrs.parameterName }).valueAsString;

class Import extends ParameterBase {
Expand All @@ -341,7 +342,7 @@ export class StringParameter extends ParameterBase implements IStringParameter {
* Imports a secure string parameter from the SSM parameter store.
*/
public static fromSecureStringParameterAttributes(scope: Construct, id: string, attrs: SecureStringParameterAttributes): IStringParameter {
const stringValue = new CfnDynamicReference(CfnDynamicReferenceService.SSM_SECURE, `${attrs.parameterName}:${attrs.version}`).toString();
const stringValue = new CfnDynamicReference(CfnDynamicReferenceService.SSM_SECURE, `${attrs.parameterName}:${Tokenization.stringifyNumber(attrs.version)}`).toString();

class Import extends ParameterBase {
public readonly parameterName = attrs.parameterName;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@
},
{
"Parameters": {
"MyParameterVersion": {
"Type": "Number",
"Default": 1
},
"MyValueParameter": {
"Type": "AWS::SSM::Parameter::Value<String>",
"Default": "/My/Public/Parameter"
Expand All @@ -28,6 +32,20 @@
"Value": {
"Ref": "MyValueParameter"
}
},
"TheValueVersionFromToken": {
"Value": {
"Fn::Join": [
"",
[
"{{resolve:ssm:/My/Public/Parameter:",
{
"Ref": "MyParameterVersion"
},
"}}"
]
]
}
}
}
}
Expand Down
20 changes: 20 additions & 0 deletions packages/@aws-cdk/aws-ssm/test/integ.parameter-store-string.lit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,27 +17,47 @@ class UsingStack extends cdk.Stack {
constructor(scope: cdk.App, id: string) {
super(scope, id);

// Parameter that contains version number, will be used to pass
// version value from token.
const parameterVersion = new cdk.CfnParameter(this, 'MyParameterVersion', {
type: 'Number',
default: 1,
}).valueAsNumber;

/// !show
// Retrieve the latest value of the non-secret parameter
// with name "/My/String/Parameter".
const stringValue = ssm.StringParameter.fromStringParameterAttributes(this, 'MyValue', {
parameterName: '/My/Public/Parameter',
// 'version' can be specified but is optional.
}).stringValue;
const stringValueVersionFromToken = ssm.StringParameter.fromStringParameterAttributes(this, 'MyValueVersionFromToken', {
parameterName: '/My/Public/Parameter',
// parameter version from token
version: parameterVersion,
}).stringValue;

// Retrieve a specific version of the secret (SecureString) parameter.
// 'version' is always required.
const secretValue = ssm.StringParameter.fromSecureStringParameterAttributes(this, 'MySecureValue', {
parameterName: '/My/Secret/Parameter',
version: 5,
});
const secretValueVersionFromToken = ssm.StringParameter.fromSecureStringParameterAttributes(this, 'MySecureValueVersionFromToken', {
parameterName: '/My/Secret/Parameter',
// parameter version from token
version: parameterVersion,
});

/// !hide

new cdk.CfnResource(this, 'Dummy', { type: 'AWS::SNS::Topic' });
new cdk.CfnOutput(this, 'TheValue', { value: stringValue });
new cdk.CfnOutput(this, 'TheValueVersionFromToken', { value: stringValueVersionFromToken });

// Cannot be provisioned so cannot be actually used
Array.isArray(secretValue);
Array.isArray(secretValueVersionFromToken);
}
}

Expand Down
68 changes: 68 additions & 0 deletions packages/@aws-cdk/aws-ssm/test/test.parameter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,40 @@ export = {
test.done();
},

'StringParameter.fromStringParameterAttributes with version from token'(test: Test) {
// GIVEN
const stack = new cdk.Stack();

// WHEN
const param = ssm.StringParameter.fromStringParameterAttributes(stack, 'MyParamName', {
parameterName: 'MyParamName',
version: cdk.Token.asNumber({ Ref: 'version' }),
});

// THEN
test.deepEqual(stack.resolve(param.parameterArn), {
'Fn::Join': ['', [
'arn:',
{ Ref: 'AWS::Partition' },
':ssm:',
{ Ref: 'AWS::Region' },
':',
{ Ref: 'AWS::AccountId' },
':parameter/MyParamName',
]],
});
test.deepEqual(stack.resolve(param.parameterName), 'MyParamName');
test.deepEqual(stack.resolve(param.parameterType), 'String');
test.deepEqual(stack.resolve(param.stringValue), {
'Fn::Join': ['', [
'{{resolve:ssm:MyParamName:',
{ Ref: 'version' },
'}}',
]],
});
test.done();
},

'StringParameter.fromSecureStringParameterAttributes'(test: Test) {
// GIVEN
const stack = new cdk.Stack();
Expand Down Expand Up @@ -372,6 +406,40 @@ export = {
test.done();
},

'StringParameter.fromSecureStringParameterAttributes with version from token'(test: Test) {
// GIVEN
const stack = new cdk.Stack();

// WHEN
const param = ssm.StringParameter.fromSecureStringParameterAttributes(stack, 'MyParamName', {
parameterName: 'MyParamName',
version: cdk.Token.asNumber({ Ref: 'version' }),
});

// THEN
test.deepEqual(stack.resolve(param.parameterArn), {
'Fn::Join': ['', [
'arn:',
{ Ref: 'AWS::Partition' },
':ssm:',
{ Ref: 'AWS::Region' },
':',
{ Ref: 'AWS::AccountId' },
':parameter/MyParamName',
]],
});
test.deepEqual(stack.resolve(param.parameterName), 'MyParamName');
test.deepEqual(stack.resolve(param.parameterType), 'SecureString');
test.deepEqual(stack.resolve(param.stringValue), {
'Fn::Join': ['', [
'{{resolve:ssm-secure:MyParamName:',
{ Ref: 'version' },
'}}',
]],
});
test.done();
},

'StringParameter.fromSecureStringParameterAttributes with encryption key creates the correct policy for grantRead'(test: Test) {
// GIVEN
const stack = new cdk.Stack();
Expand Down

0 comments on commit eb54cd4

Please sign in to comment.