VPC Peering: Non-Transitive Routing and When to Use Transit Gateway Instead
VPC peering connects two VPCs directly. It does not connect three. Understanding the non-transitive routing constraint — and the CIDR overlap failure mode — saves hours of debugging when your network doesn't behave as expected.
What VPC peering actually creates
A VPC peering connection is a direct network link between two VPCs. Traffic routed through the peering connection stays on the AWS backbone — it never traverses the public internet. Latency is low (same-region peering is typically sub-millisecond) and there is no bandwidth bottleneck at the peering layer itself.
What peering does not create: a network hub. Each peering connection is a one-to-one relationship between exactly two VPCs.
Non-transitive routing: the constraint that bites every team once
GotchaAWS NetworkingIf VPC A peers with VPC B, and VPC B peers with VPC C, VPC A cannot reach VPC C through VPC B. Routing does not chain through peering connections. Each pair that needs to communicate requires its own direct peering connection.
Prerequisites
- VPC basics
- route tables
- CIDR notation
Key Points
- A peering connection enables routing between exactly two VPCs. Not three.
- Traffic from A cannot be forwarded through B to reach C, even if A-B and B-C are both peered.
- For N VPCs that all need to communicate, you need N×(N-1)/2 peering connections (or Transit Gateway).
- Non-transitive routing applies to the internet gateway too — a peered VPC cannot use another VPC's internet gateway.
The route table requirement
A peering connection alone does nothing. You must add routes in both VPCs pointing to each other's CIDR ranges via the peering connection ID (pcx-xxxxxxxx).
Both sides must have routes. One-sided configuration is a common mistake during setup:
| Route table | Destination | Target | |-------------|-------------|--------------| | VPC A | 10.0.0.0/16 | Local | | | 10.1.0.0/16 | pcx-11112222 | | VPC B | 10.1.0.0/16 | Local | | | 10.0.0.0/16 | pcx-11112222 |
If only VPC A's route table has the entry for VPC B's CIDR, traffic from A can reach B but B's responses have no route back. The connection appears to fail from both directions, which can look identical to a security group block during debugging.
Security groups also need updating. Cross-account peering allows referencing the peer account's security group ID in rules:
# In VPC B's inbound rule for a service:
Source: 123456789012/sg-0abc123def456 (account ID / security group from VPC A)
Port: 443
This is preferable to using CIDR ranges because it stays accurate even if instances in VPC A change IPs.
CIDR overlap: the hard failure
Peering requires non-overlapping CIDR ranges. If VPC A uses 10.0.0.0/16 and VPC B also uses 10.0.0.0/16, AWS will reject the peering request.
This is not a routing rule — it is a fundamental IP addressing constraint. If both VPCs share IP ranges, the kernel cannot determine which VPC a packet with destination 10.0.1.5 should go to.
CIDR overlap becomes a real problem for organizations that:
- Created VPCs with default CIDR ranges (
172.31.0.0/16) across multiple regions or accounts - Did not plan IP address space before expansion
- Acquired another company's AWS infrastructure
There is no fix after the fact. You cannot re-CIDR a VPC. The options are: create new VPCs with non-overlapping ranges, migrate workloads to them, and re-establish peering. This is painful enough that IP address planning is worth doing before you need it.
📝Steps to establish cross-account VPC peering
- In Account A: create the peering request (specify Account B's ID and VPC ID)
- In Account B: accept the peering request
- In Account A: add route table entries for Account B's CIDR → peering connection
- In Account B: add route table entries for Account A's CIDR → peering connection
- Update security groups in both accounts to allow the desired traffic
- (Optional) Enable DNS resolution for the peering connection if services use private DNS names
The DNS resolution step is required if services in one VPC need to resolve private hosted zone records from the other VPC. This must be enabled on both sides of the peering connection separately.
Private Hosted Zone across peered VPCs
If services use Route 53 private hosted zones for internal DNS (service.internal), those zones are not automatically resolvable from a peered VPC. You need to explicitly authorize the association.
# Account that owns the hosted zone: authorize the peered VPC
aws route53 create-vpc-association-authorization \
--hosted-zone-id HOSTED_ZONE_ID \
--vpc VPCRegion=us-east-1,VPCId=VPC_ID_IN_OTHER_ACCOUNT
# Account that owns the VPC: associate with the hosted zone
aws route53 associate-vpc-with-hosted-zone \
--hosted-zone-id SAME_HOSTED_ZONE_ID \
--vpc VPCRegion=us-east-1,VPCId=SAME_VPC_ID
This cannot be done in the console — only CLI or SDK. The association authorization is a one-time step; once the VPC is associated, it resolves the hosted zone's records.
When peering stops scaling: Transit Gateway
With three VPCs you need three peering connections. With ten VPCs you need 45. Each connection requires route table entries on both sides.
Transit Gateway replaces the mesh with a hub. Each VPC attaches to the Transit Gateway once. The Transit Gateway routes between all attached VPCs (and VPNs, Direct Connect connections) based on its own route table.
Without TGW (full mesh for 4 VPCs):
A—B, A—C, A—D, B—C, B—D, C—D = 6 peering connections
With TGW:
A → TGW ← B
C → TGW ← D
= 4 attachments, TGW routes all traffic
VPC peering vs Transit Gateway
Peering is simpler and free for same-region traffic. Transit Gateway adds per-attachment and per-GB costs but scales to hundreds of VPCs without a full-mesh route table explosion.
- Free for same-region traffic (data transfer charges still apply)
- One-to-one connections only — no transitive routing
- N×(N-1)/2 connections for full mesh — does not scale past ~5 VPCs
- Route tables managed manually per connection
- Works cross-account and cross-region
- Per-attachment fee (~$0.05/hr) + per-GB data processing fee
- Hub-and-spoke: all attached VPCs can reach each other
- Supports VPN, Direct Connect, and inter-region peering on the same gateway
- Route tables on TGW centralize routing policy
- Required for complex multi-VPC, multi-account, or hybrid network topologies
Use VPC peering for simple cases: two or three VPCs, same region, no need for transitive routing. Switch to Transit Gateway when you have more than four VPCs that need mutual connectivity, or when you need to connect to on-premises networks through the same routing layer.
Your organization has three VPCs: A (dev), B (staging), and C (prod). You create peering connections A-B and B-C. A developer reports they cannot reach a prod database in VPC C from a dev machine in VPC A. Why?
easyRoute tables in all three VPCs are correctly configured for the direct peering connections (A→B routes exist, B→C routes exist). Security groups allow the traffic.
AThe peering connections are in different availability zones
Incorrect.VPC peering operates at the VPC level, not the AZ level. AZs do not affect whether a peering connection allows routing.BVPC peering is non-transitive — A-B and B-C does not enable A-to-C routing
Correct!VPC peering is strictly point-to-point. Traffic from A destined for C has no route — VPC B does not forward traffic between its peering connections. You need either a direct A-C peering connection or Transit Gateway to enable A-to-C communication.CCross-environment peering requires an IAM policy to allow cross-account traffic
Incorrect.IAM policies control AWS API access, not network routing. Peering between VPCs in the same account has no IAM requirement for the network path itself.DThe route tables need a route entry for VPC C in VPC A's route table pointing to the A-B peering connection
Incorrect.Even if you added a route for VPC C's CIDR in VPC A's route table pointing to the A-B peering connection, AWS would reject this configuration. You cannot route to a non-directly-peered VPC through an intermediate peering connection.
Hint:The peering topology is A-B and B-C. Think about whether B acts as a router for traffic between A and C.