Skip to main content

VPC Subnet Does Not Assign Public IP Addresses by Default

Overview

This check ensures that VPC subnets do not automatically assign public IPv4 addresses to instances launched within them. When MapPublicIpOnLaunch is set to true, every instance launched in that subnet automatically receives a public IP address, potentially exposing it to the internet.

Risk

When subnets automatically assign public IP addresses:

  • Reconnaissance exposure: Internet-facing instances can be discovered through port scanning and become targets for brute-force attacks against services like SSH and RDP
  • Data exfiltration: Compromised instances with public IPs provide a direct path for attackers to steal sensitive data
  • Unauthorized access: Misconfigured security groups combined with public IPs can lead to unauthorized access to internal resources
  • Compliance violations: Many compliance frameworks require workloads to be isolated from direct internet access

Severity: High

Remediation Steps

Prerequisites

You need permission to modify VPC subnet settings in the AWS account. Specifically, you need the ec2:ModifySubnetAttribute permission.

AWS Console Method

  1. Open the Amazon VPC console at https://console.aws.amazon.com/vpc/
  2. In the left navigation pane, click Subnets
  3. Select the subnet you want to modify
  4. Click Actions and then Edit subnet settings
  5. Under Auto-assign IP settings, uncheck Enable auto-assign public IPv4 address
  6. Click Save

Repeat for each subnet that has auto-assign public IP enabled.

AWS CLI (optional)

Disable auto-assign public IP for a single subnet:

aws ec2 modify-subnet-attribute \
--subnet-id subnet-0123456789abcdef0 \
--no-map-public-ip-on-launch \
--region us-east-1

Find all subnets with auto-assign public IP enabled:

aws ec2 describe-subnets \
--filters "Name=map-public-ip-on-launch,Values=true" \
--query "Subnets[*].[SubnetId,VpcId,CidrBlock,Tags[?Key=='Name'].Value|[0]]" \
--output table \
--region us-east-1

Disable auto-assign on all affected subnets (batch remediation):

for subnet_id in $(aws ec2 describe-subnets \
--filters "Name=map-public-ip-on-launch,Values=true" \
--query "Subnets[*].SubnetId" \
--output text \
--region us-east-1); do
echo "Disabling auto-assign public IP on $subnet_id"
aws ec2 modify-subnet-attribute \
--subnet-id "$subnet_id" \
--no-map-public-ip-on-launch \
--region us-east-1
done
CloudFormation (optional)

When creating new subnets with CloudFormation, explicitly set MapPublicIpOnLaunch to false:

AWSTemplateFormatVersion: '2010-09-09'
Description: VPC Subnet with public IP auto-assign disabled

Parameters:
VpcId:
Type: AWS::EC2::VPC::Id
Description: The VPC ID where the subnet will be created

SubnetCidrBlock:
Type: String
Default: 10.0.1.0/24
Description: CIDR block for the subnet

AvailabilityZone:
Type: AWS::EC2::AvailabilityZone::Name
Description: Availability Zone for the subnet

Resources:
PrivateSubnet:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VpcId
CidrBlock: !Ref SubnetCidrBlock
AvailabilityZone: !Ref AvailabilityZone
MapPublicIpOnLaunch: false
Tags:
- Key: Name
Value: private-subnet

Outputs:
SubnetId:
Description: The subnet ID
Value: !Ref PrivateSubnet
Export:
Name: !Sub '${AWS::StackName}-SubnetId'

Note: CloudFormation cannot modify existing subnet attributes directly. You must either:

  1. Delete and recreate the subnet (may require downtime)
  2. Use the AWS CLI to modify existing subnets outside of CloudFormation
Terraform (optional)

When creating new subnets with Terraform, set map_public_ip_on_launch to false:

terraform {
required_version = ">= 1.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 4.0"
}
}
}

variable "vpc_id" {
description = "The VPC ID where the subnet will be created"
type = string
}

variable "subnet_cidr_block" {
description = "CIDR block for the subnet"
type = string
default = "10.0.1.0/24"
}

variable "availability_zone" {
description = "Availability Zone for the subnet"
type = string
default = "us-east-1a"
}

resource "aws_subnet" "private" {
vpc_id = var.vpc_id
cidr_block = var.subnet_cidr_block
availability_zone = var.availability_zone
map_public_ip_on_launch = false

tags = {
Name = "private-subnet"
}
}

output "subnet_id" {
description = "The ID of the created subnet"
value = aws_subnet.private.id
}

For existing subnets managed by Terraform: Update the map_public_ip_on_launch attribute to false and run terraform apply. Terraform will modify the subnet in place without recreation.

Verification

After making changes, verify that the subnet no longer auto-assigns public IPs:

  1. In the VPC console, select the subnet
  2. Check the Auto-assign public IPv4 address field in the details panel - it should show No
CLI verification
aws ec2 describe-subnets \
--subnet-ids subnet-0123456789abcdef0 \
--query "Subnets[0].MapPublicIpOnLaunch" \
--region us-east-1

The output should be false.

Verify no subnets have auto-assign enabled:

aws ec2 describe-subnets \
--filters "Name=map-public-ip-on-launch,Values=true" \
--query "Subnets[*].SubnetId" \
--output text \
--region us-east-1

An empty result confirms all subnets have auto-assign disabled.

Additional Resources

Notes

  • Existing instances are not affected: Disabling auto-assign only affects new instances. Existing instances keep their current public IP assignments.
  • Elastic IPs still work: You can still manually assign Elastic IPs to instances in private subnets when needed.
  • Internet access alternatives: Instances in private subnets can access the internet through a NAT Gateway or NAT Instance without having public IPs.
  • Consider your architecture: Some subnets (like those hosting public-facing load balancers) may legitimately need public IP assignment. Evaluate each subnet based on its purpose.
  • Use SSM Session Manager: For administrative access to private instances, consider using AWS Systems Manager Session Manager instead of bastion hosts with public IPs.