Connecting Two VPCs with VPC Peering: Route Tables, Security Groups, and Private IP Communication

Connecting two VPCs using VPC Peering enables private IP communication without traversing the public internet — a foundational pattern for multi-VPC architectures in AWS.

TL;DR: VPC Peering Setup at a Glance

StepActionWhere
1Create peering connection requestRequester VPC
2Accept peering connectionAccepter VPC
3Add route to requester route tableRequester subnets
4Add route to accepter route tableAccepter subnets
5Update Security Groups to allow trafficBoth VPCs

How VPC Peering Works: Architecture and Data Flow

VPC Peering (a logical network connection between two VPCs that routes traffic using AWS's private backbone) creates a one-to-one relationship between two VPCs. Traffic between peered VPCs stays on the AWS network and never traverses the public internet. The connection is non-transitive — if VPC-A peers with VPC-B and VPC-B peers with VPC-C, VPC-A cannot reach VPC-C through VPC-B. Each pair requires its own peering connection.

A critical prerequisite: the CIDR blocks of the two VPCs must not overlap. Overlapping CIDRs make peering impossible because the routing table cannot distinguish which VPC owns a given IP range.

graph LR subgraph VPC_A ["VPC-A (10.0.0.0/16)"] SubA["Subnet A 10.0.1.0/24"] RTA["Route Table A"] SGA["Security Group A"] end subgraph VPC_B ["VPC-B (10.1.0.0/16)"] SubB["Subnet B 10.1.1.0/24"] RTB["Route Table B"] SGB["Security Group B"] end PCX["Peering Connection pcx-0123456789abcdef0 (active)"] SubA --> RTA RTA -->|"dst: 10.1.0.0/16 target: pcx-..."| PCX PCX -->|"dst: 10.0.0.0/16 target: pcx-..."| RTB RTB --> SubB SGA -->|"allow inbound from 10.1.0.0/16"| SubA SGB -->|"allow inbound from 10.0.0.0/16"| SubB
  1. Requester VPC initiates the peering connection request targeting the Accepter VPC.
  2. Accepter VPC must explicitly accept the request before any traffic flows.
  3. Once accepted, route table entries must be added in both VPCs — the connection alone does not update routing.
  4. Security Groups (instance-level firewalls) must permit inbound traffic from the peer CIDR or a specific Security Group in the peer VPC.
  5. Traffic flows over the AWS private backbone — no Internet Gateway, NAT Gateway, or VPN is involved.
Analogy: VPC Peering is like building a private hallway between two office buildings. The hallway exists, but each office still controls who can enter through its own door (Security Groups). And the hallway only connects those two buildings — you cannot walk through Building B to reach Building C.

Connecting Two VPCs: Step-by-Step Implementation

Prerequisites

  • Two VPCs in the same AWS account and region (this guide covers same-account, same-region peering).
  • Non-overlapping CIDR blocks. Example: 10.0.0.0/16 (VPC-A) and 10.1.0.0/16 (VPC-B).
  • AWS CLI configured with sufficient IAM permissions (see IAM section below).

Step 1: Create the Peering Connection Request

The requester VPC initiates the connection. You need both VPC IDs. The --peer-vpc-id is the accepter VPC. Since both VPCs are in the same account and region, --peer-owner-id and --peer-region are optional but shown here for clarity.

aws ec2 create-vpc-peering-connection \
  --vpc-id vpc-0abc1234def567890 \
  --peer-vpc-id vpc-0def5678abc901234 \
  --region us-east-1

The output includes a VpcPeeringConnectionId (e.g., pcx-0123456789abcdef0). Record this — you need it for all subsequent steps.

Step 2: Accept the Peering Connection

The peering connection starts in a pending-acceptance state. It must be explicitly accepted before any traffic can flow. For same-account peering, you accept it with the same credentials.

aws ec2 accept-vpc-peering-connection \
  --vpc-peering-connection-id pcx-0123456789abcdef0 \
  --region us-east-1

After acceptance, the status transitions to active. Verify with:

aws ec2 describe-vpc-peering-connections \
  --vpc-peering-connection-ids pcx-0123456789abcdef0 \
  --region us-east-1 \
  --query 'VpcPeeringConnections[0].Status.Code'

Step 3: Update Route Tables — The Step Engineers Most Often Miss

This is where most failed peering setups stall. An active peering connection does not automatically update any route table. You must add routes in both VPCs, pointing each VPC's CIDR at the peering connection ID as the target.

First, identify the route table IDs associated with the subnets that need to communicate. Each subnet is associated with exactly one route table (either explicitly or via the VPC's main route table).

aws ec2 describe-route-tables \
  --filters "Name=vpc-id,Values=vpc-0abc1234def567890" \
  --region us-east-1 \
  --query 'RouteTables[*].{RouteTableId:RouteTableId,Associations:Associations[*].SubnetId}'

Add route in VPC-A's route table pointing to VPC-B's CIDR:

aws ec2 create-route \
  --route-table-id rtb-0aaabbbccc1112223 \
  --destination-cidr-block 10.1.0.0/16 \
  --vpc-peering-connection-id pcx-0123456789abcdef0 \
  --region us-east-1

Add route in VPC-B's route table pointing to VPC-A's CIDR:

aws ec2 create-route \
  --route-table-id rtb-0dddeeefff4445556 \
  --destination-cidr-block 10.0.0.0/16 \
  --vpc-peering-connection-id pcx-0123456789abcdef0 \
  --region us-east-1
graph TD A["Peering Connection Created Status: pending-acceptance"] --> B["Peering Connection Accepted Status: active"] B --> C{"Route Tables Updated?"} C -->|"No"| D["Traffic Dropped No route to peer CIDR"] C -->|"VPC-A only"| E["One-way traffic Return path missing"] C -->|"Both VPCs"| F{"Security Groups Allow Traffic?"} F -->|"No"| G["Traffic Blocked at instance firewall"] F -->|"Yes"| H["Private IP Communication Established"]
  1. VPC-A's route table now has an entry: destination 10.1.0.0/16 → target pcx-....
  2. VPC-B's route table has the mirror entry: destination 10.0.0.0/16 → target pcx-....
  3. Without both entries, traffic is one-way at best — and typically drops silently because the return path is missing.

Step 4: Update Security Groups to Allow Peer Traffic

Route tables control where packets go. Security Groups (instance-level firewalls) control whether packets are accepted. Both layers must permit the traffic. You can reference the peer VPC's CIDR block or, for same-account peering, reference the peer Security Group ID directly — which is more precise and avoids opening the entire CIDR.

Allow inbound traffic from VPC-B's CIDR on VPC-A's instances (e.g., port 443):

aws ec2 authorize-security-group-ingress \
  --group-id sg-0aaa111bbb222ccc3 \
  --protocol tcp \
  --port 443 \
  --cidr 10.1.0.0/16 \
  --region us-east-1

Allow inbound traffic from VPC-A's CIDR on VPC-B's instances:

aws ec2 authorize-security-group-ingress \
  --group-id sg-0ddd444eee555fff6 \
  --protocol tcp \
  --port 443 \
  --cidr 10.0.0.0/16 \
  --region us-east-1

Adjust --protocol and --port to match your actual application requirements. Security Groups are stateful — allowing inbound automatically permits the return traffic for established connections.

Step 5: Verify End-to-End Connectivity

With routes and Security Groups in place, verify connectivity from an EC2 instance in VPC-A to a private IP in VPC-B. Use ping (ICMP) only if your Security Groups permit ICMP. For TCP services, telnet or nc against the target port is more reliable.

# From an EC2 instance in VPC-A, targeting a private IP in VPC-B
curl -v http://10.1.0.50:80/health

If connectivity fails, use VPC Reachability Analyzer to trace the path without sending actual traffic:

aws ec2 create-network-insights-path \
  --source eni-0source1234567890a \
  --destination eni-0dest1234567890b \
  --protocol tcp \
  --destination-port 443 \
  --region us-east-1

IAM Permissions Required for VPC Peering

The following IAM policy covers the minimum permissions needed to create, accept, and configure VPC Peering connections and route tables. Note that several EC2 Describe actions require "Resource": "*" because they do not support resource-level restrictions in IAM.

🔽 Click to expand: Minimum IAM Policy for VPC Peering Setup
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "VpcPeeringManagement",
      "Effect": "Allow",
      "Action": [
        "ec2:CreateVpcPeeringConnection",
        "ec2:AcceptVpcPeeringConnection",
        "ec2:DescribeVpcPeeringConnections",
        "ec2:DescribeVpcs",
        "ec2:DescribeRouteTables",
        "ec2:DescribeSubnets"
      ],
      "Resource": "*"
    },
    {
      "Sid": "RouteTableManagement",
      "Effect": "Allow",
      "Action": [
        "ec2:CreateRoute",
        "ec2:DeleteRoute"
      ],
      "Resource": "arn:aws:ec2:us-east-1:123456789012:route-table/*"
    },
    {
      "Sid": "SecurityGroupManagement",
      "Effect": "Allow",
      "Action": [
        "ec2:AuthorizeSecurityGroupIngress",
        "ec2:RevokeSecurityGroupIngress"
      ],
      "Resource": "arn:aws:ec2:us-east-1:123456789012:security-group/*"
    }
  ]
}

Common Failure Modes When Connecting Two VPCs

Symptom: Peering is Active but Traffic Drops

Misdiagnosis: Engineers often re-check the peering connection status (it shows active) and conclude the network layer is fine. The investigation then jumps to application-level issues.

Actual cause: The route table was updated for one VPC but not the other. Return traffic has no route and is silently dropped. This is asymmetric routing — packets reach the destination but responses never return.

Fix: Run describe-route-tables on both VPCs and confirm each has a route entry with the peer's CIDR as destination and the peering connection ID as target. The absence of a return route is the most common root cause in production peering failures.

Symptom: Route Table Updated but Still No Connectivity

If routes are correct on both sides and traffic still fails, the Security Group is the next layer to inspect. A Security Group rule referencing a CIDR that doesn't match the source IP — for example, using a subnet CIDR instead of the full VPC CIDR — will silently drop traffic. Verify the exact source IP range against the inbound rule.

Symptom: Cannot Create Peering — CIDR Conflict Error

AWS enforces non-overlapping CIDRs at peering creation time. If your VPCs were created with the default 172.31.0.0/16 CIDR (the AWS default VPC CIDR), both will conflict. The only resolution is to use non-default VPCs with distinct CIDR ranges. There is no workaround for overlapping CIDRs in VPC Peering.

flowchart TD START(["Peering active but no connectivity"]) --> Q1{"Routes in both route tables?"} Q1 -->|"Missing one or both"| FIX1["Add missing route create-route on affected RT"] Q1 -->|"Both present"| Q2{"Security Group permits peer CIDR?"} Q2 -->|"Rule missing or wrong CIDR"| FIX2["Update SG inbound rule authorize-security-group-ingress"] Q2 -->|"SG looks correct"| Q3{"CIDR blocks overlapping?"} Q3 -->|"Yes"| FIX3["Peering not possible Re-architect VPC CIDRs"] Q3 -->|"No"| FIX4["Run Reachability Analyzer create-network-insights-path"]

Key Constraints and Behavioral Notes

  • Non-transitive routing: VPC Peering does not support transitive routing. A → B → C does not allow A to reach C. Use AWS Transit Gateway if you need hub-and-spoke or mesh connectivity across many VPCs.
  • DNS resolution: By default, instances in a peered VPC resolve the peer's public DNS hostnames to public IPs, not private IPs. To resolve to private IPs across the peering connection, enable DNS resolution support on the peering connection using modify-vpc-peering-connection-options.
  • No bandwidth limits specific to peering: VPC Peering traffic is subject to standard EC2 network bandwidth limits per instance type, not a separate peering-specific cap.
  • Edge-to-edge routing restrictions: You cannot use a peering connection to route traffic through one VPC to reach an Internet Gateway, NAT Gateway, VPN, or Direct Connect connection in the peer VPC. AWS explicitly documents this as an unsupported configuration.

Glossary: Key Terms

TermDefinition
VPC PeeringA logical network connection between two VPCs that routes traffic privately using AWS's backbone network.
Peering Connection ID (pcx-...)The unique identifier for a VPC Peering connection, used as the route target in route table entries.
Route TableA set of rules (routes) that determine where network traffic from a subnet is directed.
Non-transitive RoutingThe property of VPC Peering where a peered VPC cannot act as a transit point to reach a third VPC.
Reachability AnalyzerAn AWS network diagnostic tool that analyzes the path between two network endpoints without sending actual traffic.

Connecting Two VPCs: Next Steps and Further Reading

VPC Peering is the right tool for simple, point-to-point private connectivity between two VPCs. If your architecture grows to require connectivity across three or more VPCs, evaluate AWS Transit Gateway to avoid managing an O(n²) mesh of peering connections. For DNS resolution across the peering connection, review the VPC Peering DNS options documentation to enable private hostname resolution.

Related Posts

Comments

Popular posts from this blog

EC2 No Internet Access in Custom VPC: Fix Internet Gateway and Route Table

EC2 SSH Connection Timeout: Which Security Group Rules to Check

Difference Between IAM User and IAM Role: Which One Should Your EC2 Use?