Unveiling the Security Implications of AWS EC2 IMDSv2 and How to Lock it Down

Unveiling the Security Implications of AWS EC2 IMDSv2 and How to Lock it Down

Cloudmason
Cloudmason

Hello fellow cloud enthusiasts and welcome to my very first blog!

Today, let’s embark on a journey into the world of AWS cloud security and some of its quirks. Buckle up as we uncover the security implications of the AWS EC2 Instance Metadata Service (IMDS).

What is IMDS and Why should You Care?

IMDS, short for the Instance Metadata Service, is essentially a service that runs under the hood on your EC2 instances that allows AWS (and users) to integrate the cloud plane with the OS plane. It is accessible on your EC2 instances through calling a static link-local IP address (169.254.169.254).

IMDS provides all sorts of configuration information to applications or agents running on the machine, helping in their functionality. Applications can use it to find out certain metadata of the underlying EC2 instance, such as the VPC ID or the EC2 instance ID. However, IMDS can also be used to query which IAM role is attached to the instance and obtain the temporary security tokens. This is where it gets interesting.

Now, why does this exist?

It enables applications running on the machine to authenticate to AWS by integrating with dynamic IAM roles. This way we don’t need to give the applicaitons static long-lived AWS access key credentials for having our application interact with AWS resources. If our application needs access to an S3 bucket, we can just attach the IAM instance role to the EC2 instance and under the hood a temporary short-lived security token can be used to authenticate to AWS. The token rotates automatically on a regular basis.

So far so good, right? So what’s the problem?

The Security Risks: IMDSv1 and IMDSv2

There have been two iterations of this Metadata Service: IMDSv1 and IMDSv2.

In the good ol’ days of IMDSv1, all it took to get your hands on the temporary credentials from an attached IAM role was tricking a web application into making a GET request to the metadata service IP address to unleash a world of wicked possibilities for hackers. At the very least, sensitive information could be obtained, paving the way for further exploitation. In the worst-case scenario, a malicious user could steal the attached IAM role’s temporary security tokens, giving the abuser unauthorized access to AWS resources.

If you want to get an idea of what kind of information such an SSRF vulnerability exposes, just go ahead and run this CURL command on an EC2 instance and browse through the metadata avaialble.

curl "http://169.254.169.254/latest/meta-data/"

IMDSv2, with its token-based authentication, aimed to thwart these devilish attempts. However, it’s a little bit like putting a band-aid on a leaky faucet — sure, it helps, but the faucet might still be leaking. What’s worse, the token-based system provides a false sense of security. The only additional protection it really offers is that you now need to deceive the web application into making two subsequent requests: a PUT request to retrieve a token and a GET request with the security token in the request header X-aws-ec2-metadata-token. Unfortunately, there are plenty of web applications out there nowadays that have some juicy webhook functionalities or no-code automation/integration features that allow you to do just that.

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

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

Discovery

When tackling any security issue, the first task is to map out the current exposure. When it comes to AWS configurations, there’s all kinds of tools that can be hooked into your environment for compliance scanning. One of my personal favorites for quickly building custom queries is steampipe[https://steampipe.io]. With Steampipe, you can build SQL-like queries to quickly answer any questions you have on your environment. You can save these queries to rerun them in the future and even build custom dashboards or compliance checkers with very little effort.

To find out about our usage of IMDS and IMDSv2, you can run this query for example:

select
  i.instance_id,
  i.tags ->> 'Name' as name,
  i.region,
  i.metadata_options ->> 'HttpEndpoint' as imds_http_enabled,
  i.metadata_options ->> 'HttpTokens' as imdsv2,
  i.tags ->> 'owner' as owner
from
  aws_ec2_instance as i
where
  i.instance_state != 'terminated' AND i.metadata_options ->> 'HttpEndpoint' != 'disabled'

Solutions and Best Practices

  1. Disable the IMDS service endpoint by default and only enable it when required. The best secured attack surface is no attack surface. If you only require IMDS for executing userdata scripts, consider disabling the metadata service endpoint at the end of your userdata script. Note: check there are no agents like the CloudWatch agent running on your server that rely on IMDS.

  2. Always use IMDSv2 over IMDSv1. This is usually an easy to implement layer of protection that will save your bacon if an attacker can only manage to trigger GET requests. You can check the CloudWatch EC2 metric ‘MetadataNoToken’ for your instance to check if IMDSv1 is still being used.

  3. Follow the Least Privilege Principle in all things. Think twice when attaching IAM roles to EC2 instances and thrice about every permission inside the policy. AWS provides tools like IAM Access Analyzer to help generate least-privilege policies based on access activity. Also apply the least privilege principle on your EC2 security groups. Where possible, use whitelisting to only allow access to your web application from trusted networks.

  4. Deny usage of the IAM instance role credentials outside of the EC2 instance. There’s no good reason why the permissions granted by EC2 instance roles should be used outside of that instance. Add a condition-based explicit deny rule to any IAM role that will be attached to an EC2 instance. Now if an attacker can make any HTTP request through your application, they will also just be able to call the AWS API through this, but at least a breach may be more more difficult to exploit. More info here: https://aws.amazon.com/blogs/security/how-to-use-policies-to-restrict-where-ec2-instance-credentials-can-be-used-from/

  5. If your account is part of an AWS Organization multi-account structure, create a Service Control Policy (SCP) that prevents the use of IAM instance role security tokens outside of the instances they were intended for.

  6. Harness the Power of the AWS Web Application Firewall (WAF) to add an additional layer of defense on any publicly exposed endpoint. For larger AWS environments, consider using Firewall Manager to centrally manage WAF configurations and to enforce compliance on newly created resources.

  7. Locking Down IMDS on Linux: On Linux systems, you can take an extra step to lock down the metadata service. You can segregate access to IMDSv2 away from the user that is used to run the hosted application by configuring the local firewall (iptables) to restrict access to the metadata service’s IP address (169.254.169.254) to specific users (for example only accessible for the root user and/or ssm-user).

iptables -A OUTPUT -m owner ! --uid-owner root -d 169.254.169.254 -j DROP

Wrapping Up

In conclusion, while IMDSv2 represents a step forward in securing EC2 instances, it’s essential to recognize there are still significant risks involved. As for any security issue, think in layers and never trust a single layer to provide you with complete security. By understanding the risks and implementing robust security measures, cloud engineers can navigate the AWS ecosystem with confidence. Stay vigilant, prioritize security, and fortify your cloud environment against evolving threats.

https://aws.amazon.com/blogs/security/defense-in-depth-open-firewalls-reverse-proxies-ssrf-vulnerabilities-ec2-instance-metadata-service/