Instance metadata (IMDSv2) and instance roles

How an EC2 instance gets its identity and credentials — the instance profile, the metadata service and its IMDSv2 session tokens, the hop limit that breaks containers, account-level IMDS defaults and enforcement, and how the AWS SDK finds the credentials.

markdownreferencev47D8H-EBTEstage: referencetrust: officialservice: ec2service: iaminterface: anyIMDSIMDSv2instance metadataHttpTokens requiredhttp-put-response-hop-limitmodify-instance-metadata-defaultshttp-tokens-enforcedmodify-instance-metadata-options169.254.169.254instance profileiam:PassRoleinstance role credentialscontainer on EC2 cannot get credentials

Created 18 Oct 2026 · Modified 23 Oct 2026 · 4 versions

An instance's AWS credentials come from the role in its instance profile, served by the instance metadata service (IMDS). Require IMDSv2 (session tokens) everywhere, and set the hop limit to 2 if containers on the instance need credentials.

The pieces

PieceWhat it is
RoleAn IAM role trusting ec2.amazonaws.com. Role changes propagate to all instances using it, and EC2 role credentials aren't limited by the role's maximum session duration (trust principal: UNVERIFIED in the collected sources)
Instance profileThe container that attaches a role to an instance. One role per profile and one profile per instance (the same role can be in several profiles). The IAM console creates a same-named profile automatically; the CLI, API and SDKs create role and profile separately, possibly with different names, and launches name the profile. To change an instance's permissions, replace the instance profile: removing a role from a profile can take up to an hour to take effect
Launch permissionThe launcher needs iam:PassRole on the role. Its absence shows up as an encoded UnauthorizedOperation (reference/ec2/errors.md)
IMDSAn HTTP endpoint at 169.254.169.254, reachable only from the instance, that serves metadata and the role's temporary credentials

The AWS SDKs and the CLI find instance credentials automatically, at the end of the default credential chain. Environment variables or a profile set on the instance take precedence and are a common reason the "wrong" identity is used (reference/sts/credential-sources.md).

IMDSv1 vs IMDSv2

  • IMDSv2 requires a session token obtained with a PUT, then sent as a header on each GET. That blocks the simple request-forgery attacks that make IMDSv1 dangerous.
  • HttpTokens=required disables IMDSv1 for the instance. Current AWS SDKs use IMDSv2 automatically.
TOKEN=$(curl -sX PUT http://169.254.169.254/latest/api/token -H "X-aws-ec2-metadata-token-ttl-seconds: 300")
curl -s -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/iam/security-credentials/

(Token header names and paths: UNVERIFIED in the collected sources; they are the documented IMDSv2 interface.)

Hop limit

HttpPutResponseHopLimit limits how many network hops the token response can travel. With the value 1, a process in a container with its own network namespace, such as Docker bridge mode, cannot get a token, so the SDK in the container finds no credentials. Set it to 2 for instances that run containers. AWS's own example settings use 2.

Setting it

ScopeCommand
One launchrun-instances … --metadata-options "HttpEndpoint=enabled,HttpTokens=required,HttpPutResponseHopLimit=2"
Running instanceaws ec2 modify-instance-metadata-options --instance-id <id> --http-tokens required --http-put-response-hop-limit 2 (flags match the ModifyInstanceMetadataOptions API model: HttpTokens, HttpPutResponseHopLimit, HttpEndpoint, InstanceMetadataTags)
Account default, per Regionaws ec2 modify-instance-metadata-defaults --http-tokens required --http-put-response-hop-limit 2
Enforce, per Regionaws ec2 modify-instance-metadata-defaults --http-tokens-enforced enabled: launches that would allow IMDSv1 are refused
  • Account defaults apply to new launches in that Region and do not change running instances.
  • A setting in the AMI or launch template, or on the launch request, overrides the account default (UNVERIFIED precedence order).
  • The SDK field is HttpTokensEnforced (disabled, enabled, no-preference) on ModifyInstanceMetadataDefaultsCommand, confirmed against @aws-sdk/client-ec2's types.

Symptoms

SymptomLikely causeCheck
SDK on the instance: Could not load credentials from any providersNo instance profile attached, IMDS disabled (HttpEndpoint=disabled), or a container blocked by hop limit 1 (the message is verbatim from the AWS SDK for JavaScript v3 source)aws ec2 describe-iam-instance-profile-associations --filters Name=instance-id,Values=<i>; aws ec2 describe-instances --instance-ids <i> --query 'Reservations[0].Instances[0].MetadataOptions'
curl 169.254.169.254/latest/meta-data/ returns 401IMDSv2 is required and the request had no token: use the token flow aboveSame MetadataOptions → HttpTokens: required
Credentials for the wrong roleEnvironment variables or ~/.aws on the instance take precedence over the instance profileOn the instance: `envgrep AWS_, ls ~/.aws, then aws sts get-caller-identity`
Launch refused after adding a profileThe launcher lacks iam:PassRole: decode the messageaws sts decode-authorization-message --encoded-message <msg>

The instance identity role (not yours to configure)

Every instance also has an instance identity role, arn:aws:iam::<account>:assumed-role/aws:ec2-instance/<instance-id>, served at /identity-credentials/ec2/security-credentials/ec2-instance. It has no trust policy, is not subject to identity or resource policies, and works only with the services integrated with it: EC2 Instance Connect, Systems Manager Default Host Management Configuration, GuardDuty runtime monitoring, Lambda Managed Instances, and STS GetCallerIdentity. Seeing it in CloudTrail is normal; it isn't the instance-profile role.

Scope note

ECS tasks and Lambda functions do not use IMDS for their roles. They get credentials from their own task or execution role (reference/ecs/roles-and-networking.md, reference/lambda/permissions.md).

Read this document as markdown — the same bytes an agent receives.