Secrets and configuration management with AWS Parameter Store

How we found a solution for effective secrets management

Paolo Ferretti
Growens Innovation Blog
3 min readJun 17, 2021

--

One of the big challenges of modern software development is about the security of our code and, therefore, our applications.

Probably one of the pillars of secure code is the correct management of secrets and configuration settings. These are plain-text strings, so they should be simple to manage. In this simplicity, however, we should keep in mind these three principles:

  • confidentiality: only users with permissions must access the data
  • integrity: data must not be altered by unauthorized users
  • availability: data is available to authorized users when they need it

Most of Growens’ infrastructure is on AWS, so we ended up choosing AWS Systems Manager Parameter Store.

What is Parameter Store?

This is a service that provides a centralized store to manage configuration data. Values can be stored as plain-text or encrypted data.

Every value is identified by a unique name and parameters can be organized in hierarchies and version tracked.

Why Parameter Store?

There are a lot of alternatives, like HashiCorp Vault. Parameter Store is a very good service and it has a very good integration with a lot of AWS services.
All the external services evaluated by our team required a lot of work for the integration with our AWS infrastructure. The cost wasn’t worth the benefit.
In addition to this, we consider the secret and configuration management a core part of our system, so the excellent integration of Parameter Store with our infrastructure was an invaluable feature.

What about our three security pillars?

All the three principles are respected: confidentiality and integrity are provided by IAM Policies attached to Roles and Users, while availability is guaranteed by the Parameter Store APIs.

The implementation

The management of our keys with Parameter Store is very straigthforward. We defined a pattern for generic keys, something like:

/[type]/[environment]/[service]/[key]/[subkey]

Where:

  • type is the root of the tree: inventory for generic keys, app for specific applications keys
  • environment is something like dev, pre, qa, pro
  • service is name of the service like postgresql, rabbitmq or microservice proper name
  • key (optional) is the entity, something similar to service and relative to the service itself. Useful, for example, to define keys for database access specific to a microservice (example below)
  • subkey is the last leaf of our tree, so the key name itself like user, password, host, etc…

Here some examples:

/inventory/pre/rabbitmq/management/host
/inventory/pre/rabbitmq/management/user
/inventory/pre/rabbitmq/management/password
/app/qa/single_sign_on/db/host
/app/qa/single_sign_on/db/user
/app/qa/single_sign_on/db/password

So, in our hypotetical single_sign_on application, for qa environment we need to do basically two things: configure an IAM Role for our application and ask Parameter Store API the path /app/qa/single_sign_on/*. With these simple two steps we have all our configurations and secrets with a single API call.

The IAM Policy, for example, could be:

{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"kms:Decrypt",
"ssm:GetParametersByPath"
],
"Resource": [
"arn:aws:kms:*:*:key/your-key",
"arn:aws:ssm:*:*:parameter/app/qa/single_sign_on/*"
],
"Effect": "Allow",
"Sid": "VisualEditor0"
}
]
}

No secrets or configurations hardcoded in our settings files: this happens at runtime with an on-the-fly authentication thanks to IAM Roles.

--

--