Deploying your container with secrets using AWS and CDK

Igor Soroka
FAUN — Developer Community 🐾
5 min readSep 2, 2021

The idea of this blog post came to me when I have realized that there are no good materials on an end-to-end example of deploying a Spring container with the Secrets by using modern infrastructure as a code solution. Here is the GitHub repository to follow along with the article. (cdk-ecs-fargate-spring-secrets) It will be handy to have the repository opened while reading the article.

What will be used in this article? The main tech stack will include:

  • CDK with TypeScript — as IaC tool
  • GitHub Actions for CI/CD
  • Docker for containerization
  • Spring app is written with Kotlin

This article can be a great start for using CDK with the real-world example where there is a need for API deployed with AWS. Here we will take a CDK application as an infrastructure that will be serverless in our case because of the Fargate usage. So we will create VPC, ECS, ELB with some secrets from SSM. The actual application with implementation is a Spring Boot with Kotlin. For the compilation and packaging Gradle is used.

Parts:

  • Setup CDK
  • Preparing container
  • CI/CD

CDK Setup

The AWS CDK is a package installed with npm:

npm install -g aws-cdk

Basically, that's the only thing you need to run cdk projects. The template project can be created with this:

mkdir my-project
cd my-project
mkdir infra
cd infra
cdk init app --language typescript

But in the repo, this is already done by me.

One more thing which I really recommend is to use npm for your CDK projects instead of yarn. By this, you will avoid the problem of installing dependencies of dependencies.

Before Deployment

We will need to complete several things to deploy the container. First of all, in the folder with the code, there should be a valid Dockerfile. You can try to build and run the container locally first. In my case, I used the spring boot Kotlin application and I will need to have a valid jar package also. In this case, building the jar will be by running:

./gradlew bootJar

We are using SSM parameters in this project. They are listed in the stack (link to file) as. For deployment to succeed your AWS account should have the SSM parameters with the exact path and type as it is in the typescript code. So, with the AWS-CLI one can create parameters with the following syntax.

For simple string:

aws ssm put-parameter — name "/dev/demo/user" — type "String" — value "super-duper-user"

For secured string (added encryption)

aws ssm put-parameter — name "/dev/demo/PASSWORD" — type "SecureString" — value "secret-password-123"

Here is an example of the task definition.

In the picture under the text, one can see that the variable defined in the 'environment' object in the task definition will be readable from AWS Console. However, the 'secrets' part is shown as the SSM arn only without any value. This is adding more security to your real secrets like passwords.

The best part is that with these environment variables there is no need to do any special manipulations. One will need just to retrieve the secrets. The values can be retrieved in Kotlin with one-liners:

var user = System.getenv("USER") ?: "default_value"
var password = System.getenv(“PASSWORD”) ?: “default_value”

Time to automate

In this repository, we will use GitHub Actions to make deployments. This is a great tool that can be natively integrated into the repository. You will need to create a folder with files.

However, before that, one will need to create a user on AWS with programmatic access and the ability to deploy the code. In most cases, the user for CI/CD should have access to CloudFormation and that's it. This policy is just an example. I am encouraging the reader not to use AdministratorAccess and make the access as granular as possible. The example policy could be looking like that:

{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "cloudformation:*",
"Resource": "*"
},
{
"Effect": "Allow",
"Action": "ecr:*",
"Resource": "*"
},
{
"Effect": "Allow",
"Action": "ssm:GetParameters",
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"ec2:*"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"logs:*"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"ecs:*"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"iam:*"
],
"Resource": "*"
}
]
}

In the final stage, you will see the AWS Access Key ID and Secret Access Key. Stay on this page and do not close it. I am suggesting using GitHub CLI to save the environment variables. Go to the root of the git repo from the beginning of the article. With your command line you can do this:

gh secret set AWS_ACCESS_KEY_ID — body <your  key id>gh secret set AWS_SECRET_ACCESS_KEY — body <your secret access key>gh secret set AWS_DEFAULT_REGION - body <your region>

It is the fastest way to put the environment variables in place for your repo. GitHub CLI has many other great possibilities. With it, you can clone repositories faster or create even issues!

After that, one will need to create `/.github/workflows/deploy.yml`. There is an example in the repo. GitHub will create a pipeline automatically. First, the Kotlin code should be built. After that, the infra part will be built. The deployment will be done as a final step.

Log in to the AWS console. Go to CloudFormation. Find 'CdkEcsFargateSpringSecretsStack'. In the Outputs part, any one of them will be the ones to access. When the pipeline is succeeded, one can go to the browser and check these endpoints:

http://***.***.elb.amazonaws.com/http://***.***.elb.amazonaws.com/secrets

Now the Spring application written in Kotlin is packed as a Docker container and deployed with Fargate. The CDK was used for deployment. For the secrets management, the SSM parameters were used and retrieved as environment variables (both encrypted and not).

CDK is a powerful tool for making life easier when it comes to infrastructure as code. Automation saves manpower for doing really amazing things. When it is coupled together with GitHub Actions there is an enormous amount of possibilities.

Enjoyed the article? Please, star the repository and put thumbs up. I also wrote a blog about my reflections on different infrastructures as code tools.

Join FAUN: Website 💻|Podcast 🎙️|Twitter 🐦|Facebook 👥|Instagram 📷|Facebook Group 🗣️|Linkedin Group 💬| Slack 📱|Cloud Native News 📰|More.

If this post was helpful, please click the clap 👏 button below a few times to show your support for the author 👇

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

--

--

Published in FAUN — Developer Community 🐾

We help developers learn and grow by keeping them up with what matters. 👉 www.faun.dev

Written by Igor Soroka

⚡ AWS Community Builder, 📺 wabi-sabi, 👨‍💻 Soroka Tech founder, 🏃 long-distance runner, 🇫🇮 Finland. Writing about tech, motivation, learning, and sports.

No responses yet

What are your thoughts?