Back to Checks
aws

Amazon EC2 launch template has no public IP addresses configured on network interfaces

ec2_launch_template_no_public_ip
Service: ec2Severity: high
OfficialBuilt-inVerified
Categories:internet-exposed
Resource Type:AwsEc2LaunchTemplate

EC2 launch templates with versions that either enable associate_public_ip_address for network interfaces or reference ENIs already associated with public IPs

Risk

Assigning public IPs makes instances Internet-reachable, enabling:

  • Loss of confidentiality via unauthorized access and data exfiltration
  • Compromised integrity through remote exploitation and tampering
  • Reduced availability from DDoS and brute-force traffic Attackers can scan exposed services and pivot within the VPC.

Run this check with Prowler

Run in Prowler Cloud
Run
prowler aws --checks ec2_launch_template_no_public_ip

Recommendation

Apply least privilege and network segmentation:

  • Set associate_public_ip_address=false in launch templates
  • Avoid referencing ENIs with public IPs
  • Place instances in private subnets behind NAT/ALB
  • Use Session Manager, bastions, or VPC endpoints/PrivateLink for access Adopt defense in depth to minimize exposure.

Remediation

CLI

aws ec2 create-launch-template-version --launch-template-id <example_resource_id> --launch-template-data '{"NetworkInterfaces":[{"DeviceIndex":0,"AssociatePublicIpAddress":false}]}' --set-default-version

Terraform

# EC2 launch template configured to not assign public IPs
resource "aws_launch_template" "<example_resource_name>" {
  name = "<example_resource_name>"

  network_interfaces {
    device_index                = 0
    associate_public_ip_address = false  # Critical: disables public IP assignment on the primary ENI
  }
}

NativeIaC

# CloudFormation: Launch template configured to not assign public IPs
Resources:
  <example_resource_name>:
    Type: AWS::EC2::LaunchTemplate
    Properties:
      LaunchTemplateData:
        NetworkInterfaces:
          - DeviceIndex: 0
            AssociatePublicIpAddress: false  # Critical: disables public IP assignment on the primary ENI

Other

1Open the EC2 console and go to Launch Templates
2Select the template and choose Actions > Create new version
3Under Network settings > Advanced network configuration, set Auto-assign public IP to Disable
4Ensure no Network interface is attached that already has a public IP
5Check Set as default version and choose Create launch template version

Check Code

from prowler.lib.check.models import Check, Check_Report_AWS
from prowler.providers.aws.services.ec2.ec2_client import ec2_client


class ec2_launch_template_no_public_ip(Check):
    def execute(self):
        findings = []
        for template in ec2_client.launch_templates:
            report = Check_Report_AWS(metadata=self.metadata(), resource=template)

            versions_with_autoassign_public_ip = []
            versions_with_network_interfaces_public_ip = []

            for version in template.versions:
                # Check if the launch template version assigns a public IP address
                if version.template_data.associate_public_ip_address:
                    versions_with_autoassign_public_ip.append(
                        str(version.version_number)
                    )
                if version.template_data.network_interfaces:
                    for network_interface in version.template_data.network_interfaces:
                        if network_interface.public_ip_addresses:
                            versions_with_network_interfaces_public_ip.append(
                                str(version.version_number)
                            )
                            break

            if (
                versions_with_autoassign_public_ip
                or versions_with_network_interfaces_public_ip
            ):
                report.status = "FAIL"

                if (
                    versions_with_autoassign_public_ip
                    and versions_with_network_interfaces_public_ip
                ):
                    report.status_extended = f"EC2 Launch Template {template.name} is configured to assign a public IP address to network interfaces upon launch in template versions: {', '.join(versions_with_autoassign_public_ip)} and is using a network interface with public IP addresses in template versions: {', '.join(versions_with_network_interfaces_public_ip)}."
                elif versions_with_autoassign_public_ip:
                    report.status_extended = f"EC2 Launch Template {template.name} is configured to assign a public IP address to network interfaces upon launch in template versions: {', '.join(versions_with_autoassign_public_ip)}."
                elif versions_with_network_interfaces_public_ip:
                    report.status_extended = f"EC2 Launch Template {template.name} is using a network interface with public IP addresses in template versions: {', '.join(versions_with_network_interfaces_public_ip)}."
            else:
                report.status = "PASS"
                report.status_extended = f"EC2 Launch Template {template.name} is neither configured to assign a public IP address to network interfaces upon launch nor using a network interface with public IP addresses."
            findings.append(report)

        return findings