Instance Metadata Service (IMDS)
Every EC2 (Elastic Compute Cloud, Amazon’s virtual servers) instance can ask “who am I?” from the inside. It does this by calling a special, local-only web service called the Instance Metadata Service, or IMDS. IMDS lives at a fixed address, 169.254.169.254, that is only reachable from inside the instance itself. It hands back facts about the instance (its ID, region, network details) and — most importantly — temporary security credentials for the IAM (Identity and Access Management) role attached to the instance. This is how the AWS SDK and CLI authenticate without you ever hard-coding an access key. Getting IMDS configuration right is one of the single biggest things you can do to keep an instance secure.
What IMDS gives you
IMDS exposes a tree of read-only paths under a base URL. You request them with a plain HTTP GET. Some useful ones:
| Path | Returns |
|---|---|
/latest/meta-data/instance-id | The instance ID, e.g. i-0a1b2c3d4e5f |
/latest/meta-data/placement/region | The region, e.g. eu-west-1 |
/latest/meta-data/local-ipv4 | The instance’s private IP |
/latest/meta-data/public-ipv4 | The public IP (if it has one) |
/latest/meta-data/iam/security-credentials/<role-name> | Temporary IAM role credentials |
/latest/dynamic/instance-identity/document | Signed JSON identity document |
/latest/user-data | The user data script you passed at launch |
The credentials path is the crown jewel. When you attach an IAM role to an instance, AWS rotates short-lived credentials onto IMDS automatically. The SDK reads them from here, so your code can call AWS APIs with zero secrets on disk.
Why this matters: because IMDS gives out role credentials, anything that can reach
169.254.169.254from inside the instance can act as the instance’s IAM role. That is the entire security story below.
IMDSv1 vs IMDSv2 — the key difference
There are two versions of the protocol. Every modern instance should use IMDSv2.
| IMDSv1 | IMDSv2 | |
|---|---|---|
| How it works | Simple GET request, instant response | Get a session token first (PUT), then send it with each GET |
| SSRF-resistant? | No | Yes |
| Token in request | None | Required X-aws-ec2-metadata-token header |
| Default on new instances | Available unless disabled | Required when you enforce it |
| When to use | Never for new builds | Always |
IMDSv1 is a plain request/response. Any code that can make an HTTP request to the metadata IP gets an answer immediately — no proof required. IMDSv2 adds a tiny handshake: you first do a PUT to fetch a short-lived session token, then you must include that token as a header on every metadata GET. That one extra step blocks the most common attack against metadata, described next.
The SSRF gotcha (how cloud breaches happen)
SSRF stands for Server-Side Request Forgery. It is a bug where an attacker tricks your web app into making an HTTP request on the attacker’s behalf — for example, a “fetch this image URL” feature that you can point at any address. If an attacker points it at http://169.254.169.254/latest/meta-data/iam/security-credentials/, and your instance still allows IMDSv1, the metadata service happily returns your role’s credentials. The attacker now has your IAM role and can do anything that role permits. This exact chain — SSRF reaching IMDSv1 — is the mechanism behind several high-profile cloud breaches.
IMDSv2 defends against this because the attack must now (1) do a PUT and (2) send a custom header — things simple SSRF bugs usually cannot do. You harden it further with a hop limit: the maximum number of network hops the token response may travel. Set it to 1 so credentials cannot leak out through a misconfigured container or proxy on the host.
Enforcing IMDSv2 with a low hop limit
When to use this: always, on every instance and launch template. There is essentially no downside for modern SDKs, which speak IMDSv2 automatically.
Console steps
- Open the EC2 console and go to Instances.
- Select your instance, then choose Actions > Instance settings > Modify instance metadata options.
- Set IMDSv2 to Required.
- Set Metadata response hop limit to 1.
- Keep Instance metadata service Enabled (turning it off entirely breaks the SDK’s auto-credentials).
- Choose Save.
CLI equivalent
aws ec2 modify-instance-metadata-options \
--instance-id i-0a1b2c3d4e5f \
--http-tokens required \
--http-put-response-hop-limit 1 \
--http-endpoint enabled
Output:
{
"InstanceId": "i-0a1b2c3d4e5f",
"InstanceMetadataOptions": {
"State": "pending",
"HttpTokens": "required",
"HttpPutResponseHopLimit": 1,
"HttpEndpoint": "enabled"
}
}
Bake the same settings into every new instance by putting them in a launch template:
Resources:
WebServerTemplate:
Type: AWS::EC2::LaunchTemplate
Properties:
LaunchTemplateData:
ImageId: ami-0abcdef1234567890
InstanceType: t3.micro
MetadataOptions:
HttpTokens: required
HttpPutResponseHopLimit: 1
HttpEndpoint: enabled
Querying IMDSv2 by hand
To read metadata yourself, fetch a token, then use it. The token is valid for up to 6 hours (21600 seconds).
TOKEN=$(curl -X PUT "http://169.254.169.254/latest/api/token" \
-H "X-aws-ec2-metadata-token-ttl-seconds: 21600")
curl -H "X-aws-ec2-metadata-token: $TOKEN" \
http://169.254.169.254/latest/meta-data/instance-id
Output:
i-0a1b2c3d4e5f
You almost never need to do this in application code — the AWS SDK does it for you. Reach for raw curl only in debugging or startup scripts.
Cost note: IMDS itself is free; it is part of every instance. The cost of getting it wrong is not — leaked role credentials can lead to crypto-mining bills or data exfiltration running into thousands of dollars before you notice.
Best Practices
- Set
--http-tokens requiredeverywhere to force IMDSv2 and disable the SSRF-exploitable v1. - Set the hop limit to
1(or2only if you run pod-networked containers that genuinely need it). - Bake these options into launch templates and AMIs so new instances are hardened by default.
- If an instance never needs role credentials or metadata, disable IMDS entirely with
--http-endpoint disabled. - Grant each instance role the least privilege it needs, so even leaked credentials do limited damage.
- Audit fleet-wide compliance with AWS Config rules or by checking the
MetadataNoTokenCloudWatch metric, which counts IMDSv1 calls.