AWS EC2 IMDS(Instance Metadata Service) all that you need to know

Table of contents

In my detailed study of the AWS EC2 service, I came across a common configuration called IMDS, which stands for Instance Metadata Service. If you’ve launched an EC2 instance or created a launch template for an Autoscaling group, you’ve likely seen this option.

So, what is it? IMDS is a local service endpoint that your services, scripts, or applications within your EC2 instances can connect to in order to acquire instance metadata, such as hostname, events, security groups, or AWS credentials. It is important to note that you can only access this endpoint from the instance itself.

The data shared by this service is not protected by authentication or any cryptographic method. This means that anyone who has access to the instance from the inside can access this endpoint. Therefore, you should never store sensitive data like passwords in the data used by your launch template.

the service is exposed in two ip’s addresses: for ipv4 169.254.169.254 or over the IPv6 protocol, it’s address is [fd00:ec2::254]. The IPv6 address of the IMDS is compatible with IMDSv2 commands. The IPv6 address is only accessible on instancias powered by nitro system

How to use it?

this service comes in two flavors.

  • IMDSv1— a request/response method

  • IMDSv2 — a session-oriented method

you can have enabled both or just one. The PUT or GET headers are unique to IMDSv2. If these headers are present in the request, then the request is intended for IMDSv2. If no headers are present, it is assumed the request is intended for IMDSv1. my recomendation is just to use the v2 due to its security imporvements that i will comment next.

This blog provides a detailed explanation of the security improvements in V2 compared to V1, which I recommend reading. To provide an overview, IMDSv2 requires an authenticated session for each request. A session can be requested via an HTTP PUT request, with a header that sets the session token duration(with a maximum of 6 hours 21600 seconds). There is no limit on the number of requests made by a session or the number of sessions. This token is only usable within the same EC2 instance.

TOKEN=(curl -X PUT "http://$IP_ADDRESS_IMDSV2/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 3600")
curl "http://$IP_ADDRESS_IMDSV2/latest/meta-data/profile" -H "X-aws-ec2-metadata-token: $TOKEN"
curl "http://$IP_ADDRESS_IMDSV2/latest/user-data" -H "X-aws-ec2-metadata-token: $TOKEN"
curl "http://$IP_ADDRESS_IMDSV2/latest/dynamic" -H "X-aws-ec2-metadata-token: $TOKEN"

The use of a PUT request adds an extra layer of security to IMDSv2 against misconfigured third-party firewalls. By default, most of these firewalls do not support PUT requests. This helps avoid unauthorized access via a misconfigured Web Application Firewall (WAF) or reverse proxy.

GET and HEAD methods are allowed in IMDSv2 instance metadata requests. PUT requests are rejected if they contain an X-Forwarded-For header.

knowing all this my advice is to configure your instances to use the IMDSv2 if you need it or your underlying applicaion running inside your insntace will use the isntance profile attached to the instace, a good practice with containerized workloads on eks is to restrict this endpoints to containers. One way is to block pod IMDS access is to apply a network policy, enforced by the Amazon VPC CNI or an add-on, to ensure pods are unable to reach the Instance Metadata Service. To do this, configure your network policy to block egress traffic to 169.254.0.0/16. Another way to block pod IMDS access is to require IMDSv2 to be used, and to set the maximum hop count to 1. Configuring IMDS this way will cause requests to IMDS from pods to be rejected, provided those pods do not use host networking, instead to provide iam permissions to your pods use service accounts with OIDC via iam ROLES. this will prvent pod iam permissions escalation and ensure least-minimum privilege in your end.

you can also prevent the launch of instance with IMDSv2 not enabled with a IAM policies like this

{
    "Version": "2012-10-17",
    "Statement": [
               {
            "Sid": "RequireImdsV2",
            "Effect": "Deny",
            "Action": "ec2:RunInstances",
            "Resource": "arn:aws:ec2:*:*:instance/*",
            "Condition": {
                "StringNotEquals": {
                    "ec2:MetadataHttpTokens": "required"
                }
            }
        }
    ]
}

or prevent the hop size limit to exceed a fixed value

{
    "Version": "2012-10-17",
    "Statement": [
               {
            "Sid": "MaxImdsHopLimit",
            "Effect": "Deny",
            "Action": "ec2:RunInstances",
            "Resource": "arn:aws:ec2:*:*:instance/*",
            "Condition": {
                "NumericGreaterThan": {
                    "ec2:MetadataHttpPutResponseHopLimit": "2"
                }
            }
        }
    ]
}

other endpoinds available to retrieve data from the IMDS endpoints

lastly to avoid a confussion there is an important difference between the instance identity role and the instance profile. AWS services and features that are integrated to use the instance identity role can use it to identify the instance to the service. The instance identity role credentials are accessible from the Instance Metadata Service (IMDS) at /identity-credentials/ec2/security-credentials/ec2-instance. and the instance profile is an iam role that allows the isntance to assume this role and then send requests to aws services.

i hope this post could be useful for you. this was a feature that i didn’t know until today and that is a very important security consideration for any workload on EC2 instances. : )