Cross-Cloud Networking
Connecting networks across different cloud providers is one of the most complex aspects of multi-cloud architecture. Each provider has different networking models, security requirements, and connectivity options. This part covers practical patterns for establishing secure, reliable connections between AWS, Azure, and GCP.
AWS-Azure VPN Connection
Establish site-to-site VPN between AWS and Azure:
# AWS side configuration
data "aws_availability_zones" "available" {
state = "available"
}
resource "aws_vpc" "main" {
cidr_block = "10.0.0.0/16"
enable_dns_hostnames = true
enable_dns_support = true
tags = {
Name = "aws-vpc"
}
}
resource "aws_subnet" "private" {
vpc_id = aws_vpc.main.id
cidr_block = "10.0.1.0/24"
availability_zone = data.aws_availability_zones.available.names[0]
tags = {
Name = "aws-private-subnet"
}
}
resource "aws_vpn_gateway" "main" {
vpc_id = aws_vpc.main.id
tags = {
Name = "aws-vpn-gateway"
}
}
resource "aws_customer_gateway" "azure" {
bgp_asn = 65000
ip_address = azurerm_public_ip.vpn_gateway.ip_address
type = "ipsec.1"
tags = {
Name = "azure-customer-gateway"
}
}
resource "aws_vpn_connection" "azure" {
vpn_gateway_id = aws_vpn_gateway.main.id
customer_gateway_id = aws_customer_gateway.azure.id
type = "ipsec.1"
static_routes_only = true
tags = {
Name = "aws-azure-vpn"
}
}
resource "aws_vpn_connection_route" "azure" {
vpn_connection_id = aws_vpn_connection.azure.id
destination_cidr_block = "10.1.0.0/16"
}
# Azure side configuration
resource "azurerm_resource_group" "main" {
name = "multi-cloud-rg"
location = "East US"
}
resource "azurerm_virtual_network" "main" {
name = "azure-vnet"
address_space = ["10.1.0.0/16"]
location = azurerm_resource_group.main.location
resource_group_name = azurerm_resource_group.main.name
}
resource "azurerm_subnet" "gateway" {
name = "GatewaySubnet"
resource_group_name = azurerm_resource_group.main.name
virtual_network_name = azurerm_virtual_network.main.name
address_prefixes = ["10.1.255.0/27"]
}
resource "azurerm_public_ip" "vpn_gateway" {
name = "azure-vpn-gateway-ip"
location = azurerm_resource_group.main.location
resource_group_name = azurerm_resource_group.main.name
allocation_method = "Static"
sku = "Standard"
}
resource "azurerm_virtual_network_gateway" "main" {
name = "azure-vpn-gateway"
location = azurerm_resource_group.main.location
resource_group_name = azurerm_resource_group.main.name
type = "Vpn"
vpn_type = "RouteBased"
active_active = false
enable_bgp = false
sku = "VpnGw1"
ip_configuration {
name = "vnetGatewayConfig"
public_ip_address_id = azurerm_public_ip.vpn_gateway.id
private_ip_address_allocation = "Dynamic"
subnet_id = azurerm_subnet.gateway.id
}
}
resource "azurerm_local_network_gateway" "aws" {
name = "aws-local-gateway"
resource_group_name = azurerm_resource_group.main.name
location = azurerm_resource_group.main.location
gateway_address = aws_vpn_connection.azure.tunnel1_address
address_space = ["10.0.0.0/16"]
}
resource "azurerm_virtual_network_gateway_connection" "aws" {
name = "azure-aws-connection"
location = azurerm_resource_group.main.location
resource_group_name = azurerm_resource_group.main.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 = aws_vpn_connection.azure.tunnel1_preshared_key
}
AWS-GCP Interconnect
Establish dedicated connection between AWS and GCP:
# GCP side configuration
resource "google_compute_network" "main" {
name = "gcp-vpc"
auto_create_subnetworks = false
}
resource "google_compute_subnetwork" "private" {
name = "gcp-private-subnet"
ip_cidr_range = "10.2.1.0/24"
region = "us-central1"
network = google_compute_network.main.id
}
resource "google_compute_router" "main" {
name = "gcp-router"
region = "us-central1"
network = google_compute_network.main.id
bgp {
asn = 64512
}
}
resource "google_compute_vpn_gateway" "main" {
name = "gcp-vpn-gateway"
network = google_compute_network.main.id
region = "us-central1"
}
resource "google_compute_address" "vpn_static_ip" {
name = "gcp-vpn-ip"
region = "us-central1"
}
resource "google_compute_vpn_tunnel" "aws" {
name = "gcp-aws-tunnel"
peer_ip = aws_vpn_connection.gcp.tunnel1_address
shared_secret = aws_vpn_connection.gcp.tunnel1_preshared_key
target_vpn_gateway = google_compute_vpn_gateway.main.id
depends_on = [
google_compute_forwarding_rule.esp,
google_compute_forwarding_rule.udp500,
google_compute_forwarding_rule.udp4500,
]
}
resource "google_compute_route" "aws" {
name = "route-to-aws"
network = google_compute_network.main.name
dest_range = "10.0.0.0/16"
priority = 1000
next_hop_vpn_tunnel = google_compute_vpn_tunnel.aws.id
}
Multi-Cloud Transit Gateway
Create a hub-and-spoke network topology:
# Central transit hub in AWS
resource "aws_ec2_transit_gateway" "hub" {
description = "Multi-cloud transit hub"
tags = {
Name = "multi-cloud-tgw"
}
}
resource "aws_ec2_transit_gateway_vpc_attachment" "aws_vpc" {
subnet_ids = [aws_subnet.private.id]
transit_gateway_id = aws_ec2_transit_gateway.hub.id
vpc_id = aws_vpc.main.id
tags = {
Name = "aws-vpc-attachment"
}
}
resource "aws_ec2_transit_gateway_vpn_attachment" "azure" {
vpn_connection_id = aws_vpn_connection.azure.id
transit_gateway_id = aws_ec2_transit_gateway.hub.id
tags = {
Name = "azure-vpn-attachment"
}
}
resource "aws_ec2_transit_gateway_route_table" "main" {
transit_gateway_id = aws_ec2_transit_gateway.hub.id
tags = {
Name = "multi-cloud-route-table"
}
}
resource "aws_ec2_transit_gateway_route" "azure" {
destination_cidr_block = "10.1.0.0/16"
transit_gateway_attachment_id = aws_ec2_transit_gateway_vpn_attachment.azure.id
transit_gateway_route_table_id = aws_ec2_transit_gateway_route_table.main.id
}
Network Automation Script
Automate cross-cloud network setup and validation:
#!/bin/bash
# scripts/setup-cross-cloud-network.sh
set -e
AWS_REGION=${1:-"us-west-2"}
AZURE_REGION=${2:-"East US"}
GCP_REGION=${3:-"us-central1"}
setup_aws_networking() {
echo "Setting up AWS networking..."
cd aws/
terraform init
terraform plan -var="region=$AWS_REGION"
terraform apply -auto-approve -var="region=$AWS_REGION"
# Export connection details
terraform output -json > ../aws-outputs.json
cd ..
}
setup_azure_networking() {
echo "Setting up Azure networking..."
# Import AWS VPN details
AWS_VPN_IP=$(jq -r '.vpn_tunnel1_address.value' aws-outputs.json)
AWS_PRESHARED_KEY=$(jq -r '.vpn_tunnel1_preshared_key.value' aws-outputs.json)
cd azure/
terraform init
terraform plan \
-var="location=$AZURE_REGION" \
-var="aws_vpn_ip=$AWS_VPN_IP" \
-var="aws_preshared_key=$AWS_PRESHARED_KEY"
terraform apply -auto-approve \
-var="location=$AZURE_REGION" \
-var="aws_vpn_ip=$AWS_VPN_IP" \
-var="aws_preshared_key=$AWS_PRESHARED_KEY"
cd ..
}
setup_gcp_networking() {
echo "Setting up GCP networking..."
cd gcp/
terraform init
terraform plan -var="region=$GCP_REGION"
terraform apply -auto-approve -var="region=$GCP_REGION"
cd ..
}
validate_connectivity() {
echo "Validating cross-cloud connectivity..."
# Test AWS to Azure
AWS_INSTANCE_IP=$(jq -r '.test_instance_private_ip.value' aws-outputs.json)
AZURE_INSTANCE_IP=$(jq -r '.test_instance_private_ip.value' azure-outputs.json)
echo "Testing AWS ($AWS_INSTANCE_IP) to Azure ($AZURE_INSTANCE_IP)..."
# This would typically involve SSH to instances and running ping tests
# For demo purposes, we'll just check VPN status
aws ec2 describe-vpn-connections \
--region "$AWS_REGION" \
--query 'VpnConnections[0].State' \
--output text
}
# Execute setup
setup_aws_networking
setup_azure_networking
setup_gcp_networking
validate_connectivity
echo "✅ Multi-cloud network setup completed"
Network Monitoring
Monitor cross-cloud network performance:
#!/usr/bin/env python3
# scripts/network_monitor.py
import boto3
import time
from azure.identity import DefaultAzureCredential
from azure.mgmt.network import NetworkManagementClient
from google.cloud import monitoring_v3
class MultiCloudNetworkMonitor:
def __init__(self):
self.aws_ec2 = boto3.client('ec2')
self.aws_cloudwatch = boto3.client('cloudwatch')
def check_aws_vpn_status(self, vpn_connection_id: str) -> dict:
"""Check AWS VPN connection status"""
response = self.aws_ec2.describe_vpn_connections(
VpnConnectionIds=[vpn_connection_id]
)
connection = response['VpnConnections'][0]
return {
'state': connection['State'],
'tunnel1_state': connection['VgwTelemetry'][0]['Status'],
'tunnel2_state': connection['VgwTelemetry'][1]['Status'],
'tunnel1_accepted_routes': connection['VgwTelemetry'][0]['AcceptedRouteCount'],
'tunnel2_accepted_routes': connection['VgwTelemetry'][1]['AcceptedRouteCount']
}
def get_network_metrics(self, vpn_connection_id: str) -> dict:
"""Get network performance metrics"""
end_time = time.time()
start_time = end_time - 3600 # Last hour
metrics = {}
# Get tunnel state metrics
for tunnel_num in [1, 2]:
response = self.aws_cloudwatch.get_metric_statistics(
Namespace='AWS/VPN',
MetricName='TunnelState',
Dimensions=[
{'Name': 'VpnId', 'Value': vpn_connection_id},
{'Name': 'TunnelIpAddress', 'Value': f'tunnel-{tunnel_num}'}
],
StartTime=start_time,
EndTime=end_time,
Period=300,
Statistics=['Average']
)
metrics[f'tunnel_{tunnel_num}_uptime'] = len([
dp for dp in response['Datapoints'] if dp['Average'] == 1
]) / len(response['Datapoints']) * 100 if response['Datapoints'] else 0
return metrics
def generate_report(self, vpn_connection_id: str) -> str:
"""Generate network status report"""
status = self.check_aws_vpn_status(vpn_connection_id)
metrics = self.get_network_metrics(vpn_connection_id)
report = [
"Multi-Cloud Network Status Report",
"=" * 40,
f"VPN Connection: {vpn_connection_id}",
f"Overall State: {status['state']}",
"",
"Tunnel Status:",
f" Tunnel 1: {status['tunnel1_state']} ({status['tunnel1_accepted_routes']} routes)",
f" Tunnel 2: {status['tunnel2_state']} ({status['tunnel2_accepted_routes']} routes)",
"",
"Uptime (Last Hour):",
f" Tunnel 1: {metrics.get('tunnel_1_uptime', 0):.1f}%",
f" Tunnel 2: {metrics.get('tunnel_2_uptime', 0):.1f}%"
]
return "\n".join(report)
def main():
import argparse
parser = argparse.ArgumentParser(description='Multi-Cloud Network Monitor')
parser.add_argument('--vpn-connection-id', required=True, help='AWS VPN Connection ID')
args = parser.parse_args()
monitor = MultiCloudNetworkMonitor()
report = monitor.generate_report(args.vpn_connection_id)
print(report)
if __name__ == "__main__":
main()
What’s Next
Cross-cloud networking provides the foundation for multi-cloud architecture, but managing identities and permissions across providers requires unified identity strategies. In the next part, we’ll explore how to implement consistent access control and identity management across AWS, Azure, and GCP.