Using AWS IAM with AWS Elastic Container Service (ECS)
Security is job zero
This is for all the people, just like me, that have committed secret keys to a public GitHub repo!
But we cannot get rid of them all together so we need a way of injecting them into our application for use. Now this is nothing new and we have been able to do with with EC2 Instance Roles for a long time. There is also a long list of other services that can assume an IAM Role identity to enable access to other cloud resources.
This feature gives us on demand secret keys we can use that are short lived and are rotated automatically, for a full explanation see the AWS docs here.
This works by providing a local endpoint call the “Instance Metadata Endpoint” which you can call and it will generate temporary credentials for you. If you are using the AWS SDK in your EC2 instances then you might not know about this as it takes care of all of this for you.
Contain this!
Ok that is great and all but I have moved my app from EC2 to the Elastic Container Service (ECS) and using Fargate to run just my containers.
If you are not using Fargate, then you could still assign a role to the EC2 instance hosting your container but they can run more than one…hopefully, so that would not be ideal as we would end up with one super user IAM Role with all sorts of access. We should follow the principal of least privilege access.
The ECS team have a solution, which is to provide a relative URL which is associated to the Task Definition of ECS, this is called…wait for it…“Task Role”
It’s slightly different to the EC2 Metadata endpoint as is uses a unique container id which you don’t get until the task is launched, but they help us out by providing and Environment Variable so we can do a lookup first.
Relative URL looks like this:
/credential_provider_version/credentials?id=task_credential_id.
So you can curl the endpoint:
curl 169.254.170.2$AWS_CONTAINER_CREDENTIALS_RELATIVE_URI
So if you need to you can go and get the access key from here to use in you code, but again the SDK teams provide this plumbing so if you are using the AWS SDK then magic happens. For more details on this see the AWS docs here
I’ve written a simple Node + Express app to expose the Metadata Endpoint to show it working (don’t do this!) and also used the AWS SDK to access a private S3 bucket with the ECS Task Role to show how it could be used.
As it’s my new favorite thing, I used the AWS CDK to scaffold the whole thing in a few lines of TypeScript and built a working demo. Check out the my demo repo here.