AWS Parameter Store is a hidden gem in the vast array of AWS services. Most engineers will never notice it unless someone tells them about it. After all, it is inconspicuously located within the Systems Manager Shared Resources section of the EC2 Console.

The Parameter store can be used for storing parameter data and secrets. That data (secrets, licenses, application params, database connection strings) can then be passed from a central location to various resources like applications. It can be said it is the defacto standard of application-level storing secrets within AWS.

Sure you can use tools like HashiCorp Vault and avoid vendor lock-in, but the Parameter Store makes it so darn easy to store secrets and specify which user or instance can access them. And do note that I'm not bashing on Vault - I love the product and what it does. AWS just bakes a similar product in and takes all the guess work of building your own secrets vault.

Using AWS Parameter Store to Store Configuration Data

AWS Parameter Store Dashboard

AWS Parameter Store Dashboard

Of course the main point is that you can store configuration data in Parameter Store.

What sort of configuration data?

The one that your applications use! Database strings, passwords, memory settings, things that change in every environment.

You can use Parameter Store to hold various config parameters that your applications can then query using AWS API or AWS CLI. Many others have found it to be a good way to configure per-app and per-environment data in individual AWS accounts. Storing this data is so easy and what really expands upon this is the fact that you can secure it from other eyes!

And it can be used with EC2, EC2 Container Service, and Lambda!

Writing parameters:

$ aws ssm put-parameter --name "/service_a/key_a" --value "Hello World" \
    --description "Hello World test" --type String

Getting parameters:

$ aws ssm get-parameter --name "/service_a/key_a" --output json
{
    "Parameter": {
        "Type": "String",
        "Name": "/service_a/key_a",
        "Value": "Hello World!"
    }
}

Note that parameters can be nested within a hierarchy. This is awesome if you have multiple applications or app tiers within your single AWS account. Plus you can use the hierarchy to store versioned parameters.

$ aws ssm put-parameter --name "/qa/qa01/service_a/string_length" --value "255" \
    --description "configuration item #1" --type String
$ aws ssm get-parameter --name "/qa/qa01/service_a/string_length"
{
    "Parameter": {
        "Type": "String",
        "Name": "/qa/qa01/service_a/string_length",
        "Value": "255"
    }
}

Parameters can also be accessed by accessing the hierarchy with get-parameters-by-path command.

Securing Who Can Access Your Parameters

Since the Parameter Store is part of AWS ecosystem you gain the ability to tie it into other Amazon services. One of them is IAM and that's for the sake of access control.

You can use AWS IAM policies to limit who can access your parameters. Those policies can be assigned to IAM roles. Those roles can then be assigned to IAM users or EC2 instance to control which instance gets access to which parameters. This is a powerful feature that is hard to beat in on-premises implementations of various secret stores.

This is especially help ful when you want your Ops or dev team to be able to tweak certain application parameters without messing with the application code.

Below is a sample customer-managed policy that you can assign to an IAM role. This role can then be attached to an instance or a user. You can equate this policy to an ACL construct within HashiCorp's Vault - except you can attach this IAM policy to an instance instead of binding a policy to an authentication group in Vault.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "Stmt1506642855000",
      "Effect": "Allow",
      "Action": [
        "ssm:GetParameter",
        "ssm:GetParameters",
        "ssm:PutParameter"
      ],
      "Resource": [
        "arn:aws:ssm::${ACCOUNTID}:parameter/service_a/*"
      ]
    },
    {
      "Sid": "Stmt1506642993000",
      "Effect": "Allow",
      "Action": [
        "ssm:DescribeParameters"
      ],
      "Resource": [
        "*"
      ]
    }
  ]
}

This policy basically states that whoever object that holds it can describe all the parameters and then put/get specific ones within the/service_a/ hierarchy.

Storing Secrets

Parameter Store key values can be encrypted using encryption keys from the AWS KMS (Hooray!).  Go ahead and create a separate KMS key in IAM, and then select that key's ID when encrypting a secure string. The key ID will be automatically picked up when you request a decrypted value.

Storing a secret using AWS CLI:

aws ssm put-parameter --name "/qa/qa02/service_a/password" --value "password" \
    --description "test secure secret" --key-id XXXXXX-XXXX-XXXX-XXXX-XXXXX \
    --type SecureString --region us-east-1

Or using EC2 Console:

Storing an encrypted secret in AWS Parameter Store

Storing an encrypted secret in AWS Parameter Store

$ aws ssm get-parameter --name "/qa/qa02/service_a/password" \
    --region us-east-1 --with-decryption
{
    "Parameter": {
        "Type": "SecureString",
        "Name": "/qa/qa02/service_a/password",
        "Value": "password"
    }
}

And in python using the boto3 SDK:

>>> session = boto3.session.Session(region_name='us-east-1')
>>> ssm = session.client('ssm')
>>> password = ssm.get_parameter(Name='/qa/qa02/service_a/password', WithDecryption=True)
>>> print(password['Parameter']['Value'])
password

Conclusion

In the end Parameter Store is just too darn useful and well worth checking out. It's a powerful tool that not everyone knows about. But once you learn it, you will love it. Just the fact that you can store your application's parameters can be changed by authorized individuals or systems is alone a huge plus.


Comments

comments powered by Disqus