6.7 EC2 Instance Metadata Service (IMDSv2): Fetching Role Credentials
Right, let’s talk about the magic box inside your EC2 instance that holds all its secrets: the Instance Metadata Service (IMDS). Think of it as a highly specific, internal-only concierge service that only your instance can call. It answers questions like, “Who am I?”, “What’s my purpose?”, and most critically, “What are my temporary AWS credentials so I can actually do things?”
The original version, now called IMDSv1, was a bit too simple. You could just curl a URL and get what you wanted, no questions asked. This became a problem. If some malicious code somehow got onto your instance, or if your web application was tricked into making a Server-Side Request Forgery (SSRF) attack, it could just as easily fetch those powerful credentials. Not great.
So, AWS introduced IMDSv2, a session-oriented, more secure method. It’s a token-based system, and you should be using it exclusively. In fact, for any new instance you launch, you should enforce its use. I’ll show you how to do both.
The Two-Step Dance: Fetching a Token, Then the Goods
IMDSv2 works in two simple, but crucial, steps. You can’t just ask for the data; you have to first ask for permission in the form of a token. This token is short-lived (by default, it lasts a few seconds to a maximum of 21600 seconds) and is only usable from the instance it was generated on.
Here’s the dance in Bash. Notice the -X PUT which is the key difference.
# Step 1: Request a token. The PUT is crucial; a simple GET won't work.
TOKEN=$(curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600")
# Step 2: Use that token to request the actual metadata, like the IAM Role credentials.
curl -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/iam/security-credentials/my-iam-role-name
That my-iam-role-name is the name of the IAM role you attached to the instance. If you don’t know it, you can find it first by making another call with your token: curl -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/iam/security-credentials/.
Why This Is a Big Deal for Security
The beauty of the PUT request is that it’s not something you can easily do with a simple SSRF attack. Most SSRF vulnerabilities are triggered by GET requests (e.g., loading an image from a URL). Forcing the initial request to be a PUT throws a massive wrench in that attack vector. The attacker would need to find a way to perform a PUT request from your vulnerable application, which is a much taller order. This isn’t just security theater; it’s a genuinely effective mitigation for a very real class of vulnerabilities.
Enforcing IMDSv2: Don’t Be Lazy
You can configure which version of IMDS your instance uses. The best practice is to require IMDSv2. You can set this at launch in the “Advanced Details” section of the EC2 launch wizard. Find the “Metadata version” option and select “V2 only (token required)”.
If you’re using infrastructure-as-code (and you should be), here’s how you’d enforce it in a Terraform aws_instance resource:
resource "aws_instance" "example" {
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t3.micro"
# ... other configuration ...
metadata_options {
http_endpoint = "enabled"
http_tokens = "required" # This is the key line
}
}
The default for http_tokens is optional, which is a polite way of saying “please leave the less secure door unlocked.” Always, always set it to required.
The Gotchas and Edge Cases
- The Hop Limit: The metadata service is on a magic link-local IP (
169.254.169.254). It’s not routable. You can’t get to it from outside the instance, and you can’t get to it from another instance. This is a feature, not a bug. - Container Nightmare: If you’re running Docker containers on your EC2 instance, the container, by default, can also access the metadata service and grab the instance’s role credentials. This is a huge security risk. The solution is to set the
--net=hostflag very carefully or, better yet, use IAM Roles for Tasks if you’re on ECS, or use the ECS agent to provide credentials another way. Never let a container inherit the host’s role unless you absolutely mean to. - Token TTL: The token’s time-to-live is your friend. A shorter TTL means if a token is somehow compromised, it’s useful for a shorter window. Don’t just blindly set it to the max 6 hours unless you have a specific reason.
- It’s Always There: The metadata service is available from any EC2 instance, regardless of its IAM role or network configuration. You can’t “disable” it in a traditional sense (though you can disable access to it via the
http_endpointoption). Its purpose is to be available to configure the instance itself.
The bottom line is this: IMDSv2 is a straightforward, no-brainer security upgrade. The two-step process adds a trivial amount of complexity to your initialization scripts while dramatically reducing your attack surface. There is simply no good reason to be using IMDSv1 on anything new. Go into your AWS account right now and check your instance configurations. I’ll wait.