From 392450a203a7c84c2170ef4d853c53da33f2d46c Mon Sep 17 00:00:00 2001 From: Jeremy Giberson Date: Tue, 24 Mar 2020 14:34:55 -0700 Subject: [PATCH] add a flag to ssm variables to resolve as string instead of object --- docs/providers/aws/guide/variables.md | 20 ++++++++++++++++++++ lib/classes/Variables.js | 12 +++++++++--- lib/classes/Variables.test.js | 18 ++++++++++++++++++ 3 files changed, 47 insertions(+), 3 deletions(-) diff --git a/docs/providers/aws/guide/variables.md b/docs/providers/aws/guide/variables.md index 1f814091ab8..fc99665699c 100644 --- a/docs/providers/aws/guide/variables.md +++ b/docs/providers/aws/guide/variables.md @@ -354,6 +354,26 @@ custom: - false ``` +If the variable value is valid JSON but you expect the plaintext form, then you can use the extended syntax `~decryptAsPlaintext`. + +``` +custom: + supersecret: ${ssm:/aws/reference/secretsmanager/secret_ID_in_Secrets_Manager~decryptAsPlaintext} +``` + +variables will be resolved like + +```yml +service: new-service +provider: aws +functions: + hello: + name: hello + handler: handler.hello +custom: + supersecret: '{"num": 1,"str": "secret","arr": [true, false]}' # a plain text string +``` + ## Reference Variables in Other Files You can reference variables in other YAML or JSON files. To reference variables in other YAML files use the `${file(./myFile.yml):someProperty}` syntax in your `serverless.yml` configuration file. To reference variables in other JSON files use the `${file(./myFile.json):someProperty}` syntax. It is important that the file you are referencing has the correct suffix, or file extension, for its file type (`.yml` for YAML or `.json` for JSON) in order for it to be interpreted correctly. Here's an example: diff --git a/lib/classes/Variables.js b/lib/classes/Variables.js index 992fa63c0a3..92ceee6a045 100644 --- a/lib/classes/Variables.js +++ b/lib/classes/Variables.js @@ -54,7 +54,7 @@ class Variables { this.stringRefSyntax = RegExp(/(?:('|").*?\1)/g); this.cfRefSyntax = RegExp(/^(?:\${)?cf(\.[a-zA-Z0-9-]+)?:/g); this.s3RefSyntax = RegExp(/^(?:\${)?s3:(.+?)\/(.+)$/); - this.ssmRefSyntax = RegExp(/^(?:\${)?ssm:([a-zA-Z0-9_.\-/]+)[~]?(true|false|split)?/); + this.ssmRefSyntax = RegExp(/^(?:\${)?ssm:([a-zA-Z0-9_.\-/]+)[~]?(true|false|split|decryptAsPlaintext)?/); } loadVariableSyntax() { @@ -761,8 +761,10 @@ class Variables { getValueFromSsm(variableString) { const groups = variableString.match(this.ssmRefSyntax); const param = groups[1]; - const decrypt = groups[2] === 'true'; + const decrypt = groups[2] === 'true' || groups[2] === 'decryptAsPlaintext'; const split = groups[2] === 'split'; + const decryptAsPlaintext = groups[2] === 'decryptAsPlaintext'; + return this.serverless .getProvider('aws') .request( @@ -778,8 +780,12 @@ class Variables { const plainText = response.Parameter.Value; const type = response.Parameter.Type; // Only if Secrets Manager. Parameter Store does not support JSON. + // if decryptAsPlaintext skip json parsing // We cannot parse StringList types, so don't try - if (type !== 'StringList' && param.startsWith('/aws/reference/secretsmanager')) { + if (type !== 'StringList' + && param.startsWith('/aws/reference/secretsmanager') + && ! decryptAsPlaintext + ) { try { const json = JSON.parse(plainText); return BbPromise.resolve(json); diff --git a/lib/classes/Variables.test.js b/lib/classes/Variables.test.js index ea34d5aed7f..9d8bd0781b2 100644 --- a/lib/classes/Variables.test.js +++ b/lib/classes/Variables.test.js @@ -2290,6 +2290,24 @@ module.exports = { .then() .finally(() => ssmStub.restore()); }); + it('should get value as text if extended syntax matches ~decryptAsPlaintext', () => { + const secretParam = '/aws/reference/secretsmanager/foo-bar'; + const jsonLikeText = '{"str":"abc","num":123}'; + + const awsResponse = { + Parameter: { + Value: jsonLikeText, + }, + }; + const ssmStub = sinon + .stub(awsProvider, 'request') + .callsFake(() => BbPromise.resolve(awsResponse)); + return serverless.variables + .getValueFromSsm(`ssm:${secretParam}~decryptAsPlaintext`) + .should.become(jsonLikeText) + .then() + .finally(() => ssmStub.restore()); + }); it('should get value as text if returned value is NOT json-like', () => { const secretParam = '/aws/reference/secretsmanager/foo-bar'; const plainText = 'I am plain text';