SSM Parameter Store for keeping secrets in a structured way

Dariusz Dwornikowski
Nordcloud Engineering
4 min readMar 25, 2018

AWS Systems Manager Parameter Store (SSM) provides you with a secure way to store config variables for your applications. You can access SSM via AWS API directly from within the app or just use from AWS CLI. SSM can store plaintext parameters or KMS encrypted secure strings. Since parameters are identified by ARNs, you can set a fine grain access control to your configuration bits with IAM. A truely versatile service !

Common use cases of SSM are storing configuration for Docker containers initialisation during the runtime, storing secrets for Lambda functions and app, and even using SSM Parameters in CloudFormation.

Parameters

You can set the parameters via AWS Console or CLI:

aws ssm put-paramater --name "DB_NAME" --value "myDb" 

If you want to store a secure string parameter, you add the KMS key id and set a type to SecureString . Now you parameter will be stored in an encrypted way. You will be able to read it only if your IAM policy allows.

aws ssm put-parameter --name "DB_PASSWORD" --value "secret123" --type SecureString --key-id 333be3e-fb33-333e-fb33-3333f7b33f3

Mind that KMS limits apply here, SecureString can’t be larger than 4096 bytes in size

Getting parameters is also easy

aws ssm get-parameter --name "DB_NAME" 

If you want to get an encrypted one, add --with-decryption . SSM will automatically decrypt the parameter on the fly and you will get the plain text value.

Versioning and tagging

One of cool features of SSM Parameters is that they are versioned, moreover you can see who or what created which version. This way you can fix buggy apps or human mistakes, or at least blame a colleague who made a mistake 😜.

Versioned SSM Parameters with audit info

Parameters are also tagged, which is a neat addition to group and target resources based on some common tag value.

Paths

Now to the juicy nice part. Parameters can be named either by a simple string or a path. When you use path — you introduce hierarchy on your parameters. This makes it easy to group parameters by stage, app or whatever structure you imagine. SSM allows you to get parameters by path.

Let’s say we have parameters:

  • /myapp/production/DB_NAME
  • /myapp/production/DB_PASSWORD
  • /myapp/production/DB_USERNAME

In order to get all of them you would do:

aws ssm get-parameters-by-path --with-decryption --path /myapp/production

This will produce you with a JSON array containing all of the parameters above. Parameters might be encrypted or plaintext, --with-decryption has no effect on plaintext parameters so you always will get a list of plaintext params.

Docker case study

Let’s go through some case study. If you ever configured an app in a docker container, you probably needed to pass some secrets, like db password, some external services keys or tokens.

Rails app is a good example. There, DB secrets are stored in a file called database.yml residing in the app config directory. In Rails you can populate the config file with environment variables which will be read upon start and populated.

production:
adapter: 'postgresql'
database: <%= ENV['DB_NAME'] %>
username: <%= ENV['DB_USERNAME'] %>
password: <%= ENV['DB_PASSWORD'] %>
host: <%= ENV['DB_HOST'] %>
port: 5432

We can store these parameters in SSM, as encrypted secure strings, under a common path: /app/production/db/{DB_NAME, DB_USERNAME, DB_PASSWORD, DB_HOST} . Naturally, different environments will get different paths — with testing, staging etc.

In the docker entrypoint script we can populate the variables before the rails server starts. First we will get the parameters, then we will export them as environment variables. This ways, the variables will be there when rails server starts so the database.yml file will get them. Easy peasy.

Example docker-enrtypoint.sh

First we get all parameters within the /app/production/db . Since this is a JSON output we use jq to extract the parameter name and value. We construct a line export PARAM_NAME=PARAM_VALUE already in jq. Since the name is a path — and it can’t be used as a env variable name, in the next step we use sed to cut out the path from the name, leaving the env name alone. The whole one liner is being evaluated — and effectively the variables are set in this script. Rails server can read them and the app can connect to the database. Voila. End of story.

Best practices and caveats

I use SSM Parameters wherever I need to store something, below are some arbitrary best practices that I think make sense with SSM Parameter Store

  1. Do not use default KMS keys, create your own for the SSM usage, you will get better IAM policies if you keep all of it within one IaC codebase
  2. Use least privileged principle, give your app access to app specific parameters, you can limit access using path in Resource section in IAM Policy.
  3. You can’t use SecureString as CloudFormation parameter yet, you would have to code a custom resource for it.
  4. Name your parameters in a concise way and use paths, it will allow you to delete old and not needed parameters and avoid namespace clash.

--

--

Dariusz Dwornikowski
Nordcloud Engineering

Building products and technology in cloud. Ex VP Engineering at Nordcloud, now CTO at Worksuite.