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:DescribeLaunchTemplatesec2:DescribeLaunchTemplateVersionsec2:CreateLaunchTemplateVersionec2:ModifyLaunchTemplate
AWS Console Method
Step 1: Find the Affected Launch Template
-
Open the EC2 Console
- Go to EC2 Console in us-east-1
-
Navigate to Launch Templates
- In the left sidebar, scroll down to Launch Templates under Instances
- Click Launch Templates
-
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
-
Start creating a new version
- In the Actions dropdown, select Modify template (Create new version)
-
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)
-
Review and create
- Optionally add a version description like "Enforce IMDSv2"
- Click Create launch template version
Step 3: Set the New Version as Default
-
Go back to the Launch Templates list
- Click Launch Templates in the breadcrumb or sidebar
-
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:
-
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)
-
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
- AWS Documentation: Configure Instance Metadata Options for New Instances
- AWS Documentation: Use IMDSv2
- AWS Blog: Defense in Depth - Open Firewalls, Reverse Proxies, SSRF Vulnerabilities, and IMDSv2
- AWS Security Hub Control: EC2.8 - EC2 instances should use IMDSv2
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-optionsto 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
HttpPutResponseHopLimitdefaults 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.