Versioning, hierarchy and advanced parameters in Parameter Store

Sessions provide one way of authenticating users. Session data is stored on the server while the session id is placed in a cookie. With this, each subsequent request has the identifier of the session, and the server will know that it can make private content available for the user.

AWS Parameter Store is a fully-managed service for storing strings, string lists and encrypted strings.

It’s an important building block in securing applications. Stored secrets can be detached from the application and can be used by multiple services.

1. Assumptions

1.1. Account and CLI

You’ll need to have a free AWS account, user credentials for programmatic access to AWS services and the AWS CLI installed on your computer if you want to successfully submit the following CLI commands.

You’ll also need the necessary IAM permissions to create, update and delete parameters. If you are an admin user in your account, this won’t be an issue.

1.2. Parameter

I’ll use the secret I created for the last post. If you don’t have a secret stored in Parameter Store, you can quickly create one:

aws ssm put-parameter --name JWT-Secret --type SecureString --value 'secret-string'

I can check if I have a parameter in the Parameter Store:

aws ssm describe-parameters

This command should return an object similar to this:

{
  "Parameters": [
    {
      "Name": "JWT-Secret",
      "Type": "SecureString",
      "KeyId": "alias/aws/ssm",
      "LastModifiedDate": 1575153932.655,
      "LastModifiedUser": "arn:aws:iam::123456789123:user/<USER>",
      "Version": 1,
      "Tier": "Standard",
      "Policies": []
    }
  ]
}

The response shows everything I need to know about parameters. Most of these properties will be discussed below.

The Type of the parameter can be String, StringList or SecureString. Secure strings are encrypted using KMS while strings and string lists (comma separated strings) are not.

2. Versioning

Versioning in Parameter Store (just like in any other services supporting versions) protects the user from accidentally overriding parameters.

Let’s prove this statement by making another PutParameter API call. This time I’ll try to overwrite the value of JWT-Secret:

aws ssm put-parameter --name JWT-Secret --type SecureString --value 'another-string'

Parameter Store should return a ParameterAlreadyExists error, which means (guess what) that the parameter already exists, which is absolutely true because I’ve just created one with the same name.

By default Parameter Store assign version 1 to a new parameter. I’ll need to use the overwrite option to update the parameter, hence I’ll create a new version:

aws ssm put-parameter --name JWT-Secret --type SecureString \\
--value 'another-value' --overwrite

overwrite is a boolean option with the default setting being true, so I don’t need to explicitly define the value.

The response should show the version:

{
  "Version": 2
}

From now on, if I call the DescribeParameters API (or any API that returns the parameter), the response will show the latest version:

aws ssm describe-parameters

This command will result in something similar:

{
  "Parameters": [
    {
      "Name": "JWT-Secret",
      "Type": "SecureString",
      "KeyId": "alias/aws/ssm",
      "LastModifiedDate": 1575834019.215,
      "LastModifiedUser": "arn:aws:iam::123456789123:user/<USER>",
      "Version": 2,
      "Tier": "Standard",
      "Policies": []
    }
  ]
}

If you are not convinced, I can show you the value of the parameter:

aws ssm get-parameter --name JWT-Secret --with-decryption

The response confirms that I have received the latest version (2):

{
  "Parameter": {
    "Name": "JWT-Secret",
    "Type": "SecureString",
    "Value": "another-value",
    "Version": 2,
    "LastModifiedDate": 1575834019.215,
    "ARN": "arn:aws:ssm:us-west-2:123456789123:parameter/JWT-Secret"
  }
}

But if I explicitly state which version I want to get, I can display the old value of the parameter:

aws ssm get-parameter --name JWT-Secret:1 --with-decryption

Now I have version 1:

{
  "Parameter": {
    "Name": "JWT-Secret",
    "Type": "SecureString",
    "Value": "secret-string",
    "Version": 1,
    "Selector": ":1",
    "LastModifiedDate": 1575153932.655,
    "ARN": "arn:aws:ssm:us-west-2:123456789123:parameter/JWT-Secret"
  }
}

The with-decryption option will display the decrypted secure string. If this option is not stated, the encrypted secret will be displayed.

3. Hierarchy

Hierarchy in Parameter Store means that I name the parameter as a path starting with the / character.

This way the parameters are easier to manage (especially if I already have thousands of parameters) and search.

JWT-Secret is a root level parameter because it doesn’t contain any paths in the name.

But I could have used a hierarchy structure instead. For example, a popular way to organize parameters looks like this:

/ENVIRONMENT/APPLICATION/PARAMETER

In practice, this means that I name my parameter like /dev/my-app/JWT-Secret or /staging/my-app/JWT-Secret. This way I can refer to the parameter in my code as such:

const params = {
  Name: `/${process.env.ENVIRONMENT}/my-app/JWT-Secret`,
};

const secret = (await ssm.getParameter(params).promise()).Parameter.Value;

ENVIRONMENT can be dev, staging or production or whatever I want (I usually want these, though).

Now I feel better and more organized that I create my parameters this way, but hierarchy brings me other benefits.

I can search parameters by path:

aws ssm get-parameters-by-path --path /dev/my-app

The GetParametersByPath API call will return all parameters under the /dev/my-app path. If I have 22 parameters starting with /dev/my-app, the API response will contain 22 parameters. This is more than just cool.

On the top of that, it’s possible to create IAM policies and allow/deny access to path parameters. This feature has the advantage of allowing developers to access dev and staging parameters, but denying access to everything in production.

4. Advanced parameters

The third feature I discuss today is the tier of the parameter.

By default Parameter Store creates standard parameters. They can hold a maximum of 4 kB data and they all come for free.

Sometimes I want to store more than 4 kB, or it can happen that the size of an existing parameter will go above 4 kB. If this is the case, I need to create an advanced parameter.

I can upgrade a standard parameter to an advanced one but I can’t go backwards. This has some practical reasons, for example, the size of the parameter will be truncated down to 4 kB and there will be a data loss.

Advanced parameters can store up to 8 kB, which is still not that much, but it’s more than enough for storing secrets, passwords, URLs etc. Parameter Store is not suitable for storing long essays.

Advanced parameters cost money: it’s 5 cents per month, which is pro-rated if the parameter is less than a month old. They also use parameter policies.

To create advanced parameters I’ll need to specify the tier option (the default value is standard):

aws ssm put-parameter --name /dev/my-app/Advanced-Secret --type SecureString \\
--value 'advanced secret-string' --tier Advanced

There’s a third option for tier, which is the Intelligent-Tiering. This option will take a look at the parameter and based on the length and the defined options Parameter Store will place the parameter into either the Standard or Advanced tier.

5. Summary

Parameter Store is a flexible and secure service to store secrets and other important strings.

It offers versioning, hierarchy for better organization and advanced tier for advanced use cases.

Thanks for reading and see you next time.