AWS SSM Variables in serverless.yml

I have a question about accessing SSM parameters are variables in the serverless.yml file - I’ve hit something I’m having trouble finding an existing answer for, and apologize if I missed it somewhere.
I keep getting “A valid SSM parameter to satisfy the declaration 'ssm:<variable-name>' could not be found.” I’ve verified/tried the following:

  • <variable-name> is a path within the parameter store that exists, and starts with a “/”
  • <variable-name> includes the in-file variables ${self:provider.stage} and ${self:service}, but these appear to have resolved correctly as they are replaced in the value provided by the error message
  • The parameter exists in the same region as the stack, and is not encrypted
  • I have tried adding both the read-only and full-access policies for my serverless user
  • I have been unable to find doc about requirements aside from the basic how-to-reference doc
  • I found two GitHub issues that might be relevant (4053,4744), unfortunately they are failing to load (GitHub unicorn strikes again!), but they are closed in previous versions

Can anyone point me in the right direction? Is there doc elsewhere I can dig through for more information?
Thanks!

Does this help?

I use SSM but from lambda not cloudformation.

Look in .serverless and check the fully expanded cloudformation syntax serverless is uploading to AWS.

It’s actually throwing that warning when I run serverless info as well as deploy - as far as I can tell it’s serverless doing it, not the CloudFormation stack on the AWS side. Regardless, I’ll read through this and see if anything seems relevant - thanks!

Cloudformation can call lambda functions. I just made a little JS function that does the messy stuff in Javascript.

functions:
KeysResource:
role: vapidRole
handler: vapidkeys.handler


const response = require(‘cfn-response’);
const webpush = require(‘web-push’);
const AWS = require(“aws-sdk”);
const ssm = new AWS.SSM();

exports.handler = function(event, context) {
console.log(event);

if (event.RequestType == “Update”) {
let keys = webpush.generateVAPIDKeys();
var params = {
Name: ‘/VAPID/’ + event.ResourceProperties.Stage + ‘/publicKey’, /* required */
Type: ‘SecureString’,
Value: keys.publicKey,
Description: ‘VAPID public key for server push’,
Overwrite: true
};
ssm.putParameter(params, function(err, data) {
if (err) console.log(err, err.stack); // an error occurred
else console.log(data); // successful response
});
params.Name = ‘/VAPID/’ + event.ResourceProperties.Stage + ‘/privateKey’;
params.Value = keys.privateKey;
params.Description = “VAPID private key for server push”
ssm.putParameter(params, function(err, data) {
if (err) console.log(err, err.stack); // an error occurred
else console.log(data); // successful response
});
return response.send(event, context, response.SUCCESS, {
VAPIDPublicKey: keys.publicKey
});
} else {
return response.send(event, context, response.SUCCESS, {
VAPIDPublicKey: ‘’
});
}
};

I’m not sure I follow the relevance of CloudFormation access to lambda functions to the problem described - the issue I am seeing is with trying to use a parameter within AWS parameter store (SSM) within the serverless.yml file, as per the notation documented here: https://serverless.com/framework/docs/providers/aws/guide/variables#reference-variables-using-the-ssm-parameter-store

As far as I am aware, that doesn’t involve Lambda calling CloudFormation or vice versa (though I could certainly be wrong about that)

That being said, thank you for taking the time to make an example to try to clarify your suggestion for me!

I see now what you want. I ignored that feature in YAML and used code in my lambdas to directly fetch the SSM variables.

I don’t remember exactly why now, but I believe I did it because when you bring them in as environment variables they are sitting around unencrypted where a hacker can get to them. When you do it in code you can decrypt them and then immediately delete them.

Another benefit of calling via code from within the Lambda is if the value in SSM changes, then next instance of the Lambda will pick up the change versus being in the serverless.yml which would require a re-deploy.

I am actually already pulling some variables within the Lambda (secured ones, for exactly the reasons pointed out by @jonsmirl).
I wanted to provide this one via environment because it isn’t likely to change much, and based on some logging/testing I did, it can take over a second to read from SSM, which in my very short 3/4 second runtime is significant (basically, since I don’t need the live-update for this one, I was hoping to avoid the trade-off in execution time it incurs)
At the moment, reading from within the lambda is how I am working around the issue - was mainly hoping someone could specify any “gotchas” they found with using the feature, since I can’t get it to work at all as-documented (required roles for the configured serverless user, etc, that may not be documented)