Credentials and sensitive variables allow access to confidential data and must be protected from unauthorized access so only permitted entities can access them. AWS Fargate is a technology that can be used with Amazon ECS to run containers. AWS Fargate is commonly used to run workloads to interact with databases or access confidential data or services. Security best practice demands that credentials enabling access to such confidential data must not be stored in the container or in the code inside the container. Instead, they must use cloud-native solutions like AWS Secrets Manager secret. Role-based access control must also be employed to manage who or what can access credentials. In this note, I explain how to store sensitive variables in the AWS Secrets Manager secret and securely access them from an AWS Fargate task container. This use case has five steps:
1. Store a sensitive variable as a secret in AWS Secrets Manager 2. Create a VPC Endpoint to access AWS Secrets Manager 3. Update the Amazon ECS task definition to access the secret 4. Create an IAM permission policy and attach it to the task roles to access the secret 5. Update the Node.js application to access and display the secret
After implementing these five steps, GitHub Actions pipelines will deploy these changes to the AWS cloud environment.
Please note that displaying or logging sensitive variable values is not a recommended security best practice. I display that to demonstrate that the Fargate task can access the secret.
In this note, I build upon the concepts discussed in my previous three notes. If you are unfamiliar with Amazon ECS and want to learn about the service in detail, I recommend going through these three notes. If you need more time to explore these, go through the last note, where I explain the primary services you will be working with in this note -Amazon ECS Service, ECS task definition, and the two IAM roles.
1. Provision of the underlying infrastructure to host an Amazon ECS service. 2. Push a Docker image to Amazon Elastic Container Registry (Amazon ECR). 3. Create a service/task from the Docker image and host it on Amazon ECS.
I have the Terraform code to create and manage these AWS Cloud resources in my GitHub repository. So, if you are interested and want to follow along, here is a link to my code repository on GitHub: kunduso/add-aws-ecr-ecs-fargate. Please note that the branch name = create-ecs-service
.
Step 1: Store a sensitive variable as a secret in AWS Secrets Manager
The below Terraform code adds an AWS Secrets Manager secret resource and updates the latest version with the value from var.ecs_secret
.
The value of the variable
ecs_secret
must not be stored in Terraform code as plain text since it is sensitive and inaccessible to all. In this use case, the value is stored as a GitHub Secret and passed to Terraform using the GitHub Actions pipeline step, as shown below.
I have a separate note explaining how to manage sensitive credentials with AWS Secrets Manager, Terraform, and GitHub Actions.
Step 2: Create a VPC Endpoint to access AWS Secrets Manager
The AWS Fargate containers are hosted in the private subnet and, hence, do not have access to the internet. Adding a VPC endpoint to access AWS Secrets Manager enables the request and response traffic to remain within the Amazon network.
Step 3: Update the Amazon ECS task definition to access the secret
The ECS task definition is the blueprint of the ECS service. It defines the Docker image, CPU and memory requirements, networking configuration, and other settings for the tasks in the service. One such setting in the container_definitions
is the secrets
configuration that holds the name
and the source(valueFrom
) of the secret.
To access all the properties in an Amazon ECS task definition template, choose ECS-task-definition-template, and for a detailed description of the properties, choose Amazon-ECS-task-definition-parameters.
Step 4: Create an IAM permission policy and attach it to the task roles to access the secret
There are two IAM roles in this use case - the task execution role and the task role. The task execution role must have the permission to create the Amazon ECS service along with a few other mandatory permissions that are included in the AWS Managed policy arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy
. The managed policy is attached to the task execution role. I followed the recommendations in Task Execution IAM Role: Private registry authentication permissions and created the IAM policy.
Since the Amazon ECS task definition refers to the AWS Secrets Manager resource, I attached the IAM permission policy to the task execution role.
Per AWS Docs, Amazon ECS tasks can have an associated IAM role. The permissions granted in the IAM role are assumed by the containers running in the task. This role allows the application code (on the container) to use other AWS services. In this use case, the
Node.js
application in the Docker container hosted in AWS Fargate interacts with the AWS Secrets Manager to access and decrypt the secret. Hence, I attached the IAM permission policy to the task role.
Step 5: Update the Node.js application to access and display the secret
The logic to access the AWS Secrest Manager secret is in the
secrets.js
file in the Node.js
application that is hosted inside a Docker container.
And, the step to display the value of the secret is in the
home.handlebars
file.
Please note, as I stated earlier, that displaying or logging secrets is poor programming practice. I am only doing that to demonstrate the process of accessing secrets in the AWS Fargate task.
Once all the code was updated, I deployed the changes individually. There are two deployment pipelines:
- The AWS Secrets Manager secret and the VPC endpoint Terraform configuration are inside the Infrastructure stack in the \infra
folder and deployed using the GitHub Actions pipeline: terraform-infra-provisioning.
- The Node.js
application and the Amazon ECS service are deployed via the multi-job GitHub Actions pipeline: docker-build-deploy.
After the GitHub Actions pipelines deployed these changes into the AWS cloud, I logged into the AWS console and navigated to Amazon Elastic Container Service → Cluster = app-6 → Service - app-6 → Tab = Tasks.
The Health status of “Healthy” meant that the containers were up and responding successfully to the HealthCheck rule. I have a separate note demonstrating how to add HealthCheck to the AWS Fargate task.
With the HealthCheck passing, I navigated to the Load balancer, copied its DNS name, pasted it into the internet browser (Google Chrome), and followed it with the port number, which is 8080. I was greeted with the message below.
As you can see, the homepage correctly displayed the Secret Value. To validate, you can log in to the AWS Console → Secrets Manager and change the value of the secret. After you refresh the DNS URL in your browser, you’ll examine the updated password.
That brings us to the end of this note. I hope you can follow along and learn how to access the AWS Secrets Manager secret from an AWS Fargate task container. Please do not hesitate to contact me via the comments if you have any questions or suggestions.