AWS VPC Networking: Subnets, NAT, and Security Groups
Learn AWS VPC networking fundamentals including subnets, NAT gateways, route tables, security groups, and NACLs to build secure cloud architectures.
What you'll learn
- ✓Design VPC architectures with public and private subnets
- ✓Configure NAT Gateways for private subnet internet access
- ✓Set up Security Groups and NACLs for layered security
- ✓Build route tables that control traffic flow
Prerequisites
- •AWS account with admin access
- •Basic understanding of IP addressing and CIDR notation
Amazon Virtual Private Cloud (VPC) is the networking foundation of every AWS deployment. Whether you are running a single EC2 instance or a fleet of containers behind a load balancer, the VPC defines how traffic flows, who can reach what, and how your resources connect to the internet and each other.
This guide walks through every essential VPC component, explains how they fit together, and provides working configurations you can deploy today.
What Is a VPC and Why It Matters
A VPC is a logically isolated section of the AWS cloud where you launch resources in a virtual network you define. You control the IP address range, create subnets, configure route tables, and set up gateways.
Every AWS account comes with a default VPC in each region, but production workloads should always use a custom VPC. The default VPC has permissive settings that make it easy to get started but difficult to secure at scale.
Key benefits of a custom VPC:
- Full control over IP addressing so you can plan for growth and avoid conflicts with on-premises networks
- Network segmentation to isolate workloads by tier, environment, or compliance boundary
- Fine-grained security through security groups, NACLs, and private subnets
- Connectivity options including VPN, Direct Connect, VPC peering, and Transit Gateway
Planning Your CIDR Block
The CIDR block defines the IP address range for your entire VPC. Choose carefully because you cannot change the primary CIDR after creation, though you can add secondary CIDRs later.
Common CIDR ranges for production VPCs:
# Small VPC - 256 addresses
CIDR: 10.0.0.0/24
# Medium VPC - 4,096 addresses (recommended for most workloads)
CIDR: 10.0.0.0/20
# Large VPC - 65,536 addresses
CIDR: 10.0.0.0/16
A /16 VPC gives you 65,536 addresses, which is usually more than enough. The bigger concern is avoiding overlap with other VPCs you might peer with or on-premises networks you might connect to via VPN.
Subnets: Public vs Private
Subnets divide your VPC into smaller segments, each mapped to a single Availability Zone (AZ). The distinction between public and private subnets is not a property of the subnet itself but rather the route table attached to it.
- Public subnet: Route table includes a route to an Internet Gateway (IGW)
- Private subnet: No direct route to the internet; traffic goes through a NAT Gateway or stays internal
A typical three-tier architecture uses six subnets across two AZs:
# Subnet layout for a production VPC (10.0.0.0/16)
Public Subnets:
- 10.0.1.0/24 (us-east-1a) - Load balancers, bastion hosts
- 10.0.2.0/24 (us-east-1b) - Load balancers, bastion hosts
Private App Subnets:
- 10.0.10.0/24 (us-east-1a) - Application servers, containers
- 10.0.11.0/24 (us-east-1b) - Application servers, containers
Private Data Subnets:
- 10.0.20.0/24 (us-east-1a) - RDS, ElastiCache, other databases
- 10.0.21.0/24 (us-east-1b) - RDS, ElastiCache, other databases
Here is a CloudFormation snippet that creates this layout:
Resources:
ProductionVPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: 10.0.0.0/16
EnableDnsSupport: true
EnableDnsHostnames: true
Tags:
- Key: Name
Value: production-vpc
PublicSubnetA:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref ProductionVPC
CidrBlock: 10.0.1.0/24
AvailabilityZone: !Select [0, !GetAZs '']
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: public-subnet-a
PrivateAppSubnetA:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref ProductionVPC
CidrBlock: 10.0.10.0/24
AvailabilityZone: !Select [0, !GetAZs '']
Tags:
- Key: Name
Value: private-app-subnet-a
PrivateDataSubnetA:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref ProductionVPC
CidrBlock: 10.0.20.0/24
AvailabilityZone: !Select [0, !GetAZs '']
Tags:
- Key: Name
Value: private-data-subnet-a
Internet Gateway and Route Tables
An Internet Gateway (IGW) allows resources in public subnets to communicate with the internet. You attach one IGW per VPC and then create a route in the public subnet’s route table pointing 0.0.0.0/0 to the IGW.
InternetGateway:
Type: AWS::EC2::InternetGateway
AttachGateway:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
VpcId: !Ref ProductionVPC
InternetGatewayId: !Ref InternetGateway
PublicRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref ProductionVPC
PublicRoute:
Type: AWS::EC2::Route
Properties:
RouteTableId: !Ref PublicRouteTable
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref InternetGateway
PublicSubnetARouteAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref PublicSubnetA
RouteTableId: !Ref PublicRouteTable
Each subnet can be associated with exactly one route table. If you do not explicitly associate a subnet with a route table, it uses the VPC’s main route table. This is a common source of misconfigurations, so always create explicit associations.
NAT Gateways for Private Subnet Internet Access
Resources in private subnets often need outbound internet access to download packages, call external APIs, or reach AWS service endpoints. A NAT Gateway provides this access without exposing the resources to inbound internet traffic.
NAT Gateways live in a public subnet and require an Elastic IP address:
NatElasticIP:
Type: AWS::EC2::EIP
Properties:
Domain: vpc
NatGateway:
Type: AWS::EC2::NatGateway
Properties:
AllocationId: !GetAtt NatElasticIP.AllocationId
SubnetId: !Ref PublicSubnetA
PrivateRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref ProductionVPC
PrivateRoute:
Type: AWS::EC2::Route
Properties:
RouteTableId: !Ref PrivateRouteTable
DestinationCidrBlock: 0.0.0.0/0
NatGatewayId: !Ref NatGateway
PrivateAppSubnetARouteAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref PrivateAppSubnetA
RouteTableId: !Ref PrivateRouteTable
NAT Gateways cost roughly $0.045/hour plus data processing charges. For high-availability, deploy one NAT Gateway per AZ. For dev/test environments, a single NAT Gateway or even a NAT instance can save costs.
An alternative to NAT Gateways is VPC Endpoints, which allow private subnets to reach AWS services like S3 and DynamoDB without going through the internet at all. Gateway endpoints for S3 and DynamoDB are free.
Security Groups: Stateful Instance-Level Firewalls
Security groups act as virtual firewalls at the instance level. They are stateful, meaning if you allow inbound traffic on a port, the response traffic is automatically allowed outbound regardless of outbound rules.
Key characteristics:
- Allow rules only - you cannot create deny rules
- Stateful - return traffic is automatically allowed
- Instance level - attached to ENIs (network interfaces)
- Evaluated as a group - all rules are evaluated before deciding to allow traffic
Here is a practical security group configuration for a three-tier application:
ALBSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Allow HTTP/HTTPS from internet
VpcId: !Ref ProductionVPC
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 443
ToPort: 443
CidrIp: 0.0.0.0/0
- IpProtocol: tcp
FromPort: 80
ToPort: 80
CidrIp: 0.0.0.0/0
AppSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Allow traffic from ALB only
VpcId: !Ref ProductionVPC
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 8080
ToPort: 8080
SourceSecurityGroupId: !Ref ALBSecurityGroup
DatabaseSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Allow traffic from app tier only
VpcId: !Ref ProductionVPC
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 5432
ToPort: 5432
SourceSecurityGroupId: !Ref AppSecurityGroup
Notice how each security group references the previous tier’s group ID rather than IP addresses. This is a best practice because it automatically adapts as instances scale up and down.
Network ACLs: Stateless Subnet-Level Firewalls
Network Access Control Lists (NACLs) operate at the subnet level and are stateless. Unlike security groups, NACLs support both allow and deny rules and are evaluated in order by rule number.
NACLs serve as a second layer of defense. The default NACL allows all inbound and outbound traffic. For production, consider tightening these rules:
PrivateDataNACL:
Type: AWS::EC2::NetworkAcl
Properties:
VpcId: !Ref ProductionVPC
# Allow inbound PostgreSQL from app subnets
InboundPostgres:
Type: AWS::EC2::NetworkAclEntry
Properties:
NetworkAclId: !Ref PrivateDataNACL
RuleNumber: 100
Protocol: 6
RuleAction: allow
CidrBlock: 10.0.10.0/23
PortRange:
From: 5432
To: 5432
# Allow return traffic (ephemeral ports)
InboundEphemeral:
Type: AWS::EC2::NetworkAclEntry
Properties:
NetworkAclId: !Ref PrivateDataNACL
RuleNumber: 200
Protocol: 6
RuleAction: allow
CidrBlock: 10.0.0.0/16
PortRange:
From: 1024
To: 65535
# Deny everything else inbound
InboundDenyAll:
Type: AWS::EC2::NetworkAclEntry
Properties:
NetworkAclId: !Ref PrivateDataNACL
RuleNumber: 999
Protocol: -1
RuleAction: deny
CidrBlock: 0.0.0.0/0
Because NACLs are stateless, you must explicitly allow return traffic on ephemeral ports (1024-65535). This is the most common mistake when working with NACLs.
VPC Flow Logs for Visibility
VPC Flow Logs capture information about IP traffic going to and from network interfaces in your VPC. They are essential for troubleshooting connectivity issues and security monitoring.
VPCFlowLog:
Type: AWS::EC2::FlowLog
Properties:
ResourceId: !Ref ProductionVPC
ResourceType: VPC
TrafficType: ALL
LogDestinationType: cloud-watch-logs
LogGroupName: /aws/vpc/flow-logs
DeliverLogsPermissionArn: !GetAtt FlowLogRole.Arn
Flow log records show source IP, destination IP, ports, protocol, action (ACCEPT/REJECT), and byte counts. Send them to CloudWatch Logs for real-time monitoring or S3 for long-term analysis with Athena.
VPC Endpoints: Keeping Traffic Private
VPC Endpoints let your private subnets access AWS services without sending traffic over the internet. There are two types:
- Gateway Endpoints (free): S3 and DynamoDB only. Added as a route table entry.
- Interface Endpoints (paid): Most other AWS services. Creates an ENI in your subnet with a private IP.
S3GatewayEndpoint:
Type: AWS::EC2::VPCEndpoint
Properties:
ServiceName: !Sub com.amazonaws.${AWS::Region}.s3
VpcId: !Ref ProductionVPC
RouteTableIds:
- !Ref PrivateRouteTable
VpcEndpointType: Gateway
SecretsManagerEndpoint:
Type: AWS::EC2::VPCEndpoint
Properties:
ServiceName: !Sub com.amazonaws.${AWS::Region}.secretsmanager
VpcId: !Ref ProductionVPC
SubnetIds:
- !Ref PrivateAppSubnetA
- !Ref PrivateAppSubnetB
VpcEndpointType: Interface
PrivateDnsEnabled: true
SecurityGroupIds:
- !Ref EndpointSecurityGroup
Gateway endpoints for S3 are free and should always be configured. They reduce NAT Gateway data processing costs and improve security by keeping S3 traffic within the AWS network.
Common VPC Design Mistakes
Undersized CIDR blocks. Start with a /16 unless you have a reason not to. Running out of IP addresses in a VPC is painful to fix.
Single AZ deployments. Always spread subnets across at least two AZs for high availability. An AZ outage should not take down your entire application.
Overly permissive security groups. Never use 0.0.0.0/0 on application or database security groups. Reference other security groups by ID instead.
No VPC endpoints. Without endpoints, traffic to S3 and DynamoDB from private subnets goes through the NAT Gateway, adding cost and latency.
Ignoring flow logs. Enable flow logs from day one. You will need them when troubleshooting connectivity or investigating security incidents.
Wrapping Up
AWS VPC networking is the foundation that every other service builds on. A well-designed VPC uses multiple AZs, separates public and private tiers, employs security groups and NACLs for defense in depth, and uses VPC endpoints to keep traffic private and reduce costs.
Start with the three-tier architecture described here and adjust based on your workload. The time you invest in VPC design pays dividends in security, reliability, and operational simplicity as your infrastructure grows.
Related articles
- AWS AWS PrivateLink Explained: VPC Endpoints Without the Internet
Understand AWS PrivateLink: interface endpoints, endpoint services, how it differs from VPC peering and Transit Gateway, and when to choose it for private connectivity.
- AWS AWS API Gateway vs ALB: Choosing the Right Entry Point
Compare API Gateway and Application Load Balancer for fronting AWS workloads, including features, pricing, latency, and when to use each in production.
- AWS AWS Route 53 Routing Policies Explained
Understand simple, weighted, latency, failover, geolocation, and multivalue routing policies in Amazon Route 53 with real examples.
- AWS AWS VPC Basics: Subnets, Route Tables, and Gateways
Understand AWS VPC fundamentals: public vs private subnets, internet and NAT gateways, route tables, and the difference between security groups and NACLs.