When we map attack paths in AWS accounts, one step shows up again and again: an internet-facing EC2 instance that still allows version 1 of the instance metadata service. Requiring IMDSv2 is a one-line change, it rarely breaks anything, and it often closes several paths at once. Here is why, and how to roll it out safely.
Why instance metadata matters
Every EC2 instance can ask the metadata service at 169.254.169.254 about itself, including for temporary credentials of the IAM role attached to it. With IMDSv1, that is a plain HTTP GET. So if an application on the instance can be tricked into fetching a URL for an attacker (server-side request forgery, or SSRF), the attacker can ask it to fetch the role's credentials and then use them from anywhere. The widely reported 2019 Capital One breach followed this pattern: an SSRF on a web-facing server, then the role's credentials, then the role's access to S3.
What IMDSv2 changes
IMDSv2 requires a session token first, obtained with an HTTP PUT that carries a special header, and then that token on every request. Most SSRF bugs can only make the application send simple GETs, so they can't get a token. The PUT response is also limited to one network hop by default, so it doesn't travel beyond the instance. That one change removes the “SSRF to credentials” step from the path.
Find what still uses IMDSv1
- Per instance: the CloudWatch metric
MetadataNoTokencounts metadata calls made without a token. Zero over a couple of weeks means nothing on the instance depends on IMDSv1. - Per account: list instances whose
MetadataOptions.HttpTokensisoptional. Those are the ones to look at, internet-facing ones first. - Software: current AWS SDKs and the CLI use IMDSv2 already. Old SDK versions, and scripts that call the metadata URL directly with curl, are the usual reasons a non-zero count stays non-zero.
Switch it on
For a running instance, no restart needed:
aws ec2 modify-instance-metadata-options \ --instance-id i-0123456789abcdef0 \ --http-tokens required --http-endpoint enabled
For new instances, set it where they come from:
- Terraform:
metadata_options { http_tokens = "required" }on instances and launch templates. - Account default:
aws ec2 modify-instance-metadata-defaults --http-tokens requiredin each region makes it the default for new launches. - Guardrail: a service control policy that denies
ec2:RunInstancesunlessec2:MetadataHttpTokensisrequiredstops new IMDSv1 instances across an AWS Organization.
One thing to check: containers
Containers on EC2 that use bridge networking are one network hop further from the metadata service. If they rely on the instance role, set the hop limit to 2 (--http-put-response-hop-limit 2) when you require tokens. Better still, give them their own role (for example ECS task roles or EKS pod identities) so they don't need the instance's credentials at all.
Why it ranks high
On its own, “IMDSv1 allowed” is a medium finding. On an instance that faces the internet and runs as a role that can read customer data, it is the cheapest link to break on a route to that data. That is why it comes near the top of a ranking built on attack paths rather than severity alone.