EC2 Metadata IMDSv2: Secure Token Access Lab | AWS Tutorial

Introduction

Let me tell you about the time a startup lost $40,000 in a single weekend because someone didn’t understand EC2 metadata. A junior developer spun up a test instance, left IMDSv1 enabled, and deployed an application with an SSRF vulnerability. Attackers harvested IAM credentials directly from the metadata service, spun up crypto miners across three regions, and the team didn’t notice until Monday morning when AWS billing alerts finally fired.

That incident could have been prevented with about 20 minutes of understanding how EC2 metadata actually works.

This lab teaches you everything you need to know about the Instance Metadata Service, why IMDSv2 exists, and how to work with metadata securely. If you’re preparing for AWS certifications, building production infrastructure, or simply want to understand what’s happening under the hood when your EC2 instances boot, this is foundational knowledge you cannot skip.

This hands-on lab is designed for DevOps engineers, cloud practitioners, and anyone working through AWS beginner labs who wants to move beyond surface-level understanding. We’re going to get our hands dirty with real commands, real outputs, and real security considerations.

Here’s what I’ve learned after years of architecting AWS environments: metadata misuse is one of the most common attack vectors in cloud breaches. The good news is that once you understand the mechanics, securing it becomes second nature.


Lab Overview

In this step-by-step AWS tutorial, you’ll learn to interact with the EC2 Instance Metadata Service using IMDSv2’s token-based authentication. By the end of this lab, you’ll be able to retrieve IAM role credentials securely, pull instance tags programmatically, access user data from inside a running instance, and understand exactly why enterprises mandate IMDSv2.

The skills you’ll gain here translate directly to production scenarios. Metadata is used everywhere in real AWS environments: bootstrap scripts pull region information to configure applications, automation tools retrieve instance IDs for tagging and inventory, and applications use IAM role credentials from metadata instead of hardcoded access keys.

Why does every security-conscious organization enforce IMDSv2? Because IMDSv1’s simplicity was also its weakness. A single HTTP GET request could retrieve sensitive credentials with zero authentication. IMDSv2 requires a session token obtained through a PUT request, which stops most SSRF attacks cold. If an attacker can only make GET requests through a vulnerable proxy, they can’t obtain a token, and without a token, they can’t access metadata.


Prerequisites

Before starting this lab, ensure you have the following ready.

You need an active AWS account with permissions to launch and manage EC2 instances. A running EC2 instance is required, preferably Amazon Linux 2023 or Ubuntu 22.04. The instance must have an IAM role attached. If you haven’t done this before, create a role with the AmazonEC2ReadOnlyAccess policy for testing purposes.

AWS CLI should be installed on your EC2 instance. Most Amazon Linux AMIs include it by default. Verify IMDS is enabled on your instance, which is the default for new launches. Finally, you need SSH or Session Manager access to your instance’s terminal.

Related post: EC2 Launch and Connect Lab


Step-by-Step Hands-On Lab

Step 1: Verify IMDSv2 is Enabled on Your EC2 Instance

Before touching any metadata commands, let’s confirm your instance is configured correctly. From your local machine or the AWS Console, check the metadata settings.

Using AWS CLI from your local machine:

aws ec2 describe-instances \
  --instance-ids i-0abc123def456789 \
  --query 'Reservations[].Instances[].MetadataOptions'

Expected output:

[
    {
        "State": "applied",
        "HttpTokens": "required",
        "HttpPutResponseHopLimit": 2,
        "HttpEndpoint": "enabled",
        "HttpProtocolIpv6": "disabled",
        "InstanceMetadataTags": "enabled"
    }
]

The critical field here is HttpTokens. If it shows required, IMDSv2 is enforced. If it shows optional, both v1 and v2 work. For this lab, we want required.

Why this matters: I’ve walked into environments where teams assumed IMDSv2 was enabled because it’s “the default now.” It’s not universally enforced unless you explicitly set it. Always verify.

To enforce IMDSv2 if it’s not already:

aws ec2 modify-instance-metadata-options \
  --instance-id i-0abc123def456789 \
  --http-tokens required \
  --http-endpoint enabled

Step 2: Generate an IMDSv2 Token

SSH into your EC2 instance. This is where the real work happens.

The first thing you need for any IMDSv2 interaction is a session token. This token is generated via a PUT request to the metadata service’s token endpoint. The token has a configurable TTL (time-to-live) that you specify in seconds.

TOKEN=$(curl -X PUT "http://169.254.169.254/latest/api/token" \
  -H "X-aws-ec2-metadata-token-ttl-seconds: 21600")

Expected behavior: This command returns a token string and stores it in the TOKEN variable. The TTL of 21600 seconds gives you 6 hours before the token expires.

Common misconfiguration: If you see curl: (7) Failed to connect, IMDS might be disabled at the instance level, or a firewall rule is blocking the link-local address. We’ll cover this in troubleshooting.

Why 21600 seconds? For interactive sessions, 6 hours is practical. For automated scripts that run briefly, use shorter TTLs like 300 seconds. Shorter tokens reduce the window of exposure if something goes wrong.

Step 3: Retrieve IAM Role Credentials Securely

This is the part that makes metadata both incredibly useful and potentially dangerous if misconfigured.

First, discover which IAM role is attached to your instance:

curl -H "X-aws-ec2-metadata-token: $TOKEN" \
  http://169.254.169.254/latest/meta-data/iam/security-credentials/

Expected output:

MyEC2Role

Now retrieve the actual credentials for that role:

curl -H "X-aws-ec2-metadata-token: $TOKEN" \
  http://169.254.169.254/latest/meta-data/iam/security-credentials/MyEC2Role

Expected output:

{
  "Code": "Success",
  "LastUpdated": "2024-01-15T10:30:00Z",
  "Type": "AWS-HMAC",
  "AccessKeyId": "ASIAXXXXXXXXXXX",
  "SecretAccessKey": "xxxxxxxxxxxxxxxxxxxxxxxx",
  "Token": "IQoJb3JpZ2luX2VjEJ...",
  "Expiration": "2024-01-15T16:45:00Z"
}

Why this matters: These temporary credentials are how your EC2 instance assumes its IAM role. The AWS SDK and CLI automatically retrieve these credentials when running on EC2. You never hardcode access keys on instances because this mechanism exists.

Security note: These credentials rotate automatically, typically every 6 hours. The Expiration field tells you exactly when.

Step 4: Retrieve Instance ID and Region

Instance identity information is essential for automation scripts and application configuration.

curl -H "X-aws-ec2-metadata-token: $TOKEN" \
  http://169.254.169.254/latest/meta-data/instance-id

Expected output:

i-0abc123def456789

For region information, use the placement data:

curl -H "X-aws-ec2-metadata-token: $TOKEN" \
  http://169.254.169.254/latest/meta-data/placement/region

Expected output:

us-east-1

Production use case: Bootstrap scripts commonly retrieve the region to configure AWS CLI profiles, set CloudWatch agent configurations, or determine which S3 bucket to pull application artifacts from.

Step 5: Retrieve EC2 Instance Tags

This feature requires InstanceMetadataTags to be enabled (we verified this in Step 1).

curl -H "X-aws-ec2-metadata-token: $TOKEN" \
  http://169.254.169.254/latest/meta-data/tags/instance/

Expected output:

Name
Environment
Application

To retrieve a specific tag value:

curl -H "X-aws-ec2-metadata-token: $TOKEN" \
  http://169.254.169.254/latest/meta-data/tags/instance/Environment

Expected output:

production

Why this is powerful: Before this feature existed, retrieving tags required calling the EC2 API with describe-tags, which needed additional IAM permissions. Now your bootstrap scripts can read tags directly from metadata with zero API calls.

Step 6: Retrieve EC2 User Data

User data contains the bootstrap script or configuration you provided at launch time.

curl -H "X-aws-ec2-metadata-token: $TOKEN" \
  http://169.254.169.254/latest/user-data

Expected output: Whatever you passed as user data during instance launch. If you used a bash script, you’ll see the raw script content.

#!/bin/bash
yum update -y
yum install -y httpd
systemctl start httpd

Common mistake: User data is stored in plain text. I’ve seen teams put database passwords in user data, which is then readable by anyone with shell access to the instance. Don’t do this. Use Secrets Manager or Parameter Store for sensitive values.

Step 7: Compare IMDSv1 vs IMDSv2 Behavior

If your instance allows IMDSv1 (HttpTokens: optional), you can see the difference directly:

IMDSv1 (insecure, no token required):

curl http://169.254.169.254/latest/meta-data/instance-id

This works without any authentication if v1 is enabled.

IMDSv2 (secure, token required):

curl http://169.254.169.254/latest/meta-data/instance-id

Without the token header, this returns a 401 Unauthorized when IMDSv2 is enforced.

The lesson: Always enforce IMDSv2. The convenience of v1 isn’t worth the security risk.


Real Lab Experiences — Architect Insights

Let me share some war stories that will stick with you longer than any documentation.

The Capital One breach (2019) is the canonical example. An attacker exploited an SSRF vulnerability in a web application firewall, reached the metadata service via IMDSv1, extracted IAM credentials, and accessed over 100 million customer records. This breach directly accelerated AWS’s push for IMDSv2 adoption.

I personally encountered a situation where a developer’s debugging endpoint accidentally exposed metadata. The endpoint was supposed to show application health, but it proxied requests to any URL passed as a parameter. Someone discovered it, queried the metadata IP, and suddenly credentials were in server logs being shipped to a third-party logging service.

My advice to junior engineers: Treat the metadata endpoint like a database connection string. You wouldn’t expose your database credentials to the internet. The metadata service contains credentials that can potentially access your entire AWS account depending on the attached IAM role. Guard it accordingly.

Always use IMDSv2, always apply least-privilege IAM policies, and never assume that internal network position means security.


Validation & Testing

Confirm your metadata access is working correctly with these validation commands.

Verify your IAM identity from within the instance:

aws sts get-caller-identity

Expected output:

{
    "UserId": "AROAXXXXXXXXX:i-0abc123def456789",
    "Account": "123456789012",
    "Arn": "arn:aws:sts::123456789012:assumed-role/MyEC2Role/i-0abc123def456789"
}

This confirms your instance successfully assumed its IAM role using credentials from metadata.

Test a basic AWS API call:

aws ec2 describe-instances --instance-ids $(curl -s -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/instance-id) --query 'Reservations[].Instances[].InstanceType' --output text

If this returns your instance type, everything is configured correctly.


Troubleshooting Guide

Problem: curl returns “Connection refused” or times out

The metadata endpoint might be disabled. Check with:

aws ec2 describe-instances --instance-ids i-0abc123def456789 \
  --query 'Reservations[].Instances[].MetadataOptions.HttpEndpoint'

If it returns disabled, enable it:

aws ec2 modify-instance-metadata-options \
  --instance-id i-0abc123def456789 \
  --http-endpoint enabled

Problem: 401 Unauthorized when accessing metadata

You’re hitting IMDSv2 without a token. Generate a token first using the PUT request from Step 2.

Problem: IAM role credentials return 404

No IAM role is attached to the instance. Attach one through the console or CLI:

aws ec2 associate-iam-instance-profile \
  --instance-id i-0abc123def456789 \
  --iam-instance-profile Name=MyInstanceProfile

Problem: aws sts get-caller-identity fails

Check if the AWS CLI can reach AWS APIs. This might be a VPC routing issue (no internet gateway or NAT, and no VPC endpoints for STS).

curl -I https://sts.amazonaws.com

Problem: Metadata works but tags return 404

Instance metadata tags must be explicitly enabled:

aws ec2 modify-instance-metadata-options \
  --instance-id i-0abc123def456789 \
  --instance-metadata-tags enabled

AWS Best Practices — Solutions Architect Perspective

Security: Enforce IMDSv2 across your organization using Service Control Policies (SCPs). Apply least-privilege IAM roles—your EC2 instance doesn’t need AdministratorAccess to run a web server. Use VPC endpoints for AWS services to keep traffic off the public internet.

Reliability: Don’t cache metadata credentials beyond their expiration time. The SDK handles this automatically, but custom implementations sometimes get it wrong. Always handle credential refresh gracefully.

Operational Excellence: Standardize metadata access patterns across your applications. Create shared libraries or helper functions that handle token generation and refresh. Log metadata access attempts for security auditing.

Cost Optimization: Metadata calls are free, but the IAM permissions you grant can lead to expensive mistakes. Tightly scope IAM roles to prevent accidental resource creation.

Performance: Metadata responses are fast, but don’t query metadata repeatedly in tight loops. Cache instance identity information at application startup.

Tagging Strategy: Use metadata tag access to drive configuration. Tag instances with Environment, Application, and Team. Your bootstrap scripts can read these tags and configure themselves accordingly without maintaining separate configuration files per environment.

Related post: {link to IAM Best Practices for EC2}


AWS Interview Questions: EC2 Metadata & IMDSv2

These questions come directly from real AWS Solutions Architect and DevOps Engineer interviews. I’ve been on both sides of the table, and metadata understanding separates candidates who’ve actually worked in production from those who’ve only read documentation.

Entry-Level Questions

Q1: What is the EC2 Instance Metadata Service and what is it used for?

Expected Answer: The Instance Metadata Service (IMDS) is a local endpoint available at 169.254.169.254 that provides information about a running EC2 instance. Applications use it to retrieve instance identity, IAM role credentials, network configuration, and user data. It eliminates the need to hardcode credentials or configuration values in applications.

Q2: What IP address does the EC2 metadata service use, and why that specific address?

Expected Answer: The metadata service uses 169.254.169.254, which is a link-local address. This address is only routable from within the instance itself, meaning external systems cannot directly query your instance’s metadata. It’s part of the 169.254.0.0/16 range reserved for link-local communication.

Q3: How do applications running on EC2 obtain AWS credentials without hardcoding access keys?

Expected Answer: Applications retrieve temporary credentials from the Instance Metadata Service endpoint at /latest/meta-data/iam/security-credentials/{role-name}. The AWS SDK handles this automatically when running on EC2. These credentials rotate automatically, typically every 6 hours, and include an access key, secret key, and session token.

Mid-Level Questions

Q4: Explain the difference between IMDSv1 and IMDSv2. Why does IMDSv2 exist?

Expected Answer: IMDSv1 allows simple GET requests to retrieve metadata without authentication. IMDSv2 requires a session token obtained through a PUT request before accessing metadata. IMDSv2 was introduced to mitigate SSRF attacks where attackers could trick applications into making GET requests to the metadata endpoint and exfiltrating credentials. Since most SSRF vulnerabilities only allow GET requests, requiring a PUT-based token blocks these attacks.

Q5: A developer reports that their application can’t retrieve IAM credentials from metadata. Walk me through your troubleshooting process.

Expected Answer: First, verify the instance has an IAM role attached by checking the instance profile association. Second, confirm IMDS is enabled at the instance level (HttpEndpoint setting). Third, check if IMDSv2 is required and whether the application is sending the token header. Fourth, verify network connectivity to 169.254.169.254 isn’t blocked by iptables or security software. Finally, check if the IAM role trust policy allows ec2.amazonaws.com to assume it.

Q6: Your security team wants to enforce IMDSv2 across all EC2 instances. How would you implement this at scale?

Expected Answer: Implement a Service Control Policy (SCP) at the AWS Organizations level that denies ec2:RunInstances unless the condition ec2:MetadataHttpTokens equals required. For existing instances, use AWS Config rules to detect non-compliant instances and Systems Manager Automation to remediate by modifying instance metadata options. Include IMDSv2 enforcement in your AMI hardening process and CloudFormation/Terraform templates.

Senior-Level Questions

Q7: Describe a real-world attack scenario involving EC2 metadata and how IMDSv2 prevents it.

Expected Answer: In the Capital One breach, attackers exploited an SSRF vulnerability in a web application firewall. The vulnerable endpoint allowed arbitrary URL fetching. Attackers directed it to 169.254.169.254 to retrieve IAM role credentials, which had overly broad permissions. With those credentials, they accessed S3 buckets containing customer data. IMDSv2 prevents this because SSRF vulnerabilities typically only allow GET requests. Since IMDSv2 requires a PUT request to obtain a token first, the attack chain breaks at the credential retrieval step.

Q8: How would you design an application architecture that minimizes the blast radius if metadata credentials are compromised?

Expected Answer: Apply least-privilege IAM roles scoped to exactly what each application needs. Use separate IAM roles for different application tiers rather than sharing one broad role. Implement VPC endpoints so instances don’t need internet access for AWS API calls. Enable CloudTrail and set up alerts for unusual API activity from EC2 instance roles. Consider using IMDSv2 hop limit of 1 for containerized workloads to prevent containers from accessing host metadata. For highly sensitive workloads, consider using IAM Roles Anywhere or secrets management instead of instance roles.

Q9: Your team is migrating from on-premises to AWS. How do you explain to developers why they should use instance roles instead of access keys?

Expected Answer: Instance role credentials rotate automatically every few hours without application changes or deployments. Access keys are long-lived and require manual rotation, creating operational overhead and security risk. Leaked access keys remain valid until manually revoked, while leaked instance credentials expire within hours. Instance roles eliminate secrets storage problems entirely—there’s nothing to leak in your codebase, configuration files, or environment variables. The AWS SDK handles credential retrieval transparently, so applications work identically in development (with configured credentials) and production (with instance roles).

Q10: How does the EC2 metadata hop limit setting affect containerized workloads?

Expected Answer: The HttpPutResponseHopLimit controls how many network hops the IMDSv2 token can travel. For bare EC2 instances, the default of 1 works fine. For containers running on EC2 (ECS, EKS), traffic from the container to IMDS goes through the container’s network namespace, adding a hop. Setting the limit to 2 allows containers to access IMDS. However, for security-sensitive scenarios, keeping it at 1 prevents containers from accessing host metadata, forcing them to use task-level credentials (ECS) or IRSA (EKS) instead.


Frequently Asked Questions (FAQs)

What is EC2 Instance Metadata Service?

The EC2 Instance Metadata Service (IMDS) is an AWS service that provides information about a running EC2 instance from within that instance. It’s accessible at the IP address 169.254.169.254 and returns data including instance ID, instance type, IAM role credentials, network configuration, and user data scripts. Applications use IMDS to dynamically configure themselves without hardcoding environment-specific values.

What is the difference between IMDSv1 and IMDSv2?

IMDSv1 allows metadata retrieval using simple HTTP GET requests without authentication. IMDSv2 adds a security layer requiring applications to first obtain a session token through an HTTP PUT request, then include that token in subsequent metadata requests. IMDSv2 protects against server-side request forgery (SSRF) attacks because most SSRF vulnerabilities cannot make PUT requests, blocking the initial token acquisition step.

How do I enable IMDSv2 on EC2?

Enable IMDSv2 by modifying your instance’s metadata options using the AWS CLI command: aws ec2 modify-instance-metadata-options --instance-id i-1234567890abcdef0 --http-tokens required --http-endpoint enabled. For new instances, specify these options at launch time in your CloudFormation template, Terraform configuration, or the EC2 console under Advanced Details. Setting http-tokens to required enforces IMDSv2.

What is the EC2 metadata IP address?

The EC2 metadata service uses the IP address 169.254.169.254, which is a link-local address only accessible from within the EC2 instance itself. This address cannot be reached from outside the instance, providing a basic security boundary. All metadata requests, whether using IMDSv1 or IMDSv2, are made to this same IP address using HTTP on port 80.

How do I get IAM credentials from EC2 metadata?

First, generate an IMDSv2 token: TOKEN=$(curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600"). Then retrieve your role name: curl -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/iam/security-credentials/. Finally, fetch credentials using your role name in the path. The response includes temporary AccessKeyId, SecretAccessKey, and Token values.

Why is my EC2 metadata not working?

Common causes include IMDS being disabled at the instance level (check HttpEndpoint setting), IMDSv2 being required but your request missing the token header, no IAM role attached to the instance, iptables or security software blocking requests to 169.254.169.254, or running inside a container with hop limit set to 1. Run aws ec2 describe-instances --query 'Reservations[].Instances[].MetadataOptions' to check your configuration.

Is EC2 metadata secure?

EC2 metadata is secure when properly configured with IMDSv2 enforcement. The metadata endpoint is only accessible from within the instance using a link-local address, and IMDSv2’s token requirement prevents most SSRF-based attacks. However, anyone with shell access to your instance can access metadata, so IAM roles should follow least-privilege principles. Never put sensitive data like passwords in user data, as it’s readable through metadata.

What is the EC2 metadata token TTL?

The IMDSv2 token TTL (time-to-live) is configurable between 1 and 21600 seconds (6 hours). You specify the TTL when generating the token using the X-aws-ec2-metadata-token-ttl-seconds header. For interactive sessions, 6 hours is practical. For short-running scripts, use smaller values like 300 seconds to minimize the exposure window if the token is somehow leaked.

How do I retrieve EC2 tags from metadata?

First, ensure instance metadata tags are enabled: aws ec2 modify-instance-metadata-options --instance-id i-1234567890abcdef0 --instance-metadata-tags enabled. Then retrieve tags with an IMDSv2 token: curl -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/tags/instance/. This returns tag keys. Append a specific key to get its value: .../tags/instance/Environment returns that tag’s value.

What is EC2 user data vs metadata?

Metadata is read-only information about your instance provided by AWS, such as instance ID, IAM credentials, and network configuration. User data is custom data you provide at launch time, typically a shell script that runs once during first boot to configure the instance. Both are accessible through the same 169.254.169.254 endpoint but at different paths: /latest/meta-data/ and /latest/user-data.


Google Best Practices for EC2 Metadata Security

Google Cloud and AWS share similar security philosophies around instance metadata. These cross-platform best practices ensure your metadata implementation follows industry standards recognized by both major cloud providers.

Enforce Token-Based Access

Both AWS (IMDSv2) and Google Cloud (requiring headers for metadata requests) have moved toward authenticated metadata access. Always enforce IMDSv2 in AWS environments. The minor inconvenience of token management eliminates an entire class of SSRF vulnerabilities.

Apply Least Privilege to Instance Roles

Your EC2 instance role should contain only the permissions required for that specific workload. Google’s security guidelines and AWS Well-Architected Framework both emphasize this principle. If your web server only needs to read from one S3 bucket, the role should only permit s3:GetObject on that specific bucket ARN—nothing more.

Block Metadata Access from Containers When Possible

For containerized workloads, consider whether containers actually need access to the host’s metadata. In EKS, use IAM Roles for Service Accounts (IRSA) instead of node-level instance roles. In ECS, use task-level IAM roles. This follows Google’s recommendation of service account isolation per workload, preventing container escapes from escalating to full node credential access.

Monitor Metadata Access Patterns

Implement logging for metadata-related API calls through CloudTrail. Alert on unusual patterns like credential retrieval from unexpected instance roles or API calls from EC2 instances that don’t match expected behavior. Google’s Chronicle and AWS GuardDuty both offer detection capabilities for credential misuse stemming from metadata compromise.

Implement Defense in Depth

Don’t rely solely on IMDSv2. Combine multiple security layers including VPC security groups limiting outbound access, application-level input validation preventing SSRF, and IAM role permissions scoped narrowly. If one layer fails, others should prevent full compromise.

Rotate and Audit Regularly

Review IAM roles attached to EC2 instances quarterly. Remove unused permissions that accumulated over time. Verify IMDSv2 enforcement hasn’t been disabled. AWS Config and Google Cloud Asset Inventory both provide compliance checking capabilities for these configurations.

Use Infrastructure as Code

Define metadata configurations in CloudFormation, Terraform, or CDK templates. This ensures consistent, auditable, and version-controlled settings across all instances. Never manually modify metadata settings in production—all changes should flow through your IaC pipeline with appropriate review processes.


Conclusion & Next Steps

You’ve now mastered EC2 metadata access using IMDSv2. You can generate tokens, retrieve IAM credentials securely, pull instance identity and tags, and access user data. More importantly, you understand why these security mechanisms exist and what happens when they’re misconfigured.

This knowledge is foundational for everything that comes next in your AWS journey. Auto-scaling groups use metadata to register instances with load balancers. Container services use metadata to provide credentials to tasks. Systems Manager uses metadata for instance identity. Everything builds on this.

Next, we’ll put this knowledge into practice by automating instance bootstrapping with user data scripts that leverage metadata to configure themselves dynamically.


Looking for more hands-on AWS tutorials? Explore our complete EC2 lab series on thedevopstooling.com.

Similar Posts

Leave a Reply