English

How to import multiple secret environment variables to ECS tasks using CDK Typescript

CloudNation Enable. Empower. Deliver.
Publish date: 20 July 2022

Our very own cloud consultant Kevin Gallas has been working on several application migrations, using AWS Cloud Development Kit (CDK). In this blog he shares his learnings, tips and tricks with you.

Importing multiple secret environment variables to ECS tasks using CDK. CloudNation Knows How.

 

Importing secret environment variables to ECS tasks using CDK TypeScript

AWS Secrets Manager is a great service to securely store passwords, API keys, and other content you don’t want to place in a more public location like a repository. If you want to use secret environment variables in your ECS app, then wIth just a few lines of CDK, and zero adaptations to your application, you can add secret environment variables to your ECS applications!

No need to hassle around with permissions to fetch the secret (less work & less error prone!)

In this blog I will show you how to import sensitive data from the Secrets Manager as environment variables into the “secrets” ECS container definition parameter using CDK Typescript. This example web application will display the injected environment variables on its webpage.

Step 1: Create a Secret

Create the secret in the Secrets Manager in the AWS console. In this example I have created a secret named “this-is-an-example-secret” with three key-value pairs inside.

Step 2: Create a CDK app.

For testing purposes, I’ve based the CDK code on the AWS tutorial “Getting started with Amazon ECS using the AWS CDK”: https://docs.aws.amazon.com/AmazonECS/latest/userguide/tutorial-ecs-web-server-cdk.html. You will only have to follow step 1 for this and copy the code snippet from step 2 to your lib/hello-ecs-stack.ts.

Step 3: Add a customized Dockerfile

For this part I have based the Dockerfile on the tutorial https://docs.aws.amazon.com/AmazonECS/latest/userguide/create-container-image.html .

Add a file named Dockerfile to the root of your app’s directory. Add the following to this Dockerfile:

FROM ubuntu:18.04 

# Install dependencies

RUN apt-get update && \
apt-get -y install apache2 

# Install apache and write hello world message

RUN echo 'Hello World!' > /var/www/html/index.html

# This will write the env variables of the container to the webpage

RUN echo 'My env is \n' && env >> /var/www/html/index.html 

# Configure apache

RUN echo '. /etc/apache2/envvars' > /root/run_apache.sh && \
echo 'mkdir -p /var/run/apache2' >> /root/run_apache.sh && \
echo 'mkdir -p /var/lock/apache2' >> /root/run_apache.sh && \
echo '/usr/sbin/apache2 -D FOREGROUND' >> /root/run_apache.sh && \
chmod 755 /root/run_apache.sh EXPOSE 80 CMD /root/run_apache.sh

Step 4: Create a list of the keys you want to import into the container

The content of the secret retrieved from AWS Secrets Manager will be seen as one json structure containing all the key-value pairs. To separate this into individual key-value pairs to inject into the containers' environment, you can create a file, containing the names of the keys you want to retrieve from the secrets value. An advantage of this is that you can have multiple applications using the same Secrets Manager secret that need specified key-value pairs from that secret.

In this case, a file named env.secret_keys has to be created containing the three keys of the key-value pairs we want to inject into the container. When you are injecting a lot of variables, having them declared in a separate list will make your code a bit more readable.

SECRET_PASSWORD
SECRET_API_KEY
SECRET_VARIABLE

Step 5: Adjust the CDK Code to import the secret into the container’s definition parameter

In this step, I will show you what each code snippets functionality is in the lib/hello-ecs-app.ts file. First we'll define the the extra packages to import:

import * as secretsmanager from 'aws-cdk-lib/aws-secretsmanager';
import * as ecs from 'aws-cdk-lib/aws-ecs';
import * as fs from 'fs';

To get the keys of the key-value pairs you want to inject as environment variables into the container, read the “keys-list” created in step 4 and create a list in the CDK code:

// Read the list in the fileconst

secretKeysFromFile = fs.readFileSync(`./env.secret_keys`, 'utf8') 

// Create a list of the keys

let listOfKeys: string[] = []   secretKeysFromFile.split(/\r?\n/).forEach(line => {     listOfKeys.push(line)   });

Then, the list of keys can be used to create a secret class to pass to the container.

Be sure to add the full Arn of your secret, since the CDK method fromSecretNameV2 does not seem to retrieve the entire Secret ARN (https://github.com/aws/aws-cdk/issues/18555 ). You can create a constant at the beginning of your program and reference it here.

// Declare this constant at the beginning of your program

const secretArn = arn:aws:secretsmanager:eu-central-1:111111111:secret:this-is-an-example-secret-cwUGjW` 

let ecsSecrets: { [key: string]: ecs.Secret } = {}listOfKeys.forEach(secret => {

let ecsSecret: secretsmanager.ISecret = secretsmanager.Secret.fromSecretCompleteArn(   this,    `my-example-secret-${secret}`,   secretArn) ecsSecrets[secret] = ecs.Secret.fromSecretsManager(ecsSecret, secret);

})

This created secret class can then be passed on to the ECS Pattern

new ecsp.ApplicationLoadBalancedFargateService(this, 'MyWebServer', {

taskImageOptions: {  

secrets: ecsSecrets,  
image: ecs.ContainerImage.fromDockerImageAsset(new ecr_assets.DockerImageAsset(this, 'MyContainerImageAsset', {    

directory: './'  

}),

)},

publicLoadBalancer: true

});

Step 6: Deploy the CDK app

If you are connected to an AWS account on your cli, using cdk synth should show you the Cloudformation template created from the CDK code.

When you think the templates seem correct, you can deploy the application with cdk deploy

The results

If everything works correctly, you can access the application using the Loadbalancer DNS address in a browser and see a webpage like this:

As you can see, the three “secret” variables SECRET_VARIABLE, SECRET_API_KEY, and SECRET_PASSWORD are now shown in the overview, created by the env command on the container.

Disclaimer: Don’t display the containers' environment variables of your actual production applications on a web page. Keep them nice and secure inside of the containers.

References:

https://docs.aws.amazon.com/AmazonECS/latest/userguide/tutorial-ecs-web-server-cdk.html

https://docs.aws.amazon.com/AmazonECS/latest/userguide/create-container-image.html

Full code example:

https://github.com/GallibHub/ecs-with-secretsmanager-variables-example

Want to know more? Get in touch with Bart.

We want to share knowledge.

Let's talk
CloudNation, Contact met Bart
CloudNation Enable. Empower. Deliver.
Publish date: 20 July 2022

More facts, updates and howto's about the cloud