AWS security

IMDSv2 is not a migration project

The instance metadata service is still the most common pivot point in cloud breaches. Treating IMDSv2 as an account-level default — not a per-workload migration — closes the attack surface in an afternoon.

TZ

Taha Zubair

Founder, Cloud Upload · · 3 min

The instance metadata service (IMDS) is the mechanism by which an EC2 instance fetches its own IAM credentials. When IMDSv1 is reachable, any attacker who can make the instance perform an HTTP request of their choosing — SSRF, a misconfigured proxy, a vulnerable image renderer — can read the instance’s role credentials and use them from anywhere on the internet.

IMDSv2 closes this. It requires a session token obtained via a PUT request, sets a default TTL that SSRF vectors cannot meet, and is enforced at the instance level. And yet, five years after its release, the majority of production AWS accounts we audit still have IMDSv1 reachable on at least one running instance.

Critical

If any instance in your account still allows IMDSv1, assume one SSRF bug away from a credential leak. There is no workload that requires IMDSv1 that cannot be updated.

Why it stays this way

Three reasons, roughly ranked:

  1. “Migration” framing. Teams treat IMDSv2 enforcement as a per-workload task. That produces a spreadsheet, a backlog, and a year of delay. The correct framing is an account-level default: everything new is IMDSv2-only, and the existing set is closed in one sweep.

  2. Fear of breaking old images. Some legacy AMIs or pre-2019 SDKs could not obtain the v2 session token. That has been resolved in every current AWS SDK for at least four years. If you are still running a 2018 Python SDK in production, the IMDS issue is the smaller problem.

  3. Confusion between “enforcing IMDSv2” and “disabling IMDS entirely.” The required action is the former. The hop limit and token requirement are the controls; IMDS itself remains available.

The three account-level settings that close this

1. Default IMDSv2 at the account level

aws ec2 modify-instance-metadata-defaults \
  --region us-east-1 \
  --http-tokens required \
  --http-put-response-hop-limit 2 \
  --http-endpoint enabled

Apply per region. Every new instance launched in the account inherits these defaults. No Terraform change. No per-workload override.

2. Remediate existing instances in one pass

aws ec2 describe-instances \
  --filters "Name=metadata-options.http-tokens,Values=optional" \
  --query 'Reservations[].Instances[].InstanceId' \
  --output text \
| xargs -n1 -I{} aws ec2 modify-instance-metadata-options \
    --instance-id {} --http-tokens required --http-put-response-hop-limit 2

The command is idempotent and does not require instance restart. The maximum-blast-radius version of this — running it against all instances simultaneously — is safer than the incremental version, because incremental means some instances stay exposed longer for no gain.

3. Enforce via SCP

Once the account is clean, lock it:

{
  "Sid": "DenyIMDSv1Launch",
  "Effect": "Deny",
  "Action": "ec2:RunInstances",
  "Resource": "arn:aws:ec2:*:*:instance/*",
  "Condition": {
    "StringNotEquals": { "ec2:MetadataHttpTokens": "required" }
  }
}

This prevents any future launch — from any user, role, or pipeline — from regressing.

What attackers actually do with IMDSv1

The attack is not theoretical. In the public-record cloud breaches of the last five years, a significant fraction included a step where an application endpoint was induced to make a request to 169.254.169.254. The request returns the role credentials. The credentials are valid from the attacker’s laptop. From that role, further escalation follows the trust graph.

The payload is trivial. In a vulnerable image-fetch endpoint:

GET /fetch?url=http://169.254.169.254/latest/meta-data/iam/security-credentials/

With IMDSv2 enforced, the same request fails because the attacker cannot obtain the session token via a reflected URL. The attack surface collapses at that single control.

What to change today

  • Run the two CLI blocks above against every production region.
  • Add the SCP to your organization root.
  • Search Terraform for any module that sets http_tokens = "optional" and remove the line.
  • Verify from the CloudTrail query metadata-options.http-tokens = optional. The result set should be zero.

IMDSv2 enforcement is the single highest-leverage AWS hardening control and it can be completed before lunch. There is no workload-compatibility reason to delay.


Last updated October 22, 2025 ← All briefings