You are viewing a preview of this lesson. Sign in to start learning
Back to Mastering AWS

VPC & Networking Deep Dive

Subnets, routing tables, NAT gateways, VPC endpoints, and network connectivity patterns

VPC & Networking Deep Dive

Master AWS networking architecture with free flashcards and hands-on configuration practice. This lesson covers Virtual Private Clouds (VPCs), subnets, routing, internet gateways, NAT gateways, security groups, and network ACLsβ€”essential concepts for building secure, scalable cloud infrastructure and passing the AWS Solutions Architect certification.

Welcome to AWS Networking

πŸ’» Understanding AWS networking is fundamental to building secure and performant cloud applications. Amazon Virtual Private Cloud (VPC) gives you complete control over your virtual networking environment, including IP address ranges, subnets, route tables, and network gateways. Whether you're deploying a simple web application or a complex multi-tier architecture, VPC networking forms the foundation of your AWS infrastructure.

Think of a VPC as your own isolated data center in the cloudβ€”but with the flexibility, scalability, and managed services that AWS provides. Unlike traditional networking, where physical constraints limit your options, AWS VPC lets you define network topologies programmatically and modify them on demand.

πŸ” Security is built into every layer of AWS networking, from subnet isolation to security groups and network ACLs. Understanding these components and how they interact is crucial for architecting solutions that meet compliance requirements while maintaining operational efficiency.


Core Concepts

🌐 Virtual Private Cloud (VPC)

A VPC is a logically isolated section of the AWS cloud where you launch AWS resources in a virtual network that you define. Each VPC exists within a single AWS Region but can span multiple Availability Zones.

Key characteristics:

  • CIDR block: You assign an IPv4 CIDR block when creating a VPC (e.g., 10.0.0.0/16)
  • Regional scope: VPCs cannot span regions, but you can connect VPCs across regions using VPC peering or Transit Gateway
  • Default vs Custom: Each AWS account comes with a default VPC in each region, but you should create custom VPCs for production workloads
  • Tenancy: Choose between default (shared hardware) or dedicated (single-tenant hardware)
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                      AWS REGION (us-east-1)                 β”‚
β”‚                                                             β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚  β”‚            VPC (10.0.0.0/16)                          β”‚ β”‚
β”‚  β”‚                                                       β”‚ β”‚
β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”       β”‚ β”‚
β”‚  β”‚  β”‚ Availability     β”‚    β”‚ Availability     β”‚       β”‚ β”‚
β”‚  β”‚  β”‚ Zone A           β”‚    β”‚ Zone B           β”‚       β”‚ β”‚
β”‚  β”‚  β”‚                  β”‚    β”‚                  β”‚       β”‚ β”‚
β”‚  β”‚  β”‚ πŸ–₯️ Subnets       β”‚    β”‚ πŸ–₯️ Subnets       β”‚       β”‚ β”‚
β”‚  β”‚  β”‚ πŸ”’ Security      β”‚    β”‚ πŸ”’ Security      β”‚       β”‚ β”‚
β”‚  β”‚  β”‚ πŸ“‘ Resources     β”‚    β”‚ πŸ“‘ Resources     β”‚       β”‚ β”‚
β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜       β”‚ β”‚
β”‚  β”‚                                                       β”‚ β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚                                                             β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

πŸ’‘ Best Practice: Use RFC 1918 private IP ranges for your VPCs:

  • 10.0.0.0/8 (10.0.0.0 - 10.255.255.255)
  • 172.16.0.0/12 (172.16.0.0 - 172.31.255.255)
  • 192.168.0.0/16 (192.168.0.0 - 192.168.255.255)

πŸ”’ Subnets

Subnets are subdivisions of your VPC's IP address range where you actually launch resources. Each subnet exists within a single Availability Zone and must be associated with a route table.

Types of subnets:

Subnet TypeRoute to InternetUse CaseExample Resources
Public Subnetβœ… Via Internet GatewayInternet-facing resourcesWeb servers, load balancers, NAT gateways
Private Subnet❌ No direct routeBackend resourcesDatabases, application servers, Lambda functions
VPN-Only SubnetπŸ” Via Virtual Private GatewayHybrid connectivityOn-premises integration resources

CIDR block considerations:

  • AWS reserves 5 IP addresses in every subnet
  • First 4 IPs and last IP are reserved
  • Example: In 10.0.1.0/24 (256 IPs), only 251 are usable
Reserved IPs in 10.0.1.0/24:
- 10.0.1.0   β†’ Network address
- 10.0.1.1   β†’ VPC router
- 10.0.1.2   β†’ DNS server
- 10.0.1.3   β†’ Reserved for future use
- 10.0.1.255 β†’ Network broadcast

🧠 Memory Device - Public vs Private: "Public subnets are like a shop with street-facing windows (IGW)β€”anyone can see in. Private subnets are like the back roomβ€”no windows, just a delivery door (NAT) if you need to send things out."

πŸšͺ Internet Gateway (IGW)

An Internet Gateway is a horizontally scaled, redundant, and highly available VPC component that allows communication between instances in your VPC and the internet.

Key properties:

  • One per VPC: Each VPC can have only one IGW attached
  • Highly available: AWS-managed, no single point of failure
  • No bandwidth constraints: Scales automatically
  • Performs NAT: Translates private IP to public IP for instances with public IPs

How it works:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                  INTERNET                           β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                    β”‚
                    β–Ό
          β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
          β”‚ Internet Gatewayβ”‚ ← Attached to VPC
          β”‚     (IGW)       β”‚
          β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                   β”‚
    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
    β”‚      Route Table            β”‚
    β”‚  0.0.0.0/0 β†’ IGW            β”‚ ← Public route
    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                   β”‚
         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
         β”‚   Public Subnet   β”‚
         β”‚                   β”‚
         β”‚  πŸ–₯️ EC2 Instance  β”‚ ← Has public IP
         β”‚  Private: 10.0.1.5β”‚
         β”‚  Public: 54.x.x.x β”‚
         β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Configuration example:

## Create Internet Gateway
aws ec2 create-internet-gateway \
  --tag-specifications 'ResourceType=internet-gateway,Tags=[{Key=Name,Value=my-igw}]'

## Attach to VPC
aws ec2 attach-internet-gateway \
  --internet-gateway-id igw-1234567890abcdef0 \
  --vpc-id vpc-0abcd1234efgh5678

## Add route to route table
aws ec2 create-route \
  --route-table-id rtb-1234567890abcdef0 \
  --destination-cidr-block 0.0.0.0/0 \
  --gateway-id igw-1234567890abcdef0

πŸ”„ NAT Gateway vs NAT Instance

NAT (Network Address Translation) allows instances in private subnets to initiate outbound traffic to the internet while preventing inbound connections from the internet.

FeatureNAT GatewayNAT Instance
AvailabilityHighly available within AZSingle point of failure
BandwidthUp to 45 GbpsDepends on instance type
MaintenanceAWS-managedYou manage
CostPer hour + data transferEC2 instance cost
Security GroupsCannot be associatedCan use security groups
Port ForwardingNot supportedManual configuration
Bastion ServerNot supportedCan be used as bastion

πŸ’‘ Best Practice: Use NAT Gateway for production workloads. NAT instances are only cost-effective for development/testing or when you need bastion host functionality.

NAT Gateway architecture:

                    INTERNET
                       ↑
                       β”‚
              β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”
              β”‚ Internet Gatewayβ”‚
              β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                       β”‚
         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
         β”‚    Public Subnet (AZ-A)    β”‚
         β”‚                            β”‚
         β”‚   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”‚
         β”‚   β”‚   NAT Gateway    β”‚ ←───┼─── Elastic IP
         β”‚   β”‚  (nat-gateway)   β”‚     β”‚
         β”‚   β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β”‚
         β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                      β”‚
                      β”‚ Route: 0.0.0.0/0 β†’ NAT
                      ↓
         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
         β”‚   Private Subnet (AZ-A)    β”‚
         β”‚                            β”‚
         β”‚   πŸ–₯️ EC2 (10.0.2.10)       β”‚ ← Can reach internet
         β”‚   πŸ’Ύ RDS (10.0.2.20)       β”‚   (outbound only)
         β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
## Create NAT Gateway
aws ec2 create-nat-gateway \
  --subnet-id subnet-1234567890abcdef0 \
  --allocation-id eipalloc-0abcd1234efgh5678

## Update private subnet route table
aws ec2 create-route \
  --route-table-id rtb-private123 \
  --destination-cidr-block 0.0.0.0/0 \
  --nat-gateway-id nat-0abcd1234efgh5678

⚠️ High Availability: Deploy one NAT Gateway per Availability Zone. If an AZ fails, resources in other AZs won't be affected.

πŸ“‹ Route Tables

Route tables contain rules (routes) that determine where network traffic is directed. Every subnet must be associated with a route table.

Route components:

  • Destination: CIDR block to match
  • Target: Where to send matching traffic (IGW, NAT, VGW, local, etc.)
  • Propagation: Routes can be static or dynamically propagated

Example route tables:

Public Subnet Route Table:

DestinationTargetPurpose
10.0.0.0/16localVPC internal communication
0.0.0.0/0igw-xxxxxInternet access

Private Subnet Route Table:

DestinationTargetPurpose
10.0.0.0/16localVPC internal communication
0.0.0.0/0nat-xxxxxOutbound internet via NAT

Route priority: When multiple routes match, AWS uses the most specific route (longest prefix match).

Example: Traffic to 10.0.1.50

Route table:
- 10.0.0.0/16  β†’ local
- 10.0.1.0/24  β†’ vgw-xxxxx
- 0.0.0.0/0    β†’ igw-xxxxx

Result: Uses 10.0.1.0/24 route (most specific)

πŸ’‘ Exam Tip: The "local" route is automatically created and cannot be deleted. It enables communication within the VPC.

πŸ”’ Security Groups

Security Groups act as virtual firewalls for EC2 instances, controlling inbound and outbound traffic at the instance level. They are statefulβ€”return traffic is automatically allowed.

Key characteristics:

  • Stateful: If you allow inbound traffic, outbound response is automatically allowed
  • Allow rules only: You cannot create deny rules (use NACLs for that)
  • Default deny: All inbound traffic is denied by default
  • Default allow: All outbound traffic is allowed by default
  • Multiple SGs: An instance can have multiple security groups
  • Changes apply immediately: No need to reboot instances

Security Group example:

{
  "GroupName": "web-server-sg",
  "Description": "Security group for web servers",
  "InboundRules": [
    {
      "IpProtocol": "tcp",
      "FromPort": 80,
      "ToPort": 80,
      "IpRanges": ["0.0.0.0/0"]
    },
    {
      "IpProtocol": "tcp",
      "FromPort": 443,
      "ToPort": 443,
      "IpRanges": ["0.0.0.0/0"]
    },
    {
      "IpProtocol": "tcp",
      "FromPort": 22,
      "ToPort": 22,
      "IpRanges": ["203.0.113.0/24"]
    }
  ],
  "OutboundRules": [
    {
      "IpProtocol": "-1",
      "IpRanges": ["0.0.0.0/0"]
    }
  ]
}

Referencing other security groups:

## Allow traffic from another security group
aws ec2 authorize-security-group-ingress \
  --group-id sg-database123 \
  --protocol tcp \
  --port 3306 \
  --source-group sg-webserver456

This allows database access only from instances in the web server security groupβ€”no hardcoded IPs needed!

πŸ›‘οΈ Network Access Control Lists (NACLs)

Network ACLs are stateless firewalls that operate at the subnet level. They provide an additional layer of security beyond security groups.

Key characteristics:

  • Stateless: Return traffic must be explicitly allowed
  • Allow and deny rules: You can create both allow and deny rules
  • Rule evaluation: Rules are evaluated in order, starting with the lowest number
  • Default NACL: Allows all inbound and outbound traffic
  • Custom NACL: Denies all traffic by default until you add rules
  • One per subnet: Each subnet must be associated with exactly one NACL
FeatureSecurity GroupNetwork ACL
LevelInstance levelSubnet level
StateStatefulStateless
RulesAllow onlyAllow and deny
Rule processingAll rules evaluatedRules in order until match
Applied toSpecific instancesAll instances in subnet
DefaultDeny all inboundAllow all traffic

NACL rule example:

Rule #TypeProtocolPort RangeSourceAllow/Deny
100HTTPTCP800.0.0.0/0ALLOW
110HTTPSTCP4430.0.0.0/0ALLOW
120SSHTCP22203.0.113.0/24ALLOW
130EphemeralTCP1024-655350.0.0.0/0ALLOW
*AllAllAll0.0.0.0/0DENY

⚠️ Critical: Remember to allow ephemeral ports (1024-65535) for return traffic in NACLs, since they're stateless!

🧠 Memory Device - SG vs NACL: "Security Groups are like a bouncer who remembers you (stateful)β€”once you're in, you can leave freely. NACLs are like a border checkpoint (stateless)β€”you need documents both entering AND leaving."

πŸ”— VPC Peering

VPC Peering is a networking connection between two VPCs that enables routing using private IP addresses. Peered VPCs can be in different regions or AWS accounts.

Characteristics:

  • Not transitive: If VPC A peers with VPC B, and VPC B peers with VPC C, VPC A cannot reach VPC C
  • No overlapping CIDR: VPCs must have non-overlapping IP ranges
  • Cross-region: Peering works across regions
  • Cross-account: You can peer VPCs in different AWS accounts
  • Cost: Data transfer charges apply
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   VPC A         β”‚         β”‚   VPC B         β”‚
β”‚  10.0.0.0/16    │◄───────►│  10.1.0.0/16    β”‚
β”‚                 β”‚  Peering β”‚                 β”‚
β”‚  πŸ–₯️ App Servers β”‚         β”‚  πŸ’Ύ Databases   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜         β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
         ↕                           ↕
    Route table                 Route table
  10.1.0.0/16 β†’ pcx-xxx      10.0.0.0/16 β†’ pcx-xxx

Non-transitive example:

β”Œβ”€β”€β”€β”€β”€β”€β”         β”Œβ”€β”€β”€β”€β”€β”€β”         β”Œβ”€β”€β”€β”€β”€β”€β”
β”‚VPC A │◄───────►│VPC B │◄───────►│VPC C β”‚
β”‚10.0.xβ”‚  Peer   β”‚10.1.xβ”‚  Peer   β”‚10.2.xβ”‚
β””β”€β”€β”€β”€β”€β”€β”˜         β””β”€β”€β”€β”€β”€β”€β”˜         β””β”€β”€β”€β”€β”€β”€β”˜

❌ VPC A CANNOT talk to VPC C
βœ… Must create direct peering A↔C

πŸ’‘ Alternative: For complex hub-and-spoke topologies, consider AWS Transit Gateway instead of multiple peering connections.

🌐 VPC Endpoints

VPC Endpoints enable private connections between your VPC and AWS services without requiring an Internet Gateway, NAT device, VPN, or Direct Connect.

Types:

1. Interface Endpoints (AWS PrivateLink)

  • Elastic network interface with private IP
  • Supports most AWS services (S3, DynamoDB, CloudWatch, etc.)
  • Charges: Per hour + data processing
  • Uses security groups

2. Gateway Endpoints

  • Route table target
  • Only supports S3 and DynamoDB
  • Free (no additional charge)
  • Uses VPC endpoint policies
         WITHOUT VPC Endpoint
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚         Private Subnet           β”‚
β”‚                                  β”‚
β”‚  πŸ–₯️ EC2 Instance                β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
         β”‚
         ↓
    NAT Gateway β†’ IGW β†’ Internet β†’ S3
    πŸ’° Cost + Latency

         WITH VPC Endpoint
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚         Private Subnet           β”‚
β”‚                                  β”‚
β”‚  πŸ–₯️ EC2 Instance ──→ πŸ“‘ VPC     β”‚
β”‚                     Endpoint     β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜
         β”‚                β”‚
         β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
              Direct connection to S3
              πŸ’° Free + Low Latency
## Create S3 Gateway Endpoint
aws ec2 create-vpc-endpoint \
  --vpc-id vpc-12345678 \
  --service-name com.amazonaws.us-east-1.s3 \
  --route-table-ids rtb-12345678

## Create Interface Endpoint (e.g., for CloudWatch)
aws ec2 create-vpc-endpoint \
  --vpc-id vpc-12345678 \
  --vpc-endpoint-type Interface \
  --service-name com.amazonaws.us-east-1.logs \
  --subnet-ids subnet-12345678 \
  --security-group-ids sg-12345678

πŸ’‘ Cost Optimization: Use Gateway Endpoints for S3 and DynamoDBβ€”they're free!


Real-World Examples

Example 1: Three-Tier Web Application Architecture

Let's design a production-ready VPC for a web application with web servers, application servers, and databases.

Requirements:

  • High availability across 2 Availability Zones
  • Public-facing web tier
  • Private application and database tiers
  • Secure database access

Architecture:

VPC: 10.0.0.0/16

Availability Zone A:
- Public Subnet:  10.0.1.0/24  (Web servers, NAT Gateway)
- Private Subnet: 10.0.2.0/24  (App servers)
- Private Subnet: 10.0.3.0/24  (Databases)

Availability Zone B:
- Public Subnet:  10.0.11.0/24 (Web servers, NAT Gateway)
- Private Subnet: 10.0.12.0/24 (App servers)
- Private Subnet: 10.0.13.0/24 (Databases)

Implementation:

## Create VPC
VPC_ID=$(aws ec2 create-vpc \
  --cidr-block 10.0.0.0/16 \
  --query 'Vpc.VpcId' \
  --output text)

## Enable DNS hostnames
aws ec2 modify-vpc-attribute \
  --vpc-id $VPC_ID \
  --enable-dns-hostnames

## Create Internet Gateway
IGW_ID=$(aws ec2 create-internet-gateway \
  --query 'InternetGateway.InternetGatewayId' \
  --output text)

aws ec2 attach-internet-gateway \
  --vpc-id $VPC_ID \
  --internet-gateway-id $IGW_ID

## Create public subnet in AZ-A
PUBLIC_SUBNET_A=$(aws ec2 create-subnet \
  --vpc-id $VPC_ID \
  --cidr-block 10.0.1.0/24 \
  --availability-zone us-east-1a \
  --query 'Subnet.SubnetId' \
  --output text)

## Create private app subnet in AZ-A
PRIVATE_APP_A=$(aws ec2 create-subnet \
  --vpc-id $VPC_ID \
  --cidr-block 10.0.2.0/24 \
  --availability-zone us-east-1a \
  --query 'Subnet.SubnetId' \
  --output text)

## Create route table for public subnets
PUBLIC_RT=$(aws ec2 create-route-table \
  --vpc-id $VPC_ID \
  --query 'RouteTable.RouteTableId' \
  --output text)

## Add route to Internet Gateway
aws ec2 create-route \
  --route-table-id $PUBLIC_RT \
  --destination-cidr-block 0.0.0.0/0 \
  --gateway-id $IGW_ID

## Associate public subnet with route table
aws ec2 associate-route-table \
  --route-table-id $PUBLIC_RT \
  --subnet-id $PUBLIC_SUBNET_A

## Create NAT Gateway (requires Elastic IP)
EIP_ID=$(aws ec2 allocate-address \
  --domain vpc \
  --query 'AllocationId' \
  --output text)

NAT_GW=$(aws ec2 create-nat-gateway \
  --subnet-id $PUBLIC_SUBNET_A \
  --allocation-id $EIP_ID \
  --query 'NatGateway.NatGatewayId' \
  --output text)

## Create route table for private subnets
PRIVATE_RT=$(aws ec2 create-route-table \
  --vpc-id $VPC_ID \
  --query 'RouteTable.RouteTableId' \
  --output text)

## Add route to NAT Gateway
aws ec2 create-route \
  --route-table-id $PRIVATE_RT \
  --destination-cidr-block 0.0.0.0/0 \
  --nat-gateway-id $NAT_GW

## Associate private subnet with route table
aws ec2 associate-route-table \
  --route-table-id $PRIVATE_RT \
  --subnet-id $PRIVATE_APP_A

Security Group configuration:

## Web tier security group (allows HTTP/HTTPS from internet)
WEB_SG=$(aws ec2 create-security-group \
  --group-name web-tier-sg \
  --description "Web tier security group" \
  --vpc-id $VPC_ID \
  --query 'GroupId' \
  --output text)

aws ec2 authorize-security-group-ingress \
  --group-id $WEB_SG \
  --protocol tcp --port 80 --cidr 0.0.0.0/0

aws ec2 authorize-security-group-ingress \
  --group-id $WEB_SG \
  --protocol tcp --port 443 --cidr 0.0.0.0/0

## App tier security group (allows traffic only from web tier)
APP_SG=$(aws ec2 create-security-group \
  --group-name app-tier-sg \
  --description "Application tier security group" \
  --vpc-id $VPC_ID \
  --query 'GroupId' \
  --output text)

aws ec2 authorize-security-group-ingress \
  --group-id $APP_SG \
  --protocol tcp --port 8080 \
  --source-group $WEB_SG

## Database tier security group (allows traffic only from app tier)
DB_SG=$(aws ec2 create-security-group \
  --group-name db-tier-sg \
  --description "Database tier security group" \
  --vpc-id $VPC_ID \
  --query 'GroupId' \
  --output text)

aws ec2 authorize-security-group-ingress \
  --group-id $DB_SG \
  --protocol tcp --port 3306 \
  --source-group $APP_SG

Why this works:

  • Web servers in public subnets can receive internet traffic
  • NAT Gateways in each AZ provide outbound internet for private subnets
  • Security groups enforce least privilege (webβ†’appβ†’db)
  • High availability through multi-AZ deployment
  • Databases are completely isolated from direct internet access

Example 2: VPC Flow Logs for Troubleshooting

VPC Flow Logs capture information about IP traffic going to and from network interfaces in your VPC. They're invaluable for troubleshooting connectivity issues.

Enable Flow Logs:

## Create CloudWatch log group
aws logs create-log-group --log-group-name /aws/vpc/flowlogs

## Create IAM role for Flow Logs
cat > trust-policy.json <<EOF
{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Principal": {"Service": "vpc-flow-logs.amazonaws.com"},
    "Action": "sts:AssumeRole"
  }]
}
EOF

ROLE_ARN=$(aws iam create-role \
  --role-name VPCFlowLogsRole \
  --assume-role-policy-document file://trust-policy.json \
  --query 'Role.Arn' \
  --output text)

## Attach policy
aws iam attach-role-policy \
  --role-name VPCFlowLogsRole \
  --policy-arn arn:aws:iam::aws:policy/CloudWatchLogsFullAccess

## Create Flow Log
aws ec2 create-flow-logs \
  --resource-type VPC \
  --resource-ids $VPC_ID \
  --traffic-type ALL \
  --log-destination-type cloud-watch-logs \
  --log-group-name /aws/vpc/flowlogs \
  --deliver-logs-permission-arn $ROLE_ARN

Flow Log record format:

version account-id interface-id srcaddr dstaddr srcport dstport protocol packets bytes start end action log-status

Example:
2 123456789012 eni-abc123de 172.31.16.5 172.31.16.21 49152 80 6 20 4000 1620000000 1620000060 ACCEPT OK

Query rejected traffic:

-- CloudWatch Insights query
fields @timestamp, srcAddr, dstAddr, dstPort, action
| filter action = "REJECT"
| stats count() by dstPort
| sort count desc

This helps identify:

  • Which ports are being blocked
  • Source IPs attempting connections
  • Whether security groups or NACLs are blocking traffic

Example 3: Hybrid Cloud Connectivity with VPN

Connecting your on-premises data center to AWS using Site-to-Site VPN.

Architecture components:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚      On-Premises Data Center            β”‚
β”‚                                          β”‚
β”‚  🏒 Corporate Network (192.168.0.0/16)  β”‚
β”‚                                          β”‚
β”‚      Customer Gateway Device            β”‚
β”‚      (Physical/Virtual Router)          β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
               β”‚
               β”‚ IPsec VPN Tunnel
               β”‚ (Encrypted)
               ↓
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚           AWS Cloud                      β”‚
β”‚                                          β”‚
β”‚   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”‚
β”‚   β”‚  Virtual Private Gateway       β”‚    β”‚
β”‚   β”‚  (Attached to VPC)             β”‚    β”‚
β”‚   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β”‚
β”‚              β”‚                           β”‚
β”‚   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”‚
β”‚   β”‚  VPC (10.0.0.0/16)             β”‚    β”‚
β”‚   β”‚                                β”‚    β”‚
β”‚   β”‚  πŸ–₯️ Private Subnets            β”‚    β”‚
β”‚   β”‚  πŸ’Ύ Shared Resources           β”‚    β”‚
β”‚   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Setup:

## Create Customer Gateway (represents your on-premises router)
CGW_ID=$(aws ec2 create-customer-gateway \
  --type ipsec.1 \
  --public-ip 203.0.113.12 \
  --bgp-asn 65000 \
  --query 'CustomerGateway.CustomerGatewayId' \
  --output text)

## Create Virtual Private Gateway
VGW_ID=$(aws ec2 create-vpn-gateway \
  --type ipsec.1 \
  --query 'VpnGateway.VpnGatewayId' \
  --output text)

## Attach VGW to VPC
aws ec2 attach-vpn-gateway \
  --vpn-gateway-id $VGW_ID \
  --vpc-id $VPC_ID

## Create VPN Connection
VPN_ID=$(aws ec2 create-vpn-connection \
  --type ipsec.1 \
  --customer-gateway-id $CGW_ID \
  --vpn-gateway-id $VGW_ID \
  --query 'VpnConnection.VpnConnectionId' \
  --output text)

## Enable route propagation
aws ec2 enable-vgw-route-propagation \
  --route-table-id $PRIVATE_RT \
  --gateway-id $VGW_ID

Configuration downloaded from AWS:

VPN Tunnel #1:
- Outside IP Address: 54.123.45.67
- Inside IP Address: 169.254.44.1/30 (AWS side)
- Inside IP Address: 169.254.44.2/30 (Customer side)
- Pre-Shared Key: [generated key]

VPN Tunnel #2:
- Outside IP Address: 54.123.45.68
- Inside IP Address: 169.254.45.1/30 (AWS side)
- Inside IP Address: 169.254.45.2/30 (Customer side)
- Pre-Shared Key: [generated key]

πŸ’‘ High Availability: AWS creates two VPN tunnels per connection. Configure both on your customer gateway for redundancy.

πŸ”’ Security: All traffic through VPN tunnels is encrypted using IPsec. You can also use AWS Direct Connect for dedicated private connectivity.

Example 4: VPC Endpoint for S3 Cost Optimization

Reducing data transfer costs by accessing S3 through a VPC endpoint instead of the internet.

Before (using NAT Gateway):

## Instance in private subnet accessing S3
## Route: Instance β†’ NAT Gateway β†’ IGW β†’ Internet β†’ S3

## Costs incurred:
## - NAT Gateway per hour: $0.045
## - NAT Gateway data processing: $0.045/GB
## - Data transfer out to internet: $0.09/GB (first 10TB)

## For 1TB of S3 access per month:
## NAT Gateway: $0.045 Γ— 730 hours = $32.85
## Data processing: $0.045 Γ— 1000 GB = $45.00
## Data transfer: $0.09 Γ— 1000 GB = $90.00
## TOTAL: $167.85/month

After (using VPC Endpoint):

## Create S3 Gateway Endpoint
VPCE_ID=$(aws ec2 create-vpc-endpoint \
  --vpc-id $VPC_ID \
  --service-name com.amazonaws.us-east-1.s3 \
  --route-table-ids $PRIVATE_RT \
  --query 'VpcEndpoint.VpcEndpointId' \
  --output text)

## Apply endpoint policy (optional, restricts access)
cat > endpoint-policy.json <<EOF
{
  "Statement": [{
    "Effect": "Allow",
    "Principal": "*",
    "Action": [
      "s3:GetObject",
      "s3:PutObject"
    ],
    "Resource": "arn:aws:s3:::my-app-bucket/*"
  }]
}
EOF

aws ec2 modify-vpc-endpoint \
  --vpc-endpoint-id $VPCE_ID \
  --policy-document file://endpoint-policy.json

## Verify route table automatically updated
aws ec2 describe-route-tables \
  --route-table-ids $PRIVATE_RT

## Output includes:
## Destination: pl-12345678 (S3 prefix list)
## Target: vpce-xxxxx (VPC Endpoint)

## NEW COST for 1TB of S3 access per month:
## Gateway Endpoint: $0.00 (FREE)
## Data transfer: $0.00 (stays in AWS network)
## TOTAL: $0.00/month

## SAVINGS: $167.85/month = $2,014.20/year!

Verification test:

## From EC2 instance in private subnet
aws s3 ls s3://my-app-bucket/ --region us-east-1

## Check flow logs to verify traffic uses endpoint
aws logs filter-log-events \
  --log-group-name /aws/vpc/flowlogs \
  --filter-pattern "[version, account, eni, srcaddr, dstaddr=*amazonaws.com*]"

🎯 Best Practice: Always use Gateway Endpoints for S3 and DynamoDB in production environments. The cost savings are significant, and there's no performance penalty.


Common Mistakes

⚠️ Mistake 1: Forgetting to enable auto-assign public IP

Instances in public subnets won't be reachable from the internet without public IPs.

## WRONG: Launch instance without public IP
aws ec2 run-instances \
  --subnet-id $PUBLIC_SUBNET \
  --image-id ami-12345678
## Result: Instance has no public IP, unreachable from internet

## CORRECT: Enable at subnet level
aws ec2 modify-subnet-attribute \
  --subnet-id $PUBLIC_SUBNET \
  --map-public-ip-on-launch

## OR specify at launch time
aws ec2 run-instances \
  --subnet-id $PUBLIC_SUBNET \
  --image-id ami-12345678 \
  --associate-public-ip-address

⚠️ Mistake 2: Not allowing ephemeral ports in NACL

Return traffic uses random high ports (1024-65535). Blocking these breaks connections.

## WRONG: Only allow specific ports
Inbound: 80, 443
Outbound: 80, 443
## Result: HTTP requests fail because responses can't return

## CORRECT: Allow ephemeral ports
Inbound: 80, 443, 1024-65535 (for return traffic)
Outbound: 80, 443, 1024-65535 (for responses)

⚠️ Mistake 3: Overlapping CIDR blocks in VPC peering

## WRONG: Both VPCs use 10.0.0.0/16
VPC-A: 10.0.0.0/16
VPC-B: 10.0.0.0/16
## Result: Cannot create peering connection (routing conflicts)

## CORRECT: Non-overlapping ranges
VPC-A: 10.0.0.0/16
VPC-B: 10.1.0.0/16
## Result: Peering works, routing is unambiguous

⚠️ Mistake 4: Placing NAT Gateway in private subnet

NAT Gateways must be in public subnets with IGW routes.

## WRONG: NAT Gateway in private subnet
aws ec2 create-nat-gateway \
  --subnet-id $PRIVATE_SUBNET \
  --allocation-id $EIP_ID
## Result: NAT Gateway can't reach internet

## CORRECT: NAT Gateway in public subnet
aws ec2 create-nat-gateway \
  --subnet-id $PUBLIC_SUBNET \
  --allocation-id $EIP_ID

⚠️ Mistake 5: Not using separate route tables for public/private subnets

## WRONG: All subnets use main route table with IGW route
## Result: "Private" subnets are actually public!

## CORRECT: Explicit route table associations
## Public subnets β†’ Route table with IGW
## Private subnets β†’ Route table with NAT Gateway

⚠️ Mistake 6: Hardcoding IP addresses in security groups

## WRONG: Reference by IP
Source: 10.0.2.15/32 (app server IP)
## Result: Breaks when instance is replaced

## CORRECT: Reference by security group
Source: sg-app-tier-12345
## Result: Works regardless of IP changes

⚠️ Mistake 7: Single NAT Gateway for all AZs

## WRONG: One NAT Gateway in AZ-A for all private subnets
## Result: If AZ-A fails, private subnets in other AZs lose internet

## CORRECT: One NAT Gateway per AZ
## AZ-A private subnets β†’ NAT Gateway in AZ-A public subnet
## AZ-B private subnets β†’ NAT Gateway in AZ-B public subnet

⚠️ Mistake 8: Not planning CIDR blocks for growth

## WRONG: /24 VPC with 251 usable IPs
VPC: 10.0.0.0/24
## Result: Run out of IPs quickly

## CORRECT: /16 VPC with 65,531 usable IPs
VPC: 10.0.0.0/16
## Allows for multiple subnets across AZs with room to grow

Key Takeaways

βœ… VPC fundamentals:

  • VPCs provide isolated network environments within AWS
  • CIDR planning is criticalβ€”use /16 for VPCs, /24 for subnets
  • AWS reserves 5 IPs in every subnet (first 4 + last 1)
  • VPCs are regional, subnets are AZ-specific

βœ… Routing and connectivity:

  • Internet Gateway enables internet access for public subnets (one per VPC)
  • NAT Gateway provides outbound internet for private subnets (deploy per AZ)
  • Route tables determine traffic flowβ€”use explicit associations
  • VPC endpoints eliminate internet routing for AWS services (free for S3/DynamoDB)

βœ… Security layers:

  • Security Groups: Stateful, instance-level, allow rules only
  • NACLs: Stateless, subnet-level, allow and deny rules
  • Default deny inbound, default allow outbound (security groups)
  • Remember ephemeral ports (1024-65535) for NACLs

βœ… High availability patterns:

  • Deploy resources across multiple Availability Zones
  • Use one NAT Gateway per AZ (not shared)
  • Implement redundant VPN tunnels
  • Consider Transit Gateway for complex topologies

βœ… Cost optimization:

  • Use Gateway Endpoints for S3 and DynamoDB (free)
  • Right-size NAT Gateways or use NAT instances for dev/test
  • VPC Flow Logs help identify unused resources
  • Consolidate VPN connections where possible

βœ… Troubleshooting checklist:

  1. Route table has correct routes?
  2. Security groups allow traffic?
  3. NACLs allow traffic (including ephemeral ports)?
  4. Public subnet has IGW route?
  5. Private subnet has NAT Gateway route?
  6. VPC endpoints configured correctly?
  7. Flow Logs show expected traffic patterns?

πŸ“š Further Study

  1. AWS VPC Official Documentation: https://docs.aws.amazon.com/vpc/latest/userguide/what-is-amazon-vpc.html
  2. AWS Well-Architected Framework - Networking: https://docs.aws.amazon.com/wellarchitected/latest/framework/networking.html
  3. AWS VPC Connectivity Options Whitepaper: https://docs.aws.amazon.com/whitepapers/latest/aws-vpc-connectivity-options/welcome.html

πŸ“‹ Quick Reference Card

ComponentPurposeKey Fact
VPCIsolated virtual networkRegional, assign CIDR block
SubnetIP subdivisionAZ-specific, 5 IPs reserved
Internet GatewayInternet accessOne per VPC, highly available
NAT GatewayOutbound internetDeploy per AZ, costs $$$
Route TableTraffic directionMost specific route wins
Security GroupInstance firewallStateful, allow only
NACLSubnet firewallStateless, allow/deny
VPC PeeringVPC-to-VPC connectionNot transitive
VPC EndpointPrivate AWS service accessGateway (free) vs Interface
VPN GatewayHybrid connectivityIPsec encrypted tunnels

πŸ”’ Essential Port Numbers

22SSH80HTTP
443HTTPS3306MySQL
5432PostgreSQL1024-65535Ephemeral

πŸ’° Cost Comparison

ResourceHourly CostData Cost
NAT Gateway$0.045$0.045/GB
VPC Endpoint (Interface)$0.01$0.01/GB
VPC Endpoint (Gateway)FREEFREE