VPC Security Architecture (Subnets, Public/Private)
Key concepts
Public subnets have route to IGW
Private subnets use NAT for outbound
Subnet CIDR planning
Multi-AZ subnet design
Default vs custom VPCs
Overview
Amazon Virtual Private Cloud (VPC) is the foundational networking service for all AWS resources. A well-designed VPC architecture with proper subnet segregation is critical for security, providing network isolation and controlling traffic flow between resources.
Understanding the difference between public and private subnets, how routing tables work, and when to use each subnet type is essential for the SAA-C03 exam. VPC questions appear across all domains, testing both security and architectural knowledge.
The key principle is defense in depth: place resources in private subnets whenever possible, only exposing what absolutely needs public access. Load balancers and bastion hosts typically go in public subnets, while application servers and databases belong in private subnets.
Golden Rule
If a resource doesn't need direct internet access, put it in a private subnet. This single principle dramatically reduces your attack surface.
Know what makes a subnet 'public' vs 'private': A public subnet has a route to an Internet Gateway. A private subnet routes internet-bound traffic through a NAT Gateway/Instance instead. The subnet itself isn't inherently public or private - it's the route table that determines this.
Architecture Diagram

Key Concepts
What is a VPC?
Amazon VPC
Amazon VPC lets you provision a logically isolated section of the AWS Cloud where you can launch resources in a virtual network that you define.
Key Components:
- CIDR Block: IP address range for the VPC (e.g., 10.0.0.0/16)
- Subnets: Subdivisions of the VPC CIDR in specific AZs
- Route Tables: Control traffic routing for subnets
- Internet Gateway: Enables internet connectivity
- NAT Gateway: Enables outbound internet for private subnets
Default vs Custom VPC:
- AWS creates a default VPC in each region
- Default VPC has public subnets - not recommended for production
- Always create custom VPCs for production workloads
Public vs Private Subnets
Public Subnet
Public Subnet has a route to an Internet Gateway (IGW).
Characteristics:
- Resources CAN have public IP addresses
- Resources CAN be directly accessed from internet
- Route table has:
0.0.0.0/0 → igw-xxx
What Belongs Here:
- Application Load Balancers (ALB)
- NAT Gateways
- Bastion hosts (jump boxes)
- Public-facing web servers (if no ALB)
What Does NOT Belong Here:
- Databases
- Application servers
- Internal services
Private Subnet
Private Subnet does NOT have a direct route to an Internet Gateway.
Characteristics:
- Resources cannot have public IPs that work
- No direct inbound access from internet
- Outbound internet via NAT Gateway (if needed)
- Route table has:
0.0.0.0/0 → nat-xxx(optional)
What Belongs Here:
- Application/web servers (behind ALB)
- Databases (RDS, DynamoDB VPC endpoints)
- Cache servers (ElastiCache)
- Internal microservices
- Lambda functions (when VPC-connected)
Public vs Private Subnet Comparison
| Aspect | Public Subnet | Private Subnet |
|---|---|---|
| Route to IGW | Yes (0.0.0.0/0 → igw) | No |
| Public IP Works | Yes | No |
| Inbound from Internet | Possible | Not directly possible |
| Outbound to Internet | Direct via IGW | Via NAT Gateway |
| Typical Resources | ALB, NAT GW, Bastion | App servers, Databases |
| Security Level | Lower (exposed) | Higher (isolated) |
Route Tables
Route Tables
Route Tables contain rules (routes) that determine where network traffic is directed.
Key Concepts:
- Each subnet must be associated with exactly one route table
- Multiple subnets can share a route table
- Most specific route wins (longest prefix match)
- Local route (VPC CIDR) is always present and cannot be removed
Public Subnet Route Table:
Destination Target
10.0.0.0/16 local
0.0.0.0/0 igw-xxx
Private Subnet Route Table:
Destination Target
10.0.0.0/16 local
0.0.0.0/0 nat-xxx
CIDR Planning
CIDR Block Planning
CIDR (Classless Inter-Domain Routing) defines the IP address range for your VPC.
VPC CIDR Guidelines:
- Minimum: /28 (16 IPs)
- Maximum: /16 (65,536 IPs)
- Recommended: /16 for production VPCs
Subnet CIDR Guidelines:
- Subnets divide the VPC CIDR
- AWS reserves 5 IPs per subnet:
- .0 = Network address
- .1 = VPC router
- .2 = DNS server
- .3 = Reserved for future use
- .255 = Broadcast (not used but reserved)
Planning Tips:
- Use non-overlapping CIDRs if VPCs will peer
- Plan for growth - difficult to change later
- Document all CIDR allocations
Common CIDR Allocations
| CIDR | Total IPs | Usable IPs | Use Case |
|---|---|---|---|
| /16 | 65,536 | 65,531 | Large production VPC |
| /20 | 4,096 | 4,091 | Medium subnet |
| /24 | 256 | 251 | Small subnet, single tier |
| /28 | 16 | 11 | Minimum, very small workload |
How It Works
Multi-Tier VPC Architecture

Recommended Architecture Pattern
A production VPC should span multiple Availability Zones with dedicated subnet tiers:
Tier 1: Public Subnets (DMZ)
- One public subnet per AZ
- Contains: ALB, NAT Gateway, Bastion
- Smallest practical CIDR (/24 or smaller)
Tier 2: Private Application Subnets
- One private subnet per AZ
- Contains: EC2 instances, ECS tasks, Lambda
- Larger CIDR to accommodate scaling
Tier 3: Private Data Subnets
- One private subnet per AZ
- Contains: RDS, ElastiCache, DocumentDB
- Can be isolated (no internet route at all)
Traffic Flow Examples
Inbound Web Request
Internet → IGW → ALB (public subnet) → App Server (private subnet) → RDS (private subnet)
Outbound from Private Subnet
App Server (private subnet) → NAT Gateway (public subnet) → IGW → Internet
Internal Communication
App Server (private subnet) → RDS (private subnet) [stays within VPC]
Creating a Secure VPC
# Create VPC
aws ec2 create-vpc \
--cidr-block 10.0.0.0/16 \
--tag-specifications 'ResourceType=vpc,Tags=[{Key=Name,Value=Production-VPC}]'
# Create Internet Gateway
aws ec2 create-internet-gateway \
--tag-specifications 'ResourceType=internet-gateway,Tags=[{Key=Name,Value=Production-IGW}]'
# Attach IGW to VPC
aws ec2 attach-internet-gateway \
--vpc-id vpc-xxx \
--internet-gateway-id igw-xxx
# Create Public Subnet
aws ec2 create-subnet \
--vpc-id vpc-xxx \
--cidr-block 10.0.1.0/24 \
--availability-zone us-east-1a \
--tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=Public-1a}]'
# Create Private Subnet
aws ec2 create-subnet \
--vpc-id vpc-xxx \
--cidr-block 10.0.10.0/24 \
--availability-zone us-east-1a \
--tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=Private-1a}]'# Create public route table
aws ec2 create-route-table --vpc-id vpc-xxx
# Add internet route to public route table
aws ec2 create-route \
--route-table-id rtb-public \
--destination-cidr-block 0.0.0.0/0 \
--gateway-id igw-xxx
# Associate public subnet with public route table
aws ec2 associate-route-table \
--subnet-id subnet-public \
--route-table-id rtb-public
# Create NAT Gateway (in public subnet)
aws ec2 create-nat-gateway \
--subnet-id subnet-public \
--allocation-id eipalloc-xxx
# Create private route table with NAT Gateway route
aws ec2 create-route-table --vpc-id vpc-xxx
aws ec2 create-route \
--route-table-id rtb-private \
--destination-cidr-block 0.0.0.0/0 \
--nat-gateway-id nat-xxxUse Cases
Use Case 1: Three-Tier Web Application
Scenario: E-commerce application with web, app, and database tiers.

Architecture:
- Public subnets: Application Load Balancer
- Private app subnets: EC2 Auto Scaling group
- Private data subnets: RDS Multi-AZ, ElastiCache
Use Case 2: Serverless with VPC Resources
Scenario: Lambda functions need to access RDS database.

Architecture:
- Lambda functions deployed in private subnets
- RDS in private data subnets
- NAT Gateway only if Lambda needs internet access
Use Case 3: Hybrid Connectivity
Scenario: On-premises data center needs connectivity to AWS.

Architecture:
- VPN Gateway or Direct Connect attached to VPC
- Private subnets for hybrid workloads
- Route propagation from Virtual Private Gateway
Use Case 4: Isolated Data Processing
Scenario: Sensitive data processing that should never touch internet.

Architecture:
- Private subnets with NO internet route
- VPC endpoints for AWS service access (S3, DynamoDB)
- No NAT Gateway - completely air-gapped from internet
Best Practices
VPC Architecture Best Practices
- Don't Use Default VPC - Create custom VPCs for production
- Use Multiple AZs - Minimum 2, preferably 3 for HA
- Minimize Public Subnets - Only for resources requiring direct internet access
- Use Largest VPC CIDR - /16 gives room for growth
- Plan for Non-Overlapping CIDRs - Required for VPC peering/Transit Gateway
- Enable VPC Flow Logs - For traffic monitoring and troubleshooting
- Use VPC Endpoints - Avoid internet for AWS service access
- Document Your IP Scheme - Maintain CIDR allocation spreadsheet
Subnet Design Best Practices
- Dedicated Subnet Tiers - Separate public, app, and data
- Consistent CIDR Scheme - Easy to understand and troubleshoot
- Subnet per AZ per Tier - For proper high availability
- Smallest Practical Public Subnets - Reduce attack surface
- Larger Private Subnets - Room for application scaling
- Consider Future Growth - Subnets are hard to resize
Common Exam Scenarios
Exam Scenarios
| Scenario | Solution | Why |
|---|---|---|
| EC2 instance in private subnet needs to download patches | NAT Gateway in public subnet | Allows outbound internet without inbound |
| ALB needs to distribute traffic to EC2 | ALB in public subnet, EC2 in private | ALB is internet-facing, EC2 is protected |
| RDS should not be accessible from internet | Place RDS in private subnet | No route to IGW = no internet access |
| Lambda needs to access RDS and call external API | Lambda in private subnet with NAT Gateway | NAT enables outbound internet |
| Two VPCs need to communicate | VPC Peering or Transit Gateway | Requires non-overlapping CIDRs |
| Reduce NAT Gateway costs | VPC Endpoints for AWS services | S3/DynamoDB traffic stays in AWS network |
| Application needs consistent outbound IP | NAT Gateway (has static EIP) | All outbound traffic uses NAT EIP |
| Subnet running out of IPs | Cannot resize - create new larger subnet | CIDR cannot be changed after creation |
Common Pitfalls
Pitfall 1: Using Default VPC for Production
Mistake: Deploying production workloads in the default VPC.
Why it's dangerous:
- All subnets are public by default
- CIDR may overlap with other VPCs
- Less control over network architecture
- Hard to implement proper segmentation
Correct Approach:
- Create custom VPCs for production
- Design subnet tiers deliberately
- Use appropriate CIDR ranges
Pitfall 2: Placing Databases in Public Subnets
Mistake: Creating RDS instance in a public subnet "for easier access."
Why it's dangerous:
- Database exposed to internet attacks
- Single security group misconfiguration = breach
- Violates security best practices
Correct Approach:
- Always place databases in private subnets
- Access via bastion host or VPN if needed
- Use security groups to restrict access to app tier only
Pitfall 3: Single AZ Deployment
Mistake: Deploying all resources in a single Availability Zone.
Why it's risky:
- AZ failure = complete application outage
- No high availability
- Doesn't leverage AWS resilience
Correct Approach:
- Deploy across minimum 2 AZs
- Create subnets in each AZ
- Use ALB/NLB for distribution
- RDS Multi-AZ for databases
Pitfall 4: Overlapping CIDR Blocks
Mistake: Using same or overlapping CIDRs across VPCs.
Why it causes problems:
- Cannot create VPC peering
- Cannot use Transit Gateway
- Routing conflicts
- Integration headaches
Correct Approach:
- Plan CIDR allocation before creating VPCs
- Use different ranges for different environments
- Document all allocations
- Consider /16 per VPC with clear boundaries
Test Your Knowledge
What makes a subnet 'public' in AWS?
An EC2 instance in a private subnet needs to download software updates from the internet. What is the BEST solution?
How many IP addresses does AWS reserve in each subnet?
A company needs to connect two VPCs. VPC-A uses 10.0.0.0/16 and VPC-B uses 10.0.0.0/16. Can they be peered?
Related Services
Quick Reference
Common CIDR Allocations Example
VPC: 10.0.0.0/16 (65,536 IPs)
Public Subnets:
10.0.1.0/24 - Public-1a (251 IPs)
10.0.2.0/24 - Public-1b (251 IPs)
10.0.3.0/24 - Public-1c (251 IPs)
Private App Subnets:
10.0.10.0/24 - Private-App-1a (251 IPs)
10.0.11.0/24 - Private-App-1b (251 IPs)
10.0.12.0/24 - Private-App-1c (251 IPs)
Private Data Subnets:
10.0.20.0/24 - Private-Data-1a (251 IPs)
10.0.21.0/24 - Private-Data-1b (251 IPs)
10.0.22.0/24 - Private-Data-1c (251 IPs)
Reserved for Future:
10.0.100.0/24 - 10.0.255.0/24Key CLI Commands
# Describe VPCs
aws ec2 describe-vpcs
# Describe subnets
aws ec2 describe-subnets --filters "Name=vpc-id,Values=vpc-xxx"
# Describe route tables
aws ec2 describe-route-tables --filters "Name=vpc-id,Values=vpc-xxx"
# Create VPC Flow Log
aws ec2 create-flow-logs \
--resource-type VPC \
--resource-ids vpc-xxx \
--traffic-type ALL \
--log-destination-type cloud-watch-logs \
--log-group-name vpc-flow-logs
# Describe NAT Gateways
aws ec2 describe-nat-gateways --filter "Name=vpc-id,Values=vpc-xxx"VPC Limits
VPC Service Limits
| Resource | Default Limit | Can Increase? |
|---|---|---|
| VPCs per Region | 5 | Yes |
| Subnets per VPC | 200 | Yes |
| IPv4 CIDR blocks per VPC | 5 | Yes (up to 50) |
| Route tables per VPC | 200 | Yes |
| Routes per route table | 50 | Yes (up to 1,000) |
| Internet Gateways per Region | 5 | Yes |
| NAT Gateways per AZ | 5 | Yes |
| Elastic IPs per Region | 5 | Yes |