Every EC2 instance with an IAM role serves that role's credentials from a local HTTP endpoint, and if the instance still accepts IMDSv1 a single server-side request forgery bug can hand those credentials to an attacker. This guide is the migration and enforcement playbook: how IMDSv1 and IMDSv2 differ, what the hop limit really does, how to find software still using IMDSv1, how to require IMDSv2 per instance, per AMI, per account and across an AWS Organization, and how to detect stolen instance credentials. It complements the SSRF Prevention Guide, which covers the application-side bug, and the Cloud Instance Metadata Services Compared Guide, which covers Azure, Google Cloud and OCI. It is written for cloud platform, EKS and security engineering teams. Settings were checked against AWS documentation on 27 October 2026.
Key takeaways
- IMDSv2 is session based: a PUT request obtains a token that must accompany every GET, which defeats most SSRF, open proxy and misconfigured firewall paths to the metadata service.
- Instances accept both versions by default unless the AMI, launch configuration or account defaults say otherwise, so "we use IMDSv2" is often only partly true.
- Measure before you enforce: the
MetadataNoTokenCloudWatch metric and the IMDS Packet Analyzer show which software still calls IMDSv1. - The hop limit is a container decision: 1 keeps containers away from the node's role, 2 lets containers that need IMDS reach it.
- Enforce at three levels: account defaults and IMDSv2 enforcement per Region, declarative policies across the organisation, and
ec2:RoleDeliveryso IMDSv1-delivered credentials stop working.
How identity and access work in the EC2 Instance Metadata Service
When an instance has an instance profile, EC2 delivers temporary credentials for that role through the Instance Metadata Service at 169.254.169.254 (and [fd00:ec2::254] on Nitro instances in IPv6-enabled subnets, where it must be enabled explicitly). The AWS SDKs read them automatically. Anything that can make the instance issue an HTTP request to that address can read the role credentials, which is why the metadata service is the most direct credential theft path in EC2. ATT&CK tracks it as T1552.005 Unsecured Credentials: Cloud Instance Metadata API.
IMDSv1 and IMDSv2 compared
| Property | IMDSv1 | IMDSv2 |
|---|---|---|
| Request model | Plain GET, no headers | PUT to /latest/api/token with X-aws-ec2-metadata-token-ttl-seconds, then GET with X-aws-ec2-metadata-token |
| Token lifetime | None | 1 to 21,600 seconds (six hours); token valid only on the instance that issued it |
| Proxy protection | None | PUT requests containing X-Forwarded-For are rejected |
| Network reach | Any hop that can reach the address | PUT response IP TTL (hop limit) defaults to 1, so the token does not travel beyond the instance |
| SSRF exposure | A GET-only SSRF is enough to read credentials | The attacker must control method and headers, which most SSRF bugs do not allow |
| When required and missing | Not applicable | Requests without a valid token get 401 Unauthorized |
IMDSv2 is defence in depth, not a fix for SSRF. A bug that lets an attacker send arbitrary methods and headers, or code execution on the host, still reaches the credentials. See the SSRF Prevention Guide for the application controls.
The metadata options that matter
| Option (API name) | Values | Recommended |
|---|---|---|
HttpTokens | optional (v1 and v2) or required (v2 only) | required |
HttpPutResponseHopLimit | 1 to 64 | 1 for nodes whose containers must not use the node role; 2 where containers need IMDS |
HttpEndpoint | enabled or disabled | disabled only where nothing on the instance needs metadata |
HttpProtocolIpv6 | enabled or disabled | Enable only if needed; apply the same token rules |
InstanceMetadataTags | enabled or disabled | Enable only when software reads tags from metadata; tags then become readable by any local process |
Settings are evaluated per option at launch in this order: the launch configuration or launch template, then the account's per-Region defaults, then the AMI (which can only set HttpTokens and the hop limit). Existing instances can be changed without a restart.
Admin roles and privileged access
The metadata service makes the instance role a privileged credential held by every process on the box. Hardening IMDS reduces the chance of theft; the role's own scope decides the damage.
- Scope instance roles narrowly: an instance role with broad S3 read,
iam:*orsts:AssumeRoleon many roles turns one SSRF into an estate-wide incident. In the Capital One breach, SSRF in a firewall reached the metadata service and the firewall's role could list and sync S3 buckets holding data on about 106 million people. - Protect the guardrail settings: deny
ec2:ModifyInstanceMetadataDefaultsto everyone except the platform team, so the account default cannot be weakened, and restrictec2:ModifyInstanceMetadataOptionswith the condition keys below. - Bind instance credentials to their network: the global keys
aws:Ec2InstanceSourceVpcandaws:Ec2InstanceSourcePrivateIPv4record where EC2 role credentials were delivered. AWS documents a deny statement that blocks instance credentials whenaws:SourceVpcdoes not match${aws:Ec2InstanceSourceVpc}, limited to instance credentials withec2:SourceInstanceARNand excluding calls made via AWS services withaws:ViaAWSService. Note thataws:SourceVpcexists only for requests through a VPC endpoint, so this binds credentials when your workloads use endpoints. The perimeter design is covered in the AWS Resource Control Policies and Data Perimeter Guide.
IAM and SCP condition keys for IMDS
| Condition key | Applies to | Use |
|---|---|---|
ec2:MetadataHttpTokens | RunInstances, ModifyInstanceMetadataOptions | Deny launches or changes unless the value is required |
ec2:MetadataHttpPutResponseHopLimit | Same | Cap the hop limit (for example, deny above 2) |
ec2:MetadataHttpEndpoint | Same | Control who can enable or disable the endpoint |
ec2:RoleDelivery | Any API call made with instance role credentials | Deny where the value is below 2.0, so credentials fetched through IMDSv1 are refused with UnauthorizedOperation |
ec2:RoleDelivery is the strongest of these because it acts on the stolen credential itself, not only on the instance setting. Apply it as an SCP after migration, since it will break any remaining IMDSv1 user. See the AWS Organizations and SCPs Guide.
Integrations, API tokens and service accounts
The software that keeps IMDSv1 alive is usually not your application but the agents, old SDKs and containers around it.
- SDKs and CLIs: IMDSv2 needs a minimum version, for example AWS CLI 1.16.289, Boto3 1.12.6, AWS SDK for Java 2.x 2.10.21 and AWS SDK for Go v2 0.19.0. Older embedded SDKs in vendor agents are the common laggards.
- Custom scripts: bootstrap and user data scripts that read metadata with a plain GET must be rewritten to request a token first. Windows instances with PowerShell earlier than 4.0 need Windows Management Framework 4.0 before IMDSv2 is required.
- Containers: a container adds a network hop. With a hop limit of 1, IMDSv2 calls from containers get no response, and some SDKs then retry and fall back to IMDSv1, which causes delays. Either pass configuration such as the Region into the container, or raise the hop limit to 2.
- Amazon EKS: AWS's EKS best practices recommend requiring IMDSv2 with a hop limit of 1 on nodes so pods cannot inherit the node's instance role, with pods using IAM Roles for Service Accounts or EKS Pod Identity instead. Do not disable metadata entirely, because node components such as the termination handler rely on it. Nodes built by eksctl or the official CloudFormation templates have historically had v1 and v2 enabled with a hop limit of 2, so check them. See the EKS Identity Hardening Guide.
- Credential caching: link-local services share a limit of 1,024 packets per second per instance and IMDS queries are throttled, so software should cache role credentials until they approach expiry rather than fetching them per request.
Logging and detection
IMDS requests are local to the instance and do not appear in CloudTrail. Detection works on two levels: configuration and usage telemetry on the instance side, and use of the credentials on the API side.
| Signal | Source | Meaning |
|---|---|---|
MetadataNoToken | CloudWatch EC2 metric | IMDSv1 calls still being made; must reach zero before enforcement |
MetadataNoTokenRejected | CloudWatch EC2 metric | IMDSv1 calls rejected after enforcement; points to software still to fix |
ImdsV1Enabled | CloudWatch EC2 metric | 1 when HttpTokens is optional; shows exposure even without calls |
| IMDS Packet Analyzer output | Open source tool from AWS, run on the instance | Identifies the process making IMDSv1 calls at boot and runtime |
UnauthorizedAccess:IAMUser/InstanceCredentialExfiltration.OutsideAWS | Amazon GuardDuty | Instance credentials used from an external IP address; High severity |
UnauthorizedAccess:IAMUser/InstanceCredentialExfiltration.InsideAWS | Amazon GuardDuty | Instance credentials used from another AWS account; High, or Medium if the account is affiliated |
ModifyInstanceMetadataOptions and ModifyInstanceMetadataDefaults | CloudTrail | Someone loosening IMDS settings |
GuardDuty can raise the OutsideAWS finding legitimately when traffic egresses through an on-premises gateway; AWS recommends a suppression rule on the finding type and the gateway's IP range rather than disabling the finding. Treat any unexplained exfiltration finding as a compromised instance: revoke the role's sessions, isolate the instance and investigate how the request was made. See the Amazon GuardDuty Guide.
Metrics
- Instances with
HttpTokensrequired: percentage per account and Region; target 100 percent. - Accounts with IMDSv2 enforcement enabled in every used Region.
- Sum of
MetadataNoTokenacross the estate per week, trending to zero. - Nodes with hop limit above 1 that do not have a documented container need.
- Instance credential exfiltration findings and time to contain each one.
Hardening baseline
Migration plan
AWS's recommended path has five steps. The ordered plan below follows it, with test and rollback points added.
- Find exposure: list instances where
metadata-options.http-tokensisoptional, and enable theImdsV1Enabledview in dashboards. AWS Config and Security Hub controls can also report it; see the AWS Config Guide. - Find IMDSv1 users: watch
MetadataNoTokenper instance for at least one full business cycle, including batch jobs and patch windows. Run the IMDS Packet Analyzer on instances with non-zero counts. - Update software: upgrade SDKs, agents and scripts; ask vendors for IMDSv2-capable agent versions.
- Require IMDSv2 on existing instances in rings: development, then a production pilot, then the rest. The change applies without a reboot. Rollback is setting
HttpTokensback tooptionalon the affected instance while the offending software is fixed. - Fix the sources of new instances: set
ImdsSupporttov2.0on your AMIs (Amazon Linux 2023 already defaults to IMDSv2), update launch templates, Auto Scaling groups and infrastructure as code modules. - Set account defaults per Region to
HttpTokensrequired with an appropriate hop limit. Defaults apply to new instances only. - Enforce: enable IMDSv2 enforcement so launches with IMDSv1 fail and enabling IMDSv1 on existing instances is blocked. Across many accounts, use an AWS Organizations declarative policy for EC2 with
instance_metadata_defaults(http_tokens,http_put_response_hop_limit,http_endpoint,instance_metadata_tags,http_tokens_enforced) and a customexception_messagethat tells engineers where to find help. - Close the credential path: add an SCP denying API calls where
ec2:RoleDeliveryis below2.0.
Enforcement fails launches where nothing sets HttpTokens to required, including old launch templates that explicitly set optional. Run enforcement in one OU first and watch for launch failures in Auto Scaling activity before widening it.
Choosing between controls
| Control | Scope | Strength | Best for |
|---|---|---|---|
Per-instance HttpTokens required | One instance | Fixes that instance; can be reverted by anyone with permission | Migration of existing fleet |
AMI ImdsSupport v2.0 | Instances launched from the AMI | Good default; overridden by launch settings | Golden image pipelines |
| Account defaults (per Region) | New instances in the account | Default only, not a prevention | Small estates |
| IMDSv2 enforcement or declarative policy | Account or organisation | Prevents IMDSv1 launches and changes; account admins cannot override a declarative policy | Large estates and regulated workloads |
SCP on ec2:MetadataHttpTokens | OU or organisation | Prevents non-compliant API calls | Belt and braces with enforcement |
SCP on ec2:RoleDelivery | OU or organisation | Makes IMDSv1-delivered credentials useless | Final step after migration |
Small versus large organisations: with a few accounts, set per-Region defaults and enforcement directly and fix stragglers by hand. With hundreds of accounts, declarative policies are the control of record, and the migration becomes a reporting exercise driven by ImdsV1Enabled and MetadataNoToken dashboards.
Common misconfigurations
- Setting the default but not enforcing it: account defaults affect only new instances that do not specify a value, so old launch templates keep producing IMDSv1 instances.
- Raising the hop limit everywhere: a hop limit of 2 or more on EKS nodes lets every pod reach the node role. Use it only where containers genuinely need IMDS and the node role is minimal.
- Disabling IMDS on nodes: breaks node components; on EKS block pods with the hop limit instead.
- Treating IMDSv2 as an SSRF fix: a full-featured SSRF or code execution still reaches the token endpoint. Keep egress controls and input validation.
- Over-privileged instance roles: the impact of any IMDS exposure is the role's permissions. Combine IMDS hardening with least privilege, as the Capital One case shows.
- Exposing tags through metadata without review: tags sometimes contain internal names or configuration that any local process can then read.
Framework mapping
| Framework | Reference | IMDS control |
|---|---|---|
| NIST CSF 2.0 | PR.PS-01, PR.AA-05, DE.CM-09 | Secure configuration baseline, least privilege for instance roles, runtime monitoring |
| NIST SP 800-53 Rev. 5 | CM-6, CM-7, AC-6, SC-7, SI-4 | IMDS settings, disabling unneeded endpoints, scoped roles, network binding, GuardDuty |
| CIS Controls v8.1 | 4 Secure Configuration, 6 Access Control Management, 13 Network Monitoring and Defense | IMDSv2 baseline, role scope, credential exfiltration detection |
| ISO/IEC 27001:2022 Annex A | 8.9, 8.2, 8.16 | Configuration management, privileged access rights, monitoring activities |
| MITRE ATT&CK v20 | T1552.005, T1190, T1078.004 | Metadata credential theft, the SSRF entry point, use of stolen cloud credentials |
Practitioner checklist
- Report every instance with
HttpTokensoptional, per account and Region. - Track
MetadataNoTokento zero and use the IMDS Packet Analyzer on stragglers. - Set
ImdsSupportv2.0 on every golden AMI and update launch templates. - Set per-Region account defaults, then enable IMDSv2 enforcement or a declarative policy.
- Use hop limit 1 on EKS nodes and move pods to IRSA or EKS Pod Identity.
- Deny
ModifyInstanceMetadataDefaultsoutside the platform team. - Add an SCP on
ec2:RoleDeliveryonce IMDSv1 usage is gone. - Enable GuardDuty and route instance credential exfiltration findings to on-call.
- Review instance role permissions so a stolen credential has a small blast radius.
Standards and references
- AWS: Use the Instance Metadata Service to access instance metadata
- AWS: Transition to using Instance Metadata Service Version 2
- AWS: Configure the Instance Metadata Service options
- AWS: Declarative policy syntax and examples
- AWS: GuardDuty IAM finding types
- AWS: Amazon EKS best practices, identity and access management
- MITRE ATT&CK: Unsecured Credentials: Cloud Instance Metadata API
- NIST: SP 800-53 Rev. 5
Related NHI Mgmt Group resources: SSRF Prevention Guide · Cloud Instance Metadata Services Compared Guide · EKS Identity Hardening Guide · AWS STS and AssumeRole Guide · AWS Security Guide