How to pass param from Terraform to AWS ECS-powered app?
Using Terraform is a great way to keep configuration of infrastructure required by your application clean and manageable. What’s more, it greatly improves development velocity, when you can deploy new DynamoDB table or create SQS queue in almost no time. However, you need to somehow refer to just created infrastructure in the code, e.g. to send message to a SQS queue, you need to know its URL. The simplest possible solution of this problem would be to hardcode relevant address in app’s properties, but it means that each time you change it in Terraform file, you also need to change your properties file. Of course, better way of handling such cases exists. Did I catch your interest? Read on!
Example application
To clearly describe the problem we’ll try to solve together and to have something to work on, I prepared a sample application. It’s written with Micronaut framework, but all mechanisms we’ll be using are present in Spring-based apps as well, so presented solution is very easily transferable.
The application will be deployed to an AWS ECS cluster. This, as well as other infrastructure, has been prepared for the purposes of this article using Terraform scripts. Even though I won’t be describing how it all works in details, you’ll be able to find a link to GitHub repository at the end of this text and reproduce all described actions on your own.
Application logic
Implemented example performs only one operation. As a reaction to POST request sent to /message
endpoint, it takes the request body and pushes a message with it to the SQS queue.
As you can see, it’s necessary to know SQS queue’s URL in the code to be able to send a message there. It actually comes from application’s properties file.
Now everything is clear, we pass mentioned URL to the service using an environment variable. Let’s look how to actually set it by jumping straight to Terraform files.
Infrastructure configuration
In order to pass queue’s URL as environment variable, you need to follow steps listed below:
- Register queue’s URL as a parameter in AWS Systems Manager Parameter Store.
- Make sure you set an execution role for your task definition and assign it an IAM policy allowing it to get the parameter from Parameter Store.
- Specify secrets configuration in your task definition containing the env variable backed by value of previously created parameter.
Let’s now talk in more details about each of the steps.
Register queue’s URL as a parameter in Parameter Store
Registering a parameter in Parameter Store is quite straightforward. You can do it using aws_ssm_parameter
Terraform resource. Additionally, I included creation of the simplest possible SQS queue.
Customise task execution role
In order to avoid problems with deployment, the execution role specified in the task definition needs to be allowed to retrieve the parameter from Parameter Store.
First, I create AWS IAM role that might be assumed by ECS tasks. Next, the new policy document is built. It allows performing ssm:GetParameters
operations on parameter I was writing about in previous section. Finally, I assign this policy to the execution role using aws_iam_role_policy
Terraform resource. Now, we’re ready to reference this param in the task definition.
Use defined param as a value for environment variable
In this step, I’d like to show you creation of an entire ECS task definition resource, however special attention should be paid to secrets
section and specification of the execution role.
In 3rd line you can see that I specified the execution role defined and configured in previous step. Additionally, please look at container_definitions
and secrets
array inside it. Given name is a name of the environment variable we’d like to access from application running inside the container. Its value is taken from the SSM param we defined earlier. This way, in application’s properties we can refer to DEMO_QUEUE_URL
environment variable and make sure that we indeed will get actual URL of the queue created in Terraform scripts.
Let’s see it all in action
I run terraform apply
command in the main Terraform directory. After waiting a few minutes for entire infrastructure to be created in AWS we’re finally ready to perform e2e tests to see if the presented solution really works. Let’s check firstly what is the public IP of our service. After a brief exploration of created cluster it’s easy to find the task representing our application.
Using the IP given there, I’ll try to call the service.
I received the expected response, that’s the ID of message sent to the SQS queue. Let’s poll the messages there and see if it really has been sent to the right queue.
As you can see on the screenshot pasted above, the message has been sent and can be received without any problems. It means that the environment variable we’re working on points to the correct URL!
Conclusion and final words
We reached the end of this article. I hope that reading it helped you to understand how you can pass parameters from your Terraform scripts to ECS-powered applications. However, I expect you now have a feeling that way more magic happened in the background in order to test everything end to end. If so, you’re right. I don’t want to leave you without providing all the answers. You can find them in the GitHub repository I prepared for you. Give it a go, experiment, change something and try to deploy on your own. I’m pretty sure you’ll find it at least as satisfactory as it was for me watching all the infrastructure being created and then working as a charm in less than 5 minutes. Thank you for reading to the very end!
Read more about the technologies we use or take an inside look at our organisation & processes. Interested in working at StepStone? Check out our careers page.