AWS networking that doesn't break when you go multi-account
How a real AWS VPC actually gets built — subnets, route tables, Transit Gateway, and the patterns that scale beyond your first three accounts. Field-tested networking patterns.
You found a hidden page. Welcome.
The 30-second version
AWS gives you near-infinite networking flexibility, which means it gives you near-infinite ways to make a mess. The mistake I see at almost every company's first multi-VPC environment: peering everything to everything. It works for 3 VPCs, breaks down at 10, becomes unmanageable at 30.
The answer is Transit Gateway. It's been around since 2018 and most teams still haven't migrated to it. Here's the right way.
The reference topology
┌────────────────────┐
│ Transit Gateway │
│ (single per acct) │
└──┬──────────┬──────┘
│ │
┌─────────────┘ └─────────────┐
│ │
┌────────┴───────┐ ┌─────────┴──────┐
│ shared-vpc │ │ inspection-vpc │
│ AD, DNS, mgmt │ │ Palo Alto VM │
│ 10.0.0.0/16 │ │ 10.255.0.0/16 │
└────────────────┘ └────────────────┘
│ │
┌────────┴───────┐ ┌────────────┐ ┌──────────┴──────┐
│ prod-vpc │ │ dev-vpc │ │ data-vpc │
│ 10.10.0.0/16 │ │10.20.0.0/16│ │ 10.30.0.0/16 │
└────────────────┘ └────────────┘ └─────────────────┘
Key principles in this layout:
- One Transit Gateway per region per account. Don't try to span TGWs across accounts directly — use Resource Access Manager (RAM) to share a TGW from a network account.
- VPCs attach to the TGW, not to each other. Adding the 11th VPC is the same effort as adding the 4th.
- An "inspection VPC" with a real firewall (Palo Alto VM-Series in HA pair, or Gateway Load Balancer with appliances behind it). All cross-VPC traffic routes through it.
- A shared services VPC for things every other VPC needs: AD, DNS, monitoring, Bastion.
VPC subnet design
For each application VPC, I carve at minimum:
| Subnet type | Per AZ | Purpose |
|---|---|---|
| public | 1 | NAT Gateway, ALB targets |
| private-app | 1 | EC2/ECS/EKS workloads |
| private-data | 1 | RDS, ElastiCache, internal-only |
| tgw-attachment | 1 | Tiny /28 just for the TGW ENI |
Across 3 AZs that's 12 subnets per VPC. Use a /16 VPC and /20 subnets and you have plenty of headroom plus space for future growth. Don't be the person who provisioned a /22 VPC for "small" workloads and ran out of IPs in 6 months.
Route table strategy
Every subnet has a route table. The route table determines where traffic goes. The pattern:
Public subnet route table
0.0.0.0/0 → igw-xxx (Internet Gateway, direct) 10.0.0.0/8 → tgw-xxx (everything internal via TGW) local → local (auto, the VPC itself)
Private subnet route table
0.0.0.0/0 → nat-xxx (outbound internet via NAT) 10.0.0.0/8 → tgw-xxx (everything internal via TGW) local → local
TGW route table (the interesting one)
This is where you implement the firewall-inspection pattern. The TGW has its own routing logic separate from VPC route tables. You configure it so that:
- All inter-VPC traffic must traverse the inspection VPC
- Inspection VPC has a firewall in the path
- Return traffic comes back the same way (asymmetric routing = broken firewall)
The TGW supports multiple route tables. Use them to split traffic:
spoke-rt for application VPCs (default route to inspection VPC),
inspection-rt for the inspection VPC itself (routes to all spokes).
Different VPCs use different TGW route tables.
The "everything to everything" peering trap
Before TGW, the standard answer was VPC peering. It still works for 3-5 VPCs. Here's where it fails:
- Non-transitive routing. A→B and B→C does not give you A→C. Need it? Add A→C peering. Now you have 3 peerings for 3 VPCs. For 10 VPCs you need 45 peerings.
- Each peering has its own route table entries in every VPC that wants to use it.
- No central inspection point. Traffic between peered VPCs bypasses any firewall.
If you're already in this hole, migrating to TGW is straightforward but must be done carefully. Add TGW alongside existing peerings, route new traffic via TGW, drain old peerings, delete them. Allow weeks, not days, for cutover.
VPC endpoints — the cost saver everyone forgets
By default, when an EC2 instance in a private subnet talks to S3 or DynamoDB or any AWS API, the traffic goes out to the internet via NAT Gateway. NAT Gateway charges $0.045/GB processed. If your data pipeline pushes 10TB/month to S3, that's $450 for something that should be free.
The fix: VPC Endpoints.
- Gateway endpoints (S3, DynamoDB) — free, just enable them. Add to your route table.
- Interface endpoints (everything else) — ~$0.01/hour per endpoint per AZ + $0.01/GB. For commonly-used services (SSM, KMS, Secrets Manager, ECR), still way cheaper than NAT for any meaningful traffic.
First thing I do in a new AWS account: gateway endpoints for S3 and DynamoDB, interface endpoints for SSM (so Session Manager works without internet), KMS, and ECR if you're running containers.
Multi-account networking
Real organizations have many AWS accounts. The pattern that works at scale:
- One "network" account owns the TGW.
- Resource Access Manager (RAM) shares the TGW to other accounts.
- Application accounts create VPCs, attach to the shared TGW.
- One "security" account owns the inspection VPC and Palo Altos.
- One "DNS" account owns Route 53 hosted zones, shared via RAM.
Each app team owns their VPC. The platform team owns the TGW and inspection. Clean ownership boundaries. Costs centralize where they should.
Things that bit me
NAT Gateway is per-AZ
A NAT GW in us-east-1a only NATs traffic for instances in us-east-1a. Instances in us-east-1b need their own NAT GW (or you accept cross-AZ data charges). Plan for one NAT GW per AZ in production. That's $32/month each + traffic.
Security group references across peered VPCs
Pre-TGW, you could reference security groups across peered VPCs. Post-TGW, you cannot. SGs only work intra-VPC. CIDR-based rules only across TGW. Annoying, but it forces cleaner design.
The default VPC
Every new AWS account ships with a default VPC, default route to internet, default everything-public. Delete it. Day one. Build your real VPCs deliberately. Otherwise some intern eventually launches an EC2 in the default VPC and you have a publicly-exposed instance you didn't know about.
Tools that pay for themselves
- Reachability Analyzer — built into VPC console. Path tracing between any two ENIs. When you can't figure out why traffic isn't flowing, this tells you which hop drops it.
- VPC Flow Logs — to S3, queryable with Athena. Cheap, useful for forensics. Enable on day one.
- Terraform with the AWS provider — every VPC, route table, TGW attachment, NAT GW. Code it. Don't ClickOps a network.
- Network Manager — visualizes your TGW topology. Useful when you have 30+ VPC attachments and need to explain it to someone.
If you want to go deeper
- Same patterns in Azure — different naming, same principles, but different cost gotchas
- Palo Alto firewall in the inspection VPC — VM-Series HA pair behind a Gateway Load Balancer is the gold-standard pattern
Notes from real AWS environments. If your VPC mess looks like a tangled fishing net and you're trying to figure out the way forward, reach out — I've untangled a few.