Explore and Secure EC2 Metadata

Query, exploit, and lock down the EC2 Instance Metadata Service.

Introduction

30 Second Summary

Imagine a locked filing cabinet in your office that automatically opens and hands over sensitive documents to anyone who knocks. Every EC2 instance has something similar: a metadata service that shares credentials and configuration details with anything that asks.

In this project, you will query the Instance Metadata Service on a live EC2 instance to see exactly what it exposes. You will then enforce IMDSv2 to block the most common attack path against this service.

What You'll Build

You will launch an EC2 instance with an IAM role, explore what the Instance Metadata Service exposes using IMDSv2's token-based flow, and enforce IMDSv2-only access at both the instance and account level.

By the end of this project, you'll have:

  • An EC2 instance with an IAM role attached, hardened to IMDSv2-only mode.
  • Hands-on experience with IMDSv2's token-based session flow for retrieving instance metadata and live IAM credentials.
  • Account-level IMDS defaults configured to require IMDSv2 for all future instance launches in your region.
  • A Bash audit script that checks metadata exposure and reports IMDSv2 enforcement status (Secret Mission).

Are there any prerequisites?

You need an AWS account with permissions to launch EC2 instances, create IAM roles, and modify IMDS settings. You should also be comfortable with EC2 basics like launching instances and connecting via SSH.

Launch an EC2 Instance with an IAM Role

Every EC2 instance has access to a hidden HTTP endpoint called the Instance Metadata Service (IMDS). This service exposes information about the instance, including temporary security credentials delivered by an IAM role.

In this step, you will create an IAM role, launch an EC2 instance with that role attached, and SSH into it. You will configure the instance to allow both IMDSv1 and IMDSv2 so you can compare them side by side in the next step.

In this step, get ready to:
  • Create an IAM role for your EC2 instance.
  • Launch a t3.micro EC2 instance with the role attached.
  • SSH into the running instance.
Create an IAM role for EC2

An IAM role grants an EC2 instance permissions to access AWS services. When you attach a role to an instance, IMDS delivers temporary credentials that the instance can use instead of hardcoded access keys.

  • Open the AWS Management Console and type IAM in the top search bar.
  • Click Roles in the left sidebar.
  • Click Create role.
  • Under Trusted entity type, select AWS service.
  • Under Use case, select EC2.
  • Click Next.
  • In the permissions search bar, type AmazonS3ReadOnlyAccess.
  • Select the checkbox next to AmazonS3ReadOnlyAccess.
  • Click Next.

Why AmazonS3ReadOnlyAccess?

This gives the role a real but harmless permission. When you query IMDS later, you will see actual AWS credentials being delivered to the instance. The permission only allows reading from S3, so there is no risk of accidental changes to your account.

  • In the Role name field, enter imds-demo-role.
  • Scroll to the bottom and click Create role.

You should see a green success banner confirming that imds-demo-role was created.

What is an IAM role?

An IAM role is a set of permissions that AWS services can assume. Instead of storing long-lived access keys on the instance, the role tells IMDS to generate temporary credentials that expire and rotate automatically.

The AWS SDK on the instance calls IMDS behind the scenes to fetch these credentials. You will see this exact process in Step 3.

Launch a t3.micro EC2 instance

Now you need an EC2 instance to explore. You will attach the IAM role you just created and configure specific metadata settings for the experiment.

  • Type EC2 in the AWS Console search bar and open the EC2 dashboard.
  • Click Launch instance.
  • In the Name field, enter imds-demo.
  • Under Application and OS Images, select Amazon Linux 2023 AMI (free tier eligible).
  • Under Instance type, select t3.micro.
  • Under Key pair (login), select an existing key pair or click Create new key pair.
  • If creating a new key pair, enter a name, keep the default settings, and click Create key pair.

Pro tip: save your key file

The .pem file downloads automatically to your Downloads folder. Remember where it is. You will need it to SSH into the instance.

  • Under Network settings, click Edit.
  • Confirm that Auto-assign public IP is set to Enable.
  • Under the security group rules, confirm there is a rule allowing SSH (port 22) from My IP.
  • Scroll down and expand the Advanced details section.
  • Under IAM instance profile, select imds-demo-role.
  • Scroll down to Metadata version.
  • Select V1 and V2 (token optional).
  • Set the Metadata response hop limit to 1.

Why allow both metadata versions?

Amazon Linux 2023 defaults to IMDSv2-only, which blocks IMDSv1 requests entirely. You are overriding that default so you can try both versions and see the difference yourself.

In Step 4, you will enforce IMDSv2-only and confirm that IMDSv1 requests are rejected. Starting with both enabled makes the security improvement concrete.

  • Click Launch instance.

You should see a success message with your new instance ID. Click the instance ID link to go to the instance details page.

Seeing a launch error?

If you see a permissions error, confirm that your AWS account has permission to launch EC2 instances and create IAM instance profiles.

If you see a quota or capacity error, check that you have not exceeded the vCPU limit for your region. You can view your limits in the EC2 console under Limits.

Help me troubleshoot my EC2 launch error.

SSH into the instance

Your instance needs a minute or two to finish initializing. Once it reaches the running state, you can connect to it over SSH.

  • In the EC2 console, wait for the Instance state column to show Running.
  • Click on your instance to open its details.
  • Copy the Public IPv4 address from the instance summary.
  • Press Cmd+Space (macOS) or the Windows key (Windows) to open your search bar.
  • Type Terminal (macOS) or PowerShell (Windows) and press Enter to open it.
  • Connect to the instance by running this command:
ssh -i [[KEY_PAIR_PATH="path to your .pem key file"]] ec2-user@[[EC2_PUBLIC_IP="your EC2 public IPv4 address"]]

What does this command do?

  • ssh -i tells SSH to authenticate using a specific private key file.
  • ec2-user is the default username on Amazon Linux instances.
  • The address after @ is your instance's public IPv4 address.
  • If prompted to confirm the host fingerprint, type yes and press Enter.

You should see a welcome message from Amazon Linux and a command prompt ending in $. You are now inside the EC2 instance.

Can't connect to the instance?

  • If you see Permission denied, make sure you are using the correct .pem file for this instance. On macOS or Linux, you may also need to restrict the file permissions:
chmod 400 [[KEY_PAIR_PATH="path to your .pem key file"]]
  • If the connection times out, check that your security group allows SSH (port 22) from your current IP address. Your IP may have changed since you created the security group.
  • If the instance state is not Running, wait another minute and try again. Initialization can take up to two minutes.

Help me fix my SSH connection to the EC2 instance.

You are connected to an EC2 instance with an IAM role and both metadata versions enabled. Next up, you will query the Instance Metadata Service and see exactly what it exposes.

Query Metadata with IMDSv2

Your EC2 instance is running and you have SSH access. Now it is time to explore what the Instance Metadata Service actually exposes.

IMDS lives at 169.254.169.254, a special link-local address reachable from inside every EC2 instance. You will use IMDSv2's token-based flow to query this endpoint and discover the data it returns.

In this step, get ready to:
  • Retrieve an IMDSv2 session token and list all metadata categories.
  • Query specific instance identity fields and the instance identity document.
  • Compare IMDSv2 with an unauthenticated IMDSv1 request.
Get a session token and list metadata categories

IMDSv2 requires a session token before you can query any metadata. You obtain this token by sending a PUT request with a custom header that sets the token's time-to-live.

  • In your SSH session on the EC2 instance, request a session token with a 6-hour TTL by running this command:
TOKEN=$(curl -s -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600")

What does this command do?

  • curl -s -X PUT sends a PUT request to the IMDS token endpoint. The -s flag silences progress output.
  • X-aws-ec2-metadata-token-ttl-seconds: 21600 is a custom header that sets the token's lifetime to 21600 seconds (6 hours).
  • TOKEN=$(...) captures the response into a shell variable so you can reuse the token in later requests.
  • Verify the token was stored by running:
echo $TOKEN

You should see a long string of characters. This is your IMDSv2 session token.

Getting an empty response?

  • Make sure you are running this command from inside the EC2 instance via SSH, not from your local machine. The IMDS endpoint is only reachable from within the instance.
  • Check that you copied the full command, including the closing parenthesis and the -X PUT flag. A GET request to the token endpoint returns nothing.
  • Help me troubleshoot my IMDSv2 token request
  • Use the token to list all top-level metadata categories by running:
curl -s -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/

You should see a list of categories like ami-id, hostname, instance-id, instance-type, local-ipv4, mac, network/, and security-groups. Each one represents a different piece of information the instance knows about itself.

Why does this URL look like a regular IP address?

169.254.169.254 is a link-local address reserved for IMDS. It is not a real server on the internet. Only processes running on the EC2 instance can reach it, and requests to it never leave the host.

Seeing a 401 or empty response?

  • Run echo $TOKEN again to confirm the variable is not empty. Tokens can expire, so re-run the PUT command if you have been away for a while.
  • Check for typos in the header name. It must be exactly X-aws-ec2-metadata-token (case-sensitive).
  • Help me troubleshoot my IMDS metadata query
Retrieve instance identity information

Each metadata field lives at its own path under /latest/meta-data/. You can query them individually using the same session token.

  • Query several identity fields by running these commands one at a time:
curl -s -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/instance-id
curl -s -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/instance-type
curl -s -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/ami-id
curl -s -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/local-ipv4
curl -s -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/placement/availability-zone
curl -s -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/security-groups

What do these fields tell you?

  • instance-id is the unique identifier for your instance (starts with i-).
  • instance-type confirms your instance size (t3.micro).
  • local-ipv4 is the private IP assigned to the instance inside the VPC.
  • placement/availability-zone shows which data center zone your instance is in.
  • security-groups lists the firewall rules attached to the instance.

Each command prints a single value directly to the terminal. You should see your instance ID, instance type, AMI ID, private IP, availability zone, and security group name.

IMDS also provides a combined identity document that returns all of this information as JSON in a single request.

  • Retrieve the full instance identity document by running:
curl -s -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/dynamic/instance-identity/document

What is the instance identity document?

This endpoint lives under /latest/dynamic/ instead of /latest/meta-data/. It returns a single JSON object containing your instance's region, availability zone, instance ID, instance type, account ID, architecture, and more.

AWS services use this document to verify instance identity. The account ID field in particular shows exactly which AWS account owns this instance.

You should see a formatted JSON response containing fields like accountId, region, instanceId, and architecture.

Compare with an IMDSv1 request

Your instance currently allows both IMDSv1 and IMDSv2. This means you can query metadata without any token at all. Try it and see the difference.

  • Try querying metadata without a token by running:
curl -s http://169.254.169.254/latest/meta-data/instance-id

This returns your instance ID. No token, no PUT request, no custom headers. Just a plain GET request.

Why is this a security problem?

Any process on the instance that can send an HTTP GET to 169.254.169.254 can read all of this data. If a web application running on the instance has an SSRF vulnerability, an attacker could trick the application into making that GET request and stealing the response.

With IMDSv1, that single GET is all it takes. With IMDSv2, the attacker would first need to send a PUT request with a custom header to obtain a token. Most SSRF vulnerabilities only allow GET requests and cannot set custom headers.

The PUT request also has a default hop limit of 1 at the IP protocol level. This prevents the token request from being forwarded through network hops, blocking attacks from containers or instances behind a proxy.

What is SSRF?

Server-Side Request Forgery (SSRF) is an attack where an attacker tricks a server into making HTTP requests on their behalf. If the server is an EC2 instance, the attacker can target the IMDS endpoint to steal IAM credentials. This was the technique used in the 2019 Capital One breach.

You have seen everything the metadata service exposes and how easily IMDSv1 hands it over. Next up, you will explore the most sensitive data IMDS delivers: live IAM role credentials.

Explore IAM Credentials Exposed by IMDS

In the previous step, you queried your instance for identity details like its ID, type, and availability zone. That data is informative, but it is not the most sensitive thing IMDS exposes.

The real security concern is IAM role credentials. When you attach an IAM role to an EC2 instance, IMDS delivers temporary AWS credentials to any process running on that instance. In this step, you will retrieve those credentials and see exactly what an attacker could steal.

In this step, get ready to:
  • Retrieve the IAM role name attached to your instance through IMDS.
  • Fetch the temporary AWS credentials that IMDS delivers to the instance.
  • Understand why SSRF attacks targeting IMDS credentials are dangerous.
Retrieve the IAM role name from IMDS

IMDS has a dedicated path for IAM credentials at /latest/meta-data/iam/security-credentials/. Querying this path lists any IAM roles attached to the instance.

Pro tip: Refresh your token if needed

Your $TOKEN variable from the previous step should still be active. If you closed your SSH session or more than 6 hours have passed, re-run this command first:

TOKEN=$(curl -s -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600")
  • List the IAM roles available through IMDS by running this command:
curl -s -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/iam/security-credentials/

You should see imds-demo-role printed in the output. This is the role you attached to the instance in Step 1.

Not seeing imds-demo-role?

  • If you see a 404 error, the IAM role may not be attached to the instance. Go to the EC2 Console, select your instance, click Actions > Security > Modify IAM role, and select imds-demo-role.
  • If you get an empty response or 401 Unauthorized, your token may have expired. Re-run the TOKEN= command from the tip above, then try again.
  • Help me troubleshoot my IMDS IAM role query
Retrieve the temporary credentials

Knowing the role name is just the first step. The real payload is behind it. IMDS serves temporary AWS credentials for the role to any process that asks.

  • Fetch the actual credentials for imds-demo-role by running this command:
curl -s -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/iam/security-credentials/imds-demo-role

You should see a JSON response containing AccessKeyId, SecretAccessKey, Token, and Expiration fields.

What are these credentials?

These are real, working AWS credentials that grant S3 read-only access (the policy you attached in Step 1). Anyone who has these four values can make AWS API calls as this role.

  • AccessKeyId and SecretAccessKey are the credential pair used to sign API requests.
  • Token is a session token required alongside the key pair because these are temporary credentials.
  • Expiration shows when the credentials stop working. They rotate automatically, typically every 6 hours.

The AWS SDK on the instance uses this exact IMDS endpoint to get credentials transparently. Your application code never handles keys directly.

Seeing a 404 or empty response?

  • Double check that you are using the exact role name from the previous command. The role name in the URL must be imds-demo-role, not the role ARN.
  • If the previous command returned a different role name, use that name instead of imds-demo-role in the URL.
  • Help me troubleshoot my IMDS credential retrieval
Understand the SSRF risk

Imagine a web application is running on this EC2 instance. The application has an SSRF vulnerability that lets an attacker trick the application into making HTTP requests to arbitrary URLs.

What is SSRF?

Server-Side Request Forgery (SSRF) is a vulnerability where an attacker tricks a server into making HTTP requests on their behalf. The attacker cannot reach the target directly, but the server can. IMDS at 169.254.169.254 is a classic SSRF target because it is only reachable from inside the instance.

With IMDSv1, stealing credentials takes a single GET request. The attacker makes the vulnerable application send a GET to http://169.254.169.254/latest/meta-data/iam/security-credentials/imds-demo-role and the full credential JSON comes back. No token, no authentication, nothing to stop it.

How does IMDSv2 block this attack?

IMDSv2 adds two layers of defense that break the SSRF attack chain.

  • PUT request with a custom header. Before any metadata query, you must send a PUT request with the X-aws-ec2-metadata-token-ttl-seconds header to get a session token. Most SSRF vulnerabilities only allow GET requests and cannot set custom headers. This alone blocks the majority of attacks.
  • Hop limit of 1. The PUT request has a default IP-level hop limit of 1. The token request cannot be forwarded through network hops. This prevents attacks from containers or instances behind a proxy.
  • X-Forwarded-For rejection. Any PUT request containing an X-Forwarded-For header is automatically rejected. This closes another common proxy-based attack path.

This is why enforcing IMDSv2 matters. The credentials you just retrieved are real and powerful. The only thing standing between an attacker and those credentials is how the metadata service authenticates requests.

You have now seen exactly what IMDS exposes and why it is a high-value target. Next, you will lock down the instance to require IMDSv2-only and set account-level defaults to enforce this across your entire region.

Enforce IMDSv2 and Verify

In the previous step, you retrieved live IAM credentials straight from IMDS. A single unauthenticated GET request was all it took.

Now it is time to close that gap. Using the AWS CLI, you will switch your EC2 instance to IMDSv2-only mode, confirm that tokenless requests are rejected, and set account-level defaults so every future instance in your region launches secured from the start.

In this step, get ready to:
  • Enforce IMDSv2 on the running EC2 instance using the AWS CLI.
  • Verify that IMDSv1 requests return a 401 Unauthorized response.
  • Set account-level IMDS defaults to require IMDSv2 for all new instances in your region.
Enforce IMDSv2 on the running instance

The modify-instance-metadata-options command switches an instance from allowing both IMDS versions to requiring IMDSv2 only. You run this from your local machine, not from inside the EC2 instance.

  • Open a new terminal window on your local machine (or use the terminal you had open before you SSH'd into the instance).
  • Enforce IMDSv2 on your instance by running this command:
aws ec2 modify-instance-metadata-options --instance-id [[INSTANCE_ID="your instance ID e.g. i-0abc123def456"]] --http-tokens required --http-endpoint enabled

What does this command do?

  • --http-tokens required tells EC2 to reject any metadata request that does not include a valid IMDSv2 session token. This is the flag that blocks IMDSv1.
  • --http-endpoint enabled keeps the metadata service itself active. Without this, the instance would lose access to IMDS entirely.
  • Check the JSON response. You should see "HttpTokens": "required" in the output.
  • The State field might show pending initially. It changes to applied within a few seconds.

Seeing an error?

  • If you see UnauthorizedOperation, your AWS CLI credentials do not have the ec2:ModifyInstanceMetadataOptions permission. Check your IAM user or role policies.
  • If you see InvalidInstanceID.NotFound, double-check your instance ID in the EC2 Console. Make sure your CLI region matches the region where you launched the instance.
  • Help me debug why my modify-instance-metadata-options command is failing
Verify IMDSv1 is blocked

With IMDSv2 enforced, any request to the metadata endpoint without a session token should be rejected. Time to prove it.

  • Switch back to your SSH session on the EC2 instance.
  • Attempt an IMDSv1 request (no token) by running this command:
curl -s -w "\nHTTP Status: %{http_code}\n" http://169.254.169.254/latest/meta-data/instance-id
  • You should see an empty response body followed by HTTP Status: 401. IMDSv1 is officially blocked.

Why 401 Unauthorized?

When HttpTokens is set to required, EC2 rejects any metadata request that does not include a valid X-aws-ec2-metadata-token header. The 401 response proves that a simple GET request can no longer read your instance metadata.

  • Now confirm that IMDSv2 still works by running these commands:
# Request a fresh IMDSv2 session token
TOKEN=$(curl -s -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600")

# Use the token to query metadata
curl -s -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/instance-id
  • You should see your instance ID printed (e.g. i-0abc123def456). IMDSv2 is working as expected.

Still getting a 401 on the IMDSv2 request?

  • Make sure you ran both commands together. The token is stored in the TOKEN variable and only lasts for your current shell session.
  • If you see an empty response, run echo $TOKEN to check that the token variable is not empty. An empty token means the PUT request to the token endpoint failed.
  • Help me figure out why my IMDSv2 token request is failing on EC2

This is the core security win. The same SSRF attack that could steal credentials with a single GET request against IMDSv1 now fails against IMDSv2. The attacker would need to send a PUT request with a custom header, which most SSRF vulnerabilities cannot do.

Set account-level IMDS defaults and verify

Enforcing IMDSv2 on a single instance protects that instance. Account-level defaults go further. They ensure every new instance launched in a region starts with IMDSv2 required by default.

  • Switch back to your local machine terminal.
  • Set the account-level default for your region by running this command:
aws ec2 modify-instance-metadata-defaults --region [[AWS_REGION="your AWS region e.g. us-east-1"]] --http-tokens required --http-put-response-hop-limit 2

What does this command do?

  • --http-tokens required sets the default for all new instances in this region to require IMDSv2.
  • --http-put-response-hop-limit 2 sets the default hop limit to 2. A hop limit of 1 blocks token requests forwarded through a network hop. A limit of 2 supports containerized workloads where the request passes through one extra hop.

These defaults apply to new instance launches only. Existing instances are not affected.

  • Verify the setting was applied by running:
aws ec2 get-instance-metadata-defaults --region [[AWS_REGION="your AWS region e.g. us-east-1"]]
  • In the output, look for "HttpTokens": "required" under the AccountLevel section. This confirms that every new EC2 instance launched in this region will default to IMDSv2-only.

Command not returning the expected output?

  • Make sure the --region value in the get-instance-metadata-defaults command matches the region you used in the modify-instance-metadata-defaults command. Account-level defaults are set per region.
  • If you see an access denied error, check that your AWS CLI user has the ec2:ModifyInstanceMetadataDefaults and ec2:GetInstanceMetadataDefaults permissions.
  • Help me troubleshoot my account-level IMDS defaults command

What about existing instances?

Account-level defaults only apply to instances launched after the setting is applied. Any instance already running keeps its current IMDS configuration. To harden existing instances, use the per-instance modify-instance-metadata-options command you ran earlier in this step.

Secret mission

Write an IMDS Audit Script

You have explored IMDS by hand. Now automate it. Write a Bash script that auto-discovers instance identity, checks whether IMDSv1 is still open, and reports a security verdict. This is the kind of script a cloud security engineer runs during an audit.

Before you go

Clean Up Your Resources

Decide whether to keep your resources running, pause them to come back later, or delete them entirely. A running t3.micro instance costs approximately $0.0104/hour on-demand, so charges can accumulate if you leave it running beyond Free Tier limits.

Cost warning

If your AWS Free Tier has expired, the EC2 instance will incur on-demand charges for every hour it runs. EBS storage for the default volume also has a small ongoing cost. Terminate the instance and delete the associated resources if you are done experimenting.

Resources you used:

  • 1 EC2 instance (t3.micro) running in your account.
  • 1 IAM role (imds-demo-role) with the AmazonS3ReadOnlyAccess managed policy attached.
  • Account-level IMDS defaults modified for your region (set to require IMDSv2).
  • 1 EC2 key pair (if you created a new one for this project).
  • 1 security group allowing SSH from your IP.

Keep everything running

No action needed. Choose this if you are still actively experimenting with IMDS or plan to continue shortly.

  • Your EC2 instance will continue running and incurring charges (approximately $0.0104/hour for t3.micro in us-east-1).
  • The IAM role and security group remain in place at no cost.
  • Your account-level IMDS defaults stay set to require IMDSv2.

Pause - I'll come back to this later

Stop the EC2 instance to avoid compute charges while keeping your setup intact. EBS storage costs still apply, but they are minimal for the default volume.

  • In the EC2 Console, select your instance.
  • Click Instance state, then Stop instance.
  • When you are ready to resume, select the instance and choose Instance state, then Start instance. The public IP will change, so grab the new one before SSHing back in.
  • The IAM role, security group, and account-level IMDS defaults remain unchanged.

Delete - I don't want to use this again

Remove all project resources and start fresh. Follow these steps to clean up everything.

  • Terminate the EC2 instance. In the EC2 Console, select your instance, click Instance state, then Terminate instance. You can also use the CLI:
aws ec2 terminate-instances --instance-ids i-xxxxxxxxxxxx
  • Delete the IAM role. Go to IAM in the console, select Roles, find imds-demo-role, and delete it. You must detach the AmazonS3ReadOnlyAccess policy first.
  • Delete the security group you created for SSH access (if it is not the default security group).
  • Delete the key pair if you created one specifically for this project. Go to EC2, then Key Pairs, and delete it. Also remove the .pem file from your local machine.
  • Optionally reset the account-level IMDS defaults. We recommend keeping IMDSv2 enforced, but if you want to reset to the default behavior, run:
aws ec2 modify-instance-metadata-defaults --region us-east-1 --http-tokens no-preference --http-put-response-hop-limit -1

Pro tip: keep IMDSv2 enforced

The account-level IMDS default that requires IMDSv2 is a security best practice. Consider leaving it in place even after deleting the other resources. It protects all future EC2 instances in that region from IMDSv1-based attacks.

Mission accomplished

Nice Work!

You just explored one of the most security-critical services running on every EC2 instance. You went from querying raw metadata with simple GET requests to locking down the entire Instance Metadata Service with session-based authentication.

You learned how to:

  • Use IMDSv2's PUT/GET token flow to query instance metadata, networking details, and live IAM role credentials from the 169.254.169.254 endpoint.
  • Enforce IMDSv2-only on a running instance and verify that tokenless IMDSv1 requests are rejected with a 401 Unauthorized response.
  • Set account-level IMDS defaults to require IMDSv2 for all future EC2 instances launched in your region.
  • Write a Bash audit script that auto-discovers instance identity, checks IMDSv2 enforcement status, and reports a summary of all exposed metadata categories.

Ready to quiz yourself?