SSM parameter store: Keeping secret information structured

Post • 4 min read

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 and it 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 truly 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 your parameter will be stored in an encrypted way and you'll 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 & Tagging

One of the 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 ;). Parameters are also tagged, which is a neat addition to group and target resources based on some common tag values. Paths Now for the juicy nice part. Parameters can be named either by a simple string, or a path. When you use paths — you introduce hierarchy for your parameters. This makes it easy to group parameters by stage, app or whatever structure you can think of. SSM allows you to use 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 this:

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

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

Docker Case Study

Let’s go through a case study. If you have ever configured an app in a docker container, you probably needed to give away some secret information, like DB password, or some external services keys or tokens.

Rails app is a good example. Here, DB information is 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 the 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 entry point 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. In this way, the variables will be there when the rails server starts so the database.yml file will get them. Easy peasy.

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 an 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 Practice & 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.
If you would like to contact Nordcloud to find out more, contact us here.
Nordcloud ninja
NordcloudLinkedInNinja

Get in Touch.

Let’s discuss how we can help with your cloud journey. Our experts are standing by to talk about your migration, modernisation, development and skills challenges.

Ilja Summala
Ilja’s passion and tech knowledge help customers transform how they manage infrastructure and develop apps in cloud.
Ilja Summala LinkedIn
Group CTO