Skip to main content

EC2 Launch Template IMDSv2 Required

Overview

This check verifies that your EC2 launch templates enforce Instance Metadata Service Version 2 (IMDSv2). IMDSv2 adds a session-based token requirement that protects against unauthorized access to instance metadata, which often contains sensitive information like temporary IAM credentials.

Risk

When IMDSv2 is not required, instances are vulnerable to Server-Side Request Forgery (SSRF) attacks. Here is what could happen:

  • Credential theft: An attacker exploiting an SSRF vulnerability in your application can query the metadata service and steal temporary IAM credentials
  • Lateral movement: Stolen credentials can be used to access other AWS resources in your account
  • Data exfiltration: With valid credentials, attackers can read sensitive data from S3, databases, or other services
  • Privilege escalation: If the instance role has broad permissions, the impact of credential theft is magnified

IMDSv1 allows simple HTTP GET requests to retrieve metadata. IMDSv2 requires a session token obtained through a PUT request first, making SSRF exploitation significantly harder.

Remediation Steps

Prerequisites

You need:

  • AWS Console access with permissions to modify EC2 launch templates
  • Knowledge of which launch templates are affected (Prowler will list them)
Required IAM permissions (for administrators)

Your IAM user or role needs these permissions:

  • ec2:DescribeLaunchTemplates
  • ec2:DescribeLaunchTemplateVersions
  • ec2:CreateLaunchTemplateVersion
  • ec2:ModifyLaunchTemplate

AWS Console Method

Step 1: Find the Affected Launch Template

  1. Open the EC2 Console

  2. Navigate to Launch Templates

    • In the left sidebar, scroll down to Launch Templates under Instances
    • Click Launch Templates
  3. Locate your template

    • Find the launch template flagged by Prowler
    • Click on the template name to view its details

Step 2: Create a New Version with IMDSv2 Required

  1. Start creating a new version

    • In the Actions dropdown, select Modify template (Create new version)
  2. Configure metadata options

    • Scroll down to Advanced details (expand it if collapsed)
    • Find the Metadata accessible setting - ensure it is set to Enabled
    • Find the Metadata version setting
    • Change it to V2 only (token required)
  3. Review and create

    • Optionally add a version description like "Enforce IMDSv2"
    • Click Create launch template version

Step 3: Set the New Version as Default

  1. Go back to the Launch Templates list

    • Click Launch Templates in the breadcrumb or sidebar
  2. Set default version

    • Select your launch template
    • Click Actions then Set default version
    • Select the new version number you just created
    • Click Set as default version

Important: New instances launched from this template will now require IMDSv2. Existing running instances are not affected and must be configured separately.

AWS CLI (optional)

Step 1: List your launch templates

aws ec2 describe-launch-templates \
--region us-east-1 \
--query 'LaunchTemplates[*].[LaunchTemplateId,LaunchTemplateName,DefaultVersionNumber]' \
--output table

Step 2: Check current metadata settings

aws ec2 describe-launch-template-versions \
--launch-template-id <your-launch-template-id> \
--region us-east-1 \
--query 'LaunchTemplateVersions[*].[VersionNumber,LaunchTemplateData.MetadataOptions]' \
--output json

Step 3: Create a new version with IMDSv2 required

aws ec2 create-launch-template-version \
--launch-template-id <your-launch-template-id> \
--source-version <current-version-number> \
--version-description "Enforce IMDSv2" \
--launch-template-data '{"MetadataOptions":{"HttpTokens":"required","HttpEndpoint":"enabled"}}' \
--region us-east-1

Replace:

  • <your-launch-template-id> with your launch template ID (e.g., lt-0123456789abcdef0)
  • <current-version-number> with the version number to base the new version on

Step 4: Set the new version as default

aws ec2 modify-launch-template \
--launch-template-id <your-launch-template-id> \
--default-version <new-version-number> \
--region us-east-1
CloudFormation (optional)

This template creates a launch template with IMDSv2 enforced:

AWSTemplateFormatVersion: '2010-09-09'
Description: EC2 Launch Template with IMDSv2 Required

Parameters:
LaunchTemplateName:
Type: String
Description: Name of the launch template
Default: imdsv2-required-template

InstanceType:
Type: String
Description: EC2 instance type
Default: t3.micro

AmiId:
Type: AWS::EC2::Image::Id
Description: AMI ID for the instances

Resources:
SecureLaunchTemplate:
Type: AWS::EC2::LaunchTemplate
Properties:
LaunchTemplateName: !Ref LaunchTemplateName
LaunchTemplateData:
InstanceType: !Ref InstanceType
ImageId: !Ref AmiId
MetadataOptions:
HttpTokens: required
HttpEndpoint: enabled
HttpPutResponseHopLimit: 1
InstanceMetadataTags: disabled

Outputs:
LaunchTemplateId:
Description: ID of the launch template
Value: !Ref SecureLaunchTemplate

LaunchTemplateLatestVersion:
Description: Latest version number of the launch template
Value: !GetAtt SecureLaunchTemplate.LatestVersionNumber

Deploy with:

aws cloudformation deploy \
--template-file launch-template-imdsv2.yaml \
--stack-name secure-launch-template \
--parameter-overrides \
LaunchTemplateName=my-secure-template \
AmiId=ami-0123456789abcdef0 \
--region us-east-1

Note: CloudFormation creates new launch templates. To update an existing template not managed by CloudFormation, use the Console or CLI methods above.

Terraform (optional)
variable "launch_template_name" {
description = "Name of the launch template"
type = string
default = "imdsv2-required-template"
}

variable "instance_type" {
description = "EC2 instance type"
type = string
default = "t3.micro"
}

variable "ami_id" {
description = "AMI ID for the instances"
type = string
}

resource "aws_launch_template" "secure" {
name = var.launch_template_name

instance_type = var.instance_type
image_id = var.ami_id

metadata_options {
http_tokens = "required"
http_endpoint = "enabled"
http_put_response_hop_limit = 1
instance_metadata_tags = "disabled"
}

tags = {
Name = var.launch_template_name
}
}

output "launch_template_id" {
description = "ID of the launch template"
value = aws_launch_template.secure.id
}

output "launch_template_latest_version" {
description = "Latest version number of the launch template"
value = aws_launch_template.secure.latest_version
}

Deploy with:

terraform init
terraform plan -var="ami_id=ami-0123456789abcdef0"
terraform apply -var="ami_id=ami-0123456789abcdef0"

Note: To update an existing launch template managed by Terraform, modify the metadata_options block and apply the changes.

Verification

After making changes, verify IMDSv2 is enforced:

  1. In the AWS Console:

    • Go to EC2 > Launch Templates
    • Click on your launch template
    • Select the Versions tab
    • Click on the latest (or default) version number
    • Scroll to Advanced details and confirm Metadata version shows V2 only (token required)
  2. Re-run the Prowler check:

    • Run Prowler again to confirm the check now passes
CLI verification commands

Check the metadata options for your launch template:

aws ec2 describe-launch-template-versions \
--launch-template-id <your-launch-template-id> \
--versions '$Default' \
--region us-east-1 \
--query 'LaunchTemplateVersions[0].LaunchTemplateData.MetadataOptions'

Expected output when IMDSv2 is required:

{
"HttpTokens": "required",
"HttpEndpoint": "enabled",
"HttpPutResponseHopLimit": 1,
"InstanceMetadataTags": "disabled"
}

If HttpTokens shows optional or is missing, IMDSv2 is not enforced.

To verify all launch templates at once:

aws ec2 describe-launch-templates \
--region us-east-1 \
--query 'LaunchTemplates[*].LaunchTemplateId' \
--output text | tr '\t' '\n' | while read lt_id; do
echo "Launch Template: $lt_id"
aws ec2 describe-launch-template-versions \
--launch-template-id "$lt_id" \
--versions '$Default' \
--region us-east-1 \
--query 'LaunchTemplateVersions[0].LaunchTemplateData.MetadataOptions.HttpTokens' \
--output text
echo "---"
done

Additional Resources

Notes

  • Existing instances not affected: Changing the launch template only affects new instances. Running instances keep their current IMDS configuration. Use aws ec2 modify-instance-metadata-options to update running instances.
  • Auto Scaling Groups: If an Auto Scaling Group uses this launch template, new instances launched by scaling events will use IMDSv2. Existing instances in the group are not modified.
  • Application compatibility: Some older applications or SDKs may not support IMDSv2. Test your workloads before enforcing IMDSv2 in production. Most modern AWS SDKs (released after 2019) support IMDSv2.
  • Hop limit consideration: The HttpPutResponseHopLimit defaults to 1, which prevents containerized workloads from accessing IMDS. If running containers, you may need to increase this to 2.
  • Complete protection: For comprehensive protection, also enforce IMDSv2 at the account level using an SCP or at the instance level for running instances.