Multi-Cloud Networking Guide
A practical engineering guide to connecting workloads across AWS, Azure, and GCP with production-grade networking. This kit provides Terraform modules for cross-cloud VPN tunnels, transit gateway peering, service mesh federation, and unified DNS management. Each pattern includes bandwidth calculations, latency benchmarks, cost estimates, and failover configurations. Whether you're connecting two clouds for a specific workload or building a full multi-cloud fabric, this guide gives you the blueprints that actually work in production.
Key Features
- Cross-Cloud VPN Tunnels — Site-to-site VPN configurations between AWS VPC, Azure VNet, and GCP VPC with BGP routing
- Transit Gateway Patterns — Hub-and-spoke topologies using AWS Transit Gateway, Azure Virtual WAN, and GCP Cloud Interconnect
- Service Mesh Federation — Istio multi-cluster configurations for seamless service-to-service communication across clouds
- Unified DNS — Split-horizon DNS with conditional forwarding, private DNS zones, and cross-cloud name resolution
- Network Security — Cross-cloud firewall rules, security group synchronization patterns, and encrypted tunnel configurations
- Latency Optimization — Region pairing recommendations, path optimization, and Global Accelerator / Front Door configurations
- Cost Calculator — Data transfer cost estimator across clouds with egress optimization strategies
- Monitoring & Alerting — Tunnel health dashboards, bandwidth utilization tracking, and failover alerting
Quick Start
# Deploy AWS-to-Azure VPN tunnel
cd src/terraform/aws-azure-vpn
cp terraform.tfvars.example terraform.tfvars
# Configure AWS VPC CIDR, Azure VNet CIDR, and shared key
terraform init
terraform plan -out=plan.out
terraform apply plan.out
# Verify tunnel connectivity
python3 src/tools/tunnel_health.py \
--source aws:us-east-1 \
--target azure:eastus2 \
--test-latency
Architecture
┌──────────────────────────────────────────────────────────┐
│ Multi-Cloud Network Topology │
│ │
│ ┌────────────────┐ ┌────────────────┐ │
│ │ AWS │ │ Azure │ │
│ │ ┌────────────┐ │ IPSec VPN │ ┌────────────┐ │ │
│ │ │ VPC │ │◄══════════════►│ │ VNet │ │ │
│ │ │ 10.0.0.0/16│ │ BGP Peering │ │ 10.1.0.0/16│ │ │
│ │ │ │ │ │ │ │ │ │
│ │ │ Transit GW │ │ │ │ Virtual WAN│ │ │
│ │ └────────────┘ │ │ └────────────┘ │ │
│ └───────┬────────┘ └───────┬────────┘ │
│ │ IPSec VPN │ │
│ │ ┌───────────┐ │ │
│ └────────►│ GCP │◄──────────┘ │
│ │ ┌───────┐ │ │
│ │ │ VPC │ │ │
│ │ │10.2.0 │ │ │
│ │ │ /16 │ │ │
│ │ └───────┘ │ │
│ └───────────┘ │
│ │
│ DNS Resolution: │
│ ┌──────────────────────────────────────────────────┐ │
│ │ Route 53 ◄──► Azure DNS ◄──► Cloud DNS │ │
│ │ Conditional forwarding for cross-cloud zones │ │
│ └──────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────┘
Usage Examples
AWS-to-Azure Site-to-Site VPN
# src/terraform/aws-azure-vpn/aws-side.tf
resource "aws_vpn_gateway" "main" {
vpc_id = var.aws_vpc_id
amazon_side_asn = 64512
tags = { Name = "${var.project}-vpn-gw" }
}
resource "aws_customer_gateway" "azure" {
bgp_asn = 65515 # Azure default ASN
ip_address = var.azure_vpn_gw_public_ip
type = "ipsec.1"
tags = { Name = "${var.project}-azure-cgw" }
}
resource "aws_vpn_connection" "to_azure" {
vpn_gateway_id = aws_vpn_gateway.main.id
customer_gateway_id = aws_customer_gateway.azure.id
type = "ipsec.1"
static_routes_only = false # Use BGP for dynamic routing
tunnel1_preshared_key = var.vpn_shared_key
tunnel1_ike_versions = ["ikev2"]
tags = { Name = "${var.project}-aws-to-azure" }
}
# Route propagation — learn Azure routes via BGP
resource "aws_vpn_gateway_route_propagation" "main" {
vpn_gateway_id = aws_vpn_gateway.main.id
route_table_id = var.aws_route_table_id
}
Azure Side of the VPN
# src/terraform/aws-azure-vpn/azure-side.tf
resource "azurerm_virtual_network_gateway" "main" {
name = "${var.project}-vnet-gw"
location = var.azure_location
resource_group_name = var.azure_rg_name
type = "Vpn"
vpn_type = "RouteBased"
sku = "VpnGw2"
enable_bgp = true
bgp_settings {
asn = 65515
}
ip_configuration {
subnet_id = var.gateway_subnet_id
public_ip_address_id = azurerm_public_ip.vpn_gw_pip.id
}
}
resource "azurerm_local_network_gateway" "aws" {
name = "${var.project}-aws-lng"
location = var.azure_location
resource_group_name = var.azure_rg_name
gateway_address = var.aws_vpn_tunnel1_address
address_space = [var.aws_vpc_cidr]
bgp_settings {
asn = 64512
bgp_peering_address = var.aws_bgp_peer_address
}
}
resource "azurerm_virtual_network_gateway_connection" "to_aws" {
name = "${var.project}-azure-to-aws"
location = var.azure_location
resource_group_name = var.azure_rg_name
type = "IPsec"
virtual_network_gateway_id = azurerm_virtual_network_gateway.main.id
local_network_gateway_id = azurerm_local_network_gateway.aws.id
shared_key = var.vpn_shared_key
enable_bgp = true
}
Cross-Cloud DNS Forwarding
# src/terraform/dns/route53-conditional-forwarding.tf
resource "aws_route53_resolver_rule" "forward_to_azure" {
domain_name = "internal.azure.example.com"
rule_type = "FORWARD"
resolver_endpoint_id = aws_route53_resolver_endpoint.outbound.id
target_ip {
ip = var.azure_dns_inbound_ip # Azure Private DNS resolver IP
}
tags = { Name = "forward-azure-dns" }
}
resource "aws_route53_resolver_rule_association" "main" {
resolver_rule_id = aws_route53_resolver_rule.forward_to_azure.id
vpc_id = var.aws_vpc_id
}
Configuration
# configs/multi-cloud-network.yaml
project: acme-multicloud
aws:
region: us-east-1
vpc_cidr: 10.0.0.0/16
asn: 64512
azure:
region: eastus2
vnet_cidr: 10.1.0.0/16
asn: 65515
gcp:
region: us-east4
vpc_cidr: 10.2.0.0/16
asn: 65520
vpn:
ike_version: ikev2
encryption: AES-256-GCM
dh_group: 14 # 2048-bit MODP
sa_lifetime_seconds: 3600
dns:
primary_domain: example.com
aws_zone: aws.internal.example.com
azure_zone: azure.internal.example.com
gcp_zone: gcp.internal.example.com
monitoring:
tunnel_health_check_interval: 30 # seconds
bandwidth_alert_threshold_mbps: 800
alert_email: network-team@example.com
Best Practices
- Use non-overlapping CIDRs — Plan your IP address space across all clouds before deploying anything
- Enable BGP for dynamic routing — Static routes break when you add subnets; BGP propagates automatically
- Deploy redundant tunnels — Single tunnels are single points of failure; use two tunnels per connection
- Monitor egress costs — Cross-cloud data transfer is the hidden cost killer; cache aggressively and compress payloads
- Use private endpoints where possible — Azure Private Link and AWS PrivateLink reduce data transfer costs and improve security
- Test failover regularly — Simulate tunnel failures monthly to verify BGP failover and DNS resolution work correctly
Troubleshooting
| Issue | Cause | Fix |
|---|---|---|
VPN tunnel shows DOWN
|
Phase 1 (IKE) parameter mismatch | Verify IKE version, encryption algorithm, and DH group match on both sides |
| BGP session not establishing | ASN misconfiguration or firewall blocking TCP 179 | Verify ASN values; ensure NSG/SG allows BGP traffic between tunnel IPs |
| Cross-cloud DNS resolution fails | Conditional forwarder pointing to wrong IP | Verify target IP is the inbound resolver endpoint, not a VNet DNS server |
| High latency between clouds | Traffic routing through public internet | Verify VPN tunnel is UP and route tables prefer the tunnel over internet gateway |
This is 1 of 11 resources in the Cloud Architecture Pro toolkit. Get the complete [Multi-Cloud Networking Guide] with all files, templates, and documentation for $39.
Or grab the entire Cloud Architecture Pro bundle (11 products) for $149 — save 30%.
Top comments (0)