AWS SSM Parameter Store secrets management for Docker containers

Secure way to provide environment secrets to docker containers from AWS Parameter Store.

6 minute read

Storing and using secret information securely with AWS SSM

The SSM Parameters store is a great way to securely store hierarchical configuration data. It is widely used by AWS to provide parameters it own services. The names of the parameters are guaranteed to be unique and of arbitrary structure, allowing users to store nested structures of configuration data. In this post I will examine how to use Parameters Store efficiently to provide settings and secrets to Docker containers executed on ECS.

The code, examples and additional information for this post is available on the GitHub. The images instrumented with SSM bootstrap are available from the Docker hub.

AWS SSM Parameters Store Values

The SSM allows to use both single and list values for parameters. Optionally the value can be encrypted with the KMS key. The encryption allows user to keep environmental secrets in SSM, such as service to service authentication, docker registry auth strings, database credentials, X.509 keys and everything else that fits into the 4096 characters.

Values that do not fit into 4096 characters, can be stored into the S3 bucket and pre-signed access URL can be written into the SSM parameter instead.

Using the Parameter Store

The main approach to usage of the SSM parameters store is give your ECS task a role to access SSM API and call it on service start. The service itself is responsible for communication with SSM, in a safe and scalable way. This presents a natural problem in case of multiple services, probably written in different languages, each having a unique implementation of SSM nested structures reading code. It is better to decouple configuration and secrets retrieval logic from the application code with a formal contract. Environmental variables are the most common way to pass configuration values to the application code in the Docker containers and it is convenient to use them for SSM stored configuration as well.

Docker images and entrypoints

Application service packaged as Docker image can benefit from the use of intermediate base images which contain bootstrapping code and decouple secrets management from the application itself. The intermediate image can define an entrypoint, used to perform bootstrapping steps, communicate with AWS services are prepare container environment before executing the service code. The image itself can be based on a number of possible runtime environments: NodeJS, Ruby or Python. The entrypoint in docker image receives the CMD value of the image using it as a base, or an executable argument of docker run, and can invoke it directly after the setup. Below is an example of the intermediate Docker image adding SSM bootstrapping capability to an Alpine Linux based image, such as NodeJS’s node:alpine.


# Install python runtime for the bootstrap script
RUN apk update && \
    apk add python py-pip py-yaml && \
    pip install awscli && \
    pip install boto3

# Copy bootstrap scripts to image
COPY src/ /usr/bin/ssm-bootstrap
COPY src/ /usr/bin/kickstart
RUN chmod +x /usr/bin/ssm-bootstrap /usr/bin/kickstart

ENTRYPOINT /usr/bin/kickstart

Here we have an entrypoint defined as /usr/bin/kickstart script. This script will execute /usr/bin/ssm-bootstrap to communicate with SSM and save environment file and other files. Lets examine the contents of the /usr/bin/kickstart:

# query SSM parameters store for secrets and save files and environment variables
ssm-bootstrap --environ /tmp/app_environ --root /app/
[ -f /tmp/app_environ ] && . /tmp/app_environ

exec "$@"

The kickstart script uses /usr/bin/ssm-bootstrap to create /tmp/app_environ file, loads it as environment and passes execution to it’s arguments. So that executed process would inherit environment populated with data from the /tmp/app_environ file. Additionally /usr/bin/ssm-bootstrap would write a number of files at root path specified as --root argument. Such files can be various encryption keys, salts and certificates shared across your environments. Using SSM bootstrapping to provide files to Docker containers allows to avoid volume mounts to containers and specialization of your ECS host. Otherwise you have to bake such files into your an AMI or somehow persist on host’s filesystem from external storage, so that files could be volume mounted into running containers.

SSM Parameters Namespaces

The actual communications with SSM to retrieve environmental variables is done by the /usr/bin/ssm-bootstrap tool. It is the place where logic to build parameter paths is implemented and shared across all services based on the intermediate Docker image. The interface between infrastructure code and application code, defined as environment variables and (smallish) files, is implemented once and reused everywhere else. Potential structure of the parameter names can be arbitrary, but in general it is useful to have at least 2 nested levels of parameters:

  • ECS Cluster - Each service on a specific ECS cluster. The cluster scope corresponds to an instance of portable environment, usually CloudFormation stack(s).
  • ECS Service/Container name - Specific service on a specific ECS cluster.

Integration with the ECS

SSM bootstrap is using ECS metadata file determine the cluster and container name it is executed for. It must be enabled in your ecs.config on cluster instances. When ECS runs Docker container, it makes metadata file available inside the container. This metadata contains cluster name and container name used by ECS.

Below is an example of the ECS Task Definition in CloudFormation, lets examine what configuration path are available to such service:

    Type: AWS::ECS::TaskDefinition
            - Name: example-service # The name of the service 
                Image: ...
                Essential: true
                    - ContainerPort: 8080
                    AWS_DEFAULT_REGION: !Ref AWS::Region

    Type: AWS::ECS::Cluster
        ClusterName: example-cluster # The name of the ECS cluster for parameter names

    Type: AWS::ECS::Service
        TaskDefinition: !Ref ExampleTask
        Cluster: !Ref ExampleCluster

Notice that parameter names are built using Cluster and ContainerName. This information about running container is read from ECS container metadata file, so this needs to be enabled in your ECS agent configuration. The source code for the /usr/bin/ssm-bootstrap utility can be found at the GitHub.

Name structure for nested configurations

With the configuration above the service would have the following paths in SSM injected into it’s environment:

  • /example-cluster/environment/variable
  • /example-cluster/example-service/environment/variable

Also the following paths would be saved as files:

  • /example-cluster/files/filename
  • /example-cluster/example-service/files/filename

Task Role and Policy for SSM access

In order to access SSM API the task still needs to have a role allowing that. Below is an example of such role in CloudFormation syntax.

  Type: AWS::IAM::Role
    RoleName: ExampleTaskRole
      Version: 2012-10-17
      - Effect: Allow
        - sts:AssumeRole

  Type: AWS::IAM::Policy
    - !Ref ExampleTaskRole
    PolicyName: ExamplePolicy
      Version: 2012-10-17
      - Action:
        - kms:Decrypt
        Resource: !Sub "arn:aws:kms:${AWS::Region}:alias/my-key"
        Effect: Allow
      - Action:
        - ssm:GetParameter
        - ssm:GetParameters
        - ssm:DescribeParameters
        Resource: "arn:aws:ssm:*"
        Effect: Allow

Using published images

The images with SSM bootstrap middleware layer are published to the Docker Hub and available for general use. Simply specify the base image for your runtime in the FROM statement and your service will automatically receive configuration from the SSM Parameters Store. Below is an example of a generic Dockerfile for NodeJS based service:

FROM stan1y/ssm-bootstrap:node-alpine-latest

COPY src/ /app/src/
COPY .npmrc package.json /app/
RUN npm install && rm -f .npmrc

CMD npm start


A more complete code and examples are available in the project repository.

Detailed description of the SSM parameter store is available over Amazon documentation website.

comments powered by Disqus