Skip to main content

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

  1. Sign in to the AWS Console and open the EC2 service
  2. In the left navigation, click Launch Templates
  3. Select the launch template flagged by Prowler
  4. Click Actions > Modify template (Create new version)
  5. Scroll down to Network settings and expand Advanced network configuration
  6. For Auto-assign public IP, select Disable
  7. Verify that no network interface in the configuration has a public IP assigned
  8. Check the box for Set the default version
  9. 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:

  1. In the EC2 console, go to Launch Templates
  2. Select your template and view the Default version
  3. 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

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 AssociatePublicIpAddress is 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.