EC2 Launch Templates Should Not Assign Public IPs
Overview
This check verifies that your EC2 launch templates do not automatically assign public IP addresses to network interfaces. Launch templates define how EC2 instances are configured when launched, and exposing instances directly to the internet creates unnecessary security risk.
Risk
When a launch template assigns public IP addresses, every instance launched from it becomes directly reachable from the internet. This exposure can lead to:
- Unauthorized access to your instances from anywhere on the internet
- Data exfiltration if an attacker gains access through exposed services
- DDoS and brute-force attacks targeting publicly accessible endpoints
- Lateral movement where attackers use compromised instances to access other resources in your VPC
Instances should remain in private subnets and access the internet through NAT gateways, load balancers, or VPN connections.
Remediation Steps
Prerequisites
You need permission to modify EC2 launch templates in your AWS account. If using the CLI, ensure the AWS CLI is installed and configured.
AWS Console Method
- Sign in to the AWS Console and open the EC2 service
- In the left navigation, click Launch Templates
- Select the launch template flagged by Prowler
- Click Actions > Modify template (Create new version)
- Scroll down to Network settings and expand Advanced network configuration
- For Auto-assign public IP, select Disable
- Verify that no network interface in the configuration has a public IP assigned
- Check the box for Set the default version
- Click Create template version
The new version with public IP disabled is now the default and will be used for future instance launches.
AWS CLI
Step 1: Identify affected launch templates
List your launch templates and their current configuration:
aws ec2 describe-launch-templates \
--region us-east-1 \
--query 'LaunchTemplates[*].[LaunchTemplateId,LaunchTemplateName,DefaultVersionNumber]' \
--output table
Step 2: Check the current network configuration
View the network interface settings for a specific template version:
aws ec2 describe-launch-template-versions \
--region us-east-1 \
--launch-template-id lt-0123456789abcdef0 \
--versions '$Default' \
--query 'LaunchTemplateVersions[0].LaunchTemplateData.NetworkInterfaces'
Step 3: Create a new version with public IP disabled
Create a new template version that disables public IP assignment:
aws ec2 create-launch-template-version \
--region us-east-1 \
--launch-template-id lt-0123456789abcdef0 \
--source-version '$Default' \
--launch-template-data '{
"NetworkInterfaces": [{
"DeviceIndex": 0,
"AssociatePublicIpAddress": false
}]
}'
Step 4: Set the new version as default
Update the launch template to use the new version as the default:
aws ec2 modify-launch-template \
--region us-east-1 \
--launch-template-id lt-0123456789abcdef0 \
--default-version <new-version-number>
Replace <new-version-number> with the version number returned from the previous command.
CloudFormation
Use this CloudFormation template to create a launch template with public IP disabled:
AWSTemplateFormatVersion: '2010-09-09'
Description: EC2 Launch Template with public IP disabled
Parameters:
LaunchTemplateName:
Type: String
Default: secure-launch-template
Description: Name for the launch template
SubnetId:
Type: AWS::EC2::Subnet::Id
Description: Subnet ID for the network interface
Resources:
SecureLaunchTemplate:
Type: AWS::EC2::LaunchTemplate
Properties:
LaunchTemplateName: !Ref LaunchTemplateName
LaunchTemplateData:
NetworkInterfaces:
- DeviceIndex: 0
AssociatePublicIpAddress: false
SubnetId: !Ref SubnetId
TagSpecifications:
- ResourceType: instance
Tags:
- Key: Environment
Value: production
Outputs:
LaunchTemplateId:
Description: The ID of the launch template
Value: !Ref SecureLaunchTemplate
LaunchTemplateDefaultVersion:
Description: The default version of the launch template
Value: !GetAtt SecureLaunchTemplate.DefaultVersionNumber
Deploy the template:
aws cloudformation deploy \
--region us-east-1 \
--template-file launch-template.yaml \
--stack-name secure-launch-template-stack \
--parameter-overrides SubnetId=subnet-0123456789abcdef0
Terraform
Use this Terraform configuration to create a launch template with public IP disabled:
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
provider "aws" {
region = "us-east-1"
}
variable "subnet_id" {
description = "Subnet ID for the network interface"
type = string
}
resource "aws_launch_template" "secure_template" {
name = "secure-launch-template"
description = "Launch template with public IP disabled"
network_interfaces {
device_index = 0
associate_public_ip_address = false
subnet_id = var.subnet_id
}
tags = {
Environment = "production"
}
}
output "launch_template_id" {
description = "The ID of the launch template"
value = aws_launch_template.secure_template.id
}
output "launch_template_latest_version" {
description = "The latest version of the launch template"
value = aws_launch_template.secure_template.latest_version
}
Apply the configuration:
terraform init
terraform apply -var="subnet_id=subnet-0123456789abcdef0"
Verification
After making changes, verify the remediation was successful:
- In the EC2 console, go to Launch Templates
- Select your template and view the Default version
- Under Network settings, confirm Auto-assign public IP shows Disable
CLI Verification
Run this command to verify the default version has public IP disabled:
aws ec2 describe-launch-template-versions \
--region us-east-1 \
--launch-template-id lt-0123456789abcdef0 \
--versions '$Default' \
--query 'LaunchTemplateVersions[0].LaunchTemplateData.NetworkInterfaces[*].AssociatePublicIpAddress'
The output should show [false] or [null] (null means the setting inherits from the subnet, which is acceptable if the subnet does not auto-assign public IPs).
Additional Resources
- AWS EC2 Launch Templates Documentation
- Change the default network interface settings
- VPC with Public and Private Subnets
- AWS Security Hub EC2 Controls
Notes
- Existing instances are not affected: Changing the launch template only affects future instance launches. Existing instances retain their current IP configuration.
- Auto Scaling Groups: If the launch template is used by an Auto Scaling group, new instances launched by the group will use the updated configuration. Consider terminating existing instances to trigger replacement with the secure configuration.
- Subnet default behavior: If
AssociatePublicIpAddressis not explicitly set, instances inherit the subnet's default behavior. Ensure your subnets also have auto-assign public IP disabled. - Private subnet access: Instances in private subnets can access the internet through NAT gateways or NAT instances. Use AWS Systems Manager Session Manager for remote access without exposing SSH/RDP ports.