One of the nice things about running your container workloads on AWS ECS is the ability to use AWS Systems Manager Parameters to store sensitive values and inject them into your containers as Docker secrets.

This is a more secure option because your sensitive variables do not need to be accessible from your deployment tools, they only have to be available from the ECS/EC2 instance using an IAM role. For our example, we are going to use Terraform to create the SSM Parameter, and the service that consumes it. Also, injecting the wrong endpoint configuration into the wrong environment becomes a thing of the past.

We will need to make sure that the EC2 instance is configured to talk to the Systems Manager and has permission to pull parameter values.

Step 1: Configure SSM Agent

You’ll want to configure the SSM Agent on your ECS nodes, preferably in the user data file. Example:

# install pip
curl -O
python --user
export PATH=~/.local/bin:$PATH

# install AWS CLI
pip install --upgrade --user awscli
export PATH=/home/ec2-user/.local/bin:$PATH

# install SSM Agent and dependencies
sudo yum install -y
sudo yum install -y polkit

# install cloudwatch agent
curl -o amazon-cloudwatch-agent.rpm 
sudo rpm -U ./amazon-cloudwatch-agent.rpmCode language: PHP (php)

Step 2: IAM Role Permissions

Whatever role your EC2 instances launch with will need to have access to retrieve SSM Parameter Store params. Example IAM policy:

    "Version": "2012-10-17",
    "Statement": [
            "Effect": "Allow",
            "Action": [
            "Resource": "*"
            "Effect": "Allow",
            "Action": [
            "Resource": "arn:aws:ssm:us-east-1:<accountid>:parameter/*"
}Code language: JSON / JSON with Comments (json)

Now your EC2 instances have permission to call SSM, and they also have the AWS CLI and SSM Agent installed. Now we need to create some parameters. You can use the Amazon console for this, but for this example we are using Terraform.

Step 3: Create a SSM Parameter

SSM Parameters lend well to a nested path naming structure. In this example, we use parameters separated by environment and application.

locals {

resource "aws_ssm_parameter" "db_host" {
  name  = "/production/myapp/db-host"
  type  = "String"
  value = "${local.db_host}"
}Code language: JavaScript (javascript)

Don’t forget to run:

>terraform plan


>terraform apply

Step 4: Inject SSM Parameter into ECS

In your task definition, add each value in a secrets block, using valueFrom instead of value, with an ARN reference to your parameter.

, "secrets": [
            "name": "DB_HOST",
            "valueFrom": "arn:aws:ssm:${var.aws_region}:<account_id>:parameter/production/myapp/db-host"
    ]Code language: JavaScript (javascript)

Using this technique, access to sensitive information is much more restrictive than if you were keeping these values within your code. Developers only need environment variables for local development, and container orchestration can handle injecting the right value for the right app in the right environment for hosted applications. Secrets are now on a “need to know” basis. Fantastic!

May 21 20