AWS Networking & Identity

VPC Connectivity

18 min Lesson 6 of 28

VPC Connectivity

By default, every VPC you create is an island — no traffic crosses the boundary unless you explicitly build the bridge. At scale, that isolation multiplies: dozens of VPCs per region, cross-region traffic, and private access to AWS managed services all need architectural answers. AWS gives you three complementary primitives: VPC Peering, Transit Gateway (TGW), and VPC Endpoints / PrivateLink. Choosing the right one (or combination) defines your network's security posture, blast radius, and per-GB cost.

VPC Peering

A VPC peering connection is a direct, private Layer-3 link between exactly two VPCs. Traffic flows over AWS's backbone — never the public internet — and each end must add an explicit route table entry. Peering works across accounts and across regions (inter-region peering adds ~$0.01/GB data transfer charge).

Hard constraints:

  • No transitive routing. If VPC-A peers with VPC-B and VPC-B peers with VPC-C, VPC-A cannot reach VPC-C through VPC-B. Every pair that needs to communicate needs its own peering connection.
  • No overlapping CIDRs. Plan your IPAM scheme before peering — once the VPCs exist it is painful to re-CIDR them.
  • The AWS default peering limit is 125 active connections per VPC; above that, management becomes untenable.
When to choose peering: fewer than 10 VPCs, stable topology, large steady-state traffic volumes where you want the lowest possible data-transfer cost (peering within the same region is free between same-AZ ENIs).

Transit Gateway

Transit Gateway is a regional, fully managed hub-and-spoke router. Every VPC (and VPN / Direct Connect) attaches to the TGW; the TGW's own route tables control what can reach what. The mesh of O(n²) peering connections collapses into O(n) TGW attachments.

Key production capabilities:

  • Multiple route tables on the TGW — segment prod, staging, and shared-services into separate route domains; enforce that prod VPCs never route to dev VPCs even though both attach to the same TGW.
  • Inter-region peering — peer two TGWs across regions for a global backbone without the n² peering mesh.
  • VPN and Direct Connect attachment — on-prem connectivity terminates at the TGW, not at each individual VPC.
  • Multicast — for specialised workloads (financial market data, media) that use IP multicast.

Pricing: $0.05/hr per attachment + $0.02/GB processed data. At hundreds of VPCs the ops savings dwarf the cost, but at 3-4 VPCs with modest traffic, peering is cheaper.

# Terraform: create a Transit Gateway with two isolated route tables # (prod-rtb cannot reach dev-rtb by default) resource "aws_ec2_transit_gateway" "main" { description = "Central TGW" auto_accept_shared_attachments = "disable" default_route_table_association = "disable" default_route_table_propagation = "disable" tags = { Name = "main-tgw" } } resource "aws_ec2_transit_gateway_route_table" "prod" { transit_gateway_id = aws_ec2_transit_gateway.main.id tags = { Name = "prod-rtb" } } resource "aws_ec2_transit_gateway_route_table" "dev" { transit_gateway_id = aws_ec2_transit_gateway.main.id tags = { Name = "dev-rtb" } } resource "aws_ec2_transit_gateway_vpc_attachment" "prod_vpc" { transit_gateway_id = aws_ec2_transit_gateway.main.id vpc_id = aws_vpc.prod.id subnet_ids = aws_subnet.prod_private[*].id transit_gateway_default_route_table_association = false transit_gateway_default_route_table_propagation = false } resource "aws_ec2_transit_gateway_route_table_association" "prod_vpc_assoc" { transit_gateway_attachment_id = aws_ec2_transit_gateway_vpc_attachment.prod_vpc.id transit_gateway_route_table_id = aws_ec2_transit_gateway_route_table.prod.id } resource "aws_ec2_transit_gateway_route_table_propagation" "prod_vpc_prop" { transit_gateway_attachment_id = aws_ec2_transit_gateway_vpc_attachment.prod_vpc.id transit_gateway_route_table_id = aws_ec2_transit_gateway_route_table.prod.id }
VPC Peering vs Transit Gateway topology VPC Peering (mesh) VPC A VPC B VPC C VPC D 6 peering links for 4 VPCs No transitive routing Transit Gateway (hub & spoke) Transit Gateway VPC A VPC B VPC C VPC D VPN/DX 5 attachments, centralised routing
Left: full mesh peering (O(n²) connections, no transitive routing). Right: Transit Gateway hub-and-spoke (O(n) attachments, centralised route tables).

VPC Endpoints and AWS PrivateLink

Even inside a private VPC, a call to s3.amazonaws.com or dynamodb.amazonaws.com traverses the public internet by default — unless you add a VPC endpoint. There are two types:

Gateway Endpoints

Free, prefix-list-based route table entries for S3 and DynamoDB only. Traffic stays within AWS's network. You add a route target of vpce-xxxx and add an endpoint policy (IAM-like JSON) to restrict which buckets or tables are reachable from this VPC.

Interface Endpoints (PrivateLink)

An Elastic Network Interface injected into your subnet with a private IP, fronted by a Network Load Balancer on the service side. Available for 150+ AWS services (EC2, SSM, STS, KMS, ECR, CloudWatch Logs, Secrets Manager …) and for your own services shared across accounts. Cost: ~$0.01/hr per AZ per endpoint + $0.01/GB.

PrivateLink for your own services: You can expose an internal microservice (NLB-fronted) to other VPCs or accounts via PrivateLink without peering or TGW. The consumer VPC creates an interface endpoint; traffic never leaves AWS. This is the right pattern for SaaS providers sharing services to customers without granting VPC access.
# AWS CLI: create an S3 Gateway Endpoint (free, no data-transfer charge) aws ec2 create-vpc-endpoint \ --vpc-id vpc-0abc123 \ --service-name com.amazonaws.us-east-1.s3 \ --route-table-ids rtb-0def456 rtb-0ghi789 \ --vpc-endpoint-type Gateway \ --policy-document '{ "Statement": [{ "Effect": "Allow", "Principal": "*", "Action": ["s3:GetObject","s3:PutObject"], "Resource": "arn:aws:s3:::my-prod-bucket/*" }] }' # AWS CLI: create a Secrets Manager Interface Endpoint aws ec2 create-vpc-endpoint \ --vpc-id vpc-0abc123 \ --service-name com.amazonaws.us-east-1.secretsmanager \ --vpc-endpoint-type Interface \ --subnet-ids subnet-0aaa subnet-0bbb \ --security-group-ids sg-0ccc \ --private-dns-enabled # rewrites secretsmanager.us-east-1.amazonaws.com to the private IP
VPC Endpoint types: Gateway vs Interface (PrivateLink) Gateway Endpoint (S3 / DynamoDB) VPC Private Subnet EC2 instance Route Table 0.0.0.0/0 → igw Gateway Endpoint AWS S3 (AWS backbone) Free — route table entry only Interface Endpoint (PrivateLink) VPC Private Subnet EC2 instance Interface Endpoint ENI 10.0.1.55 (private) NLB (service side) AWS / Your service Secrets Manager / Custom $0.01/hr/AZ + $0.01/GB
Gateway Endpoints add a free route-table entry for S3/DynamoDB; Interface Endpoints inject a private ENI (via PrivateLink) for 150+ services and custom workloads.

Decision Framework

  • Small, stable topology (2-5 VPCs): VPC Peering — lowest cost, lowest complexity.
  • Many VPCs, shared services, on-prem integration: Transit Gateway — centralised routing, segmentation via multiple route tables, single on-prem attachment point.
  • Accessing AWS services or sharing internal APIs without network overlap: VPC Endpoints / PrivateLink — prevents internet exposure, enables endpoint policies for data perimeter controls.
  • Cross-account service sharing without full network access: PrivateLink — the provider stays behind an NLB; consumers get a private IP only; no VPC-level visibility.
Production pitfall — endpoint DNS resolution: Interface endpoints with --private-dns-enabled rewrite the public hostname (e.g., secretsmanager.us-east-1.amazonaws.com) to the private IP. If you have a corporate DNS resolver forwarding queries to an on-prem server, the rewrite only works in the VPC where the endpoint lives. EC2 instances resolving via a different DNS server will still resolve to the public endpoint and bypass PrivateLink. The fix: use Route 53 Resolver inbound/outbound endpoints with forwarding rules, or ensure all DNS queries originate from the VPC's resolver (169.254.169.253).

Verification and Troubleshooting

After wiring up any connectivity path, validate it systematically:

# Verify TGW route table propagation and associations aws ec2 describe-transit-gateway-route-tables \ --filters "Name=transit-gateway-id,Values=tgw-0abc123" aws ec2 search-transit-gateway-routes \ --transit-gateway-route-table-id tgw-rtb-0def456 \ --filters "Name=state,Values=active" # Confirm an interface endpoint resolves to private IP nslookup secretsmanager.us-east-1.amazonaws.com # Expected: returns 10.x.x.x (your VPC CIDR), not 54.x.x.x # Test S3 gateway endpoint — should succeed without internet route aws s3 ls s3://my-prod-bucket --region us-east-1 # VPC Reachability Analyzer: automated path analysis (no traffic sent) aws ec2 start-network-insights-analysis \ --network-insights-path-id nip-0abc123 aws ec2 describe-network-insights-analyses \ --network-insights-analysis-ids nia-0xyz789 \ --query "NetworkInsightsAnalyses[0].{Status:Status,Reachable:NetworkPathFound}"
VPC Reachability Analyzer is the fastest way to prove (or disprove) a connectivity path without sending live traffic. It models your VPCs, security groups, NACLs, and TGW route tables and returns a hop-by-hop explanation of why traffic is blocked. At $0.10 per analysis it is cheap insurance before a production change.