LAB37_GCP_Hybrid Connectivity: High Availability (HA) VPN with BGP

Hybrid Connectivity: High Availability (HA) VPN with BGP

☁ GCP 🔥 Intermediate HA VPN Cloud Router BGP Hybrid Cloud

Scenario

Your GCP VPC needs to establish an encrypted, highly resilient Site-to-Site tunnel to an On-Premises data center (or another cloud like AWS). You must provision an HA VPN Gateway. Unlike "Classic VPN" which requires manual static route management, HA VPN guarantees 99.99% SLA using dual active tunnels and uses BGP (Border Gateway Protocol) via Cloud Router to dynamically advertise subnet IP blocks.

Your Objectives
  • Provision a custom VPC and a google_compute_router with BGP ASN enabled.
  • Provision a google_compute_ha_vpn_gateway inside the GCP VPC.
  • Mock the remote environment by provisioning a google_compute_external_vpn_gateway (representing your On-Prem router).
  • Provision two google_compute_vpn_tunnel resources pointing to the external gateway's two interfaces.
  • Provision two google_compute_router_interface and two google_compute_router_peer resources to establish BGP peering over the tunnels.

Additional Context

SLA Requirements: To get the 99.99% SLA from Google, you must configure two VPN tunnels. HA VPN Gateways have 2 external interfaces natively. You must map `interface 0` to your on-prem router's first IP, and `interface 1` to the second IP.

BGP API: Cloud Router uses BGP to automatically discover which subnets live On-Prem. For this to work, both sides must agree on a shared secret and unique BGP IPs inside the tunnel (usually `/30` links like `169.254.0.1` and `169.254.0.2`).

variables.tf

variable "project_id" { type = string }

main.tf

provider "google" {
  project = var.project_id
  region  = "us-central1"
}

# 1. VPC & BGP Router
resource "google_compute_network" "vpc" {
  name                    = "hybrid-vpc"
  auto_create_subnetworks = false
}

resource "google_compute_subnetwork" "subnet" {
  name          = "hybrid-subnet"
  network       = google_compute_network.vpc.id
  region        = "us-central1"
  cidr_range    = "10.0.1.0/24"
}

resource "google_compute_router" "bgp_router" {
  name    = "hybrid-bgp-router"
  network = google_compute_network.vpc.id
  region  = "us-central1"
  bgp {
    # Private Google ASN
    asn = 64514
  }
}

# 2. GCP HA VPN Gateway (2 physical interfaces created automatically by Google)
resource "google_compute_ha_vpn_gateway" "gcp_gateway" {
  name    = "ha-vpn-gateway"
  network = google_compute_network.vpc.id
  region  = "us-central1"
}

# 3. External VPN Gateway (Representation of your On-Prem/AWS Router)
resource "google_compute_external_vpn_gateway" "on_prem_gateway" {
  name            = "on-prem-gateway"
  redundancy_type = "TWO_IPS_REDUNDANCY"
  description     = "The customer datacenter Cisco CSR"

  interface {
    id         = 0
    ip_address = "8.8.8.8" # Mock public IP 1
  }
  interface {
    id         = 1
    ip_address = "8.8.4.4" # Mock public IP 2
  }
}

resource "random_password" "shared_secret" { length = 16; special = false }

# 4. VPN Tunnels (Data Plane)
resource "google_compute_vpn_tunnel" "tunnel_0" {
  name                            = "tunnel-0"
  region                          = "us-central1"
  vpn_gateway                     = google_compute_ha_vpn_gateway.gcp_gateway.id
  peer_external_gateway           = google_compute_external_vpn_gateway.on_prem_gateway.id
  peer_external_gateway_interface = 0
  shared_secret                   = random_password.shared_secret.result
  router                          = google_compute_router.bgp_router.name
  vpn_gateway_interface           = 0
}

resource "google_compute_vpn_tunnel" "tunnel_1" {
  name                            = "tunnel-1"
  region                          = "us-central1"
  vpn_gateway                     = google_compute_ha_vpn_gateway.gcp_gateway.id
  peer_external_gateway           = google_compute_external_vpn_gateway.on_prem_gateway.id
  peer_external_gateway_interface = 1
  shared_secret                   = random_password.shared_secret.result
  router                          = google_compute_router.bgp_router.name
  vpn_gateway_interface           = 1
}

# 5. BGP Sessions (Control Plane)
# Interface binds to Tunnel 0
resource "google_compute_router_interface" "router_if0" {
  name       = "router-if-0"
  router     = google_compute_router.bgp_router.name
  region     = "us-central1"
  ip_range   = "169.254.0.1/30"
  vpn_tunnel = google_compute_vpn_tunnel.tunnel_0.name
}

# Peering to On-Prem via Tunnel 0
resource "google_compute_router_peer" "router_peer_0" {
  name                      = "router-peer-0"
  router                    = google_compute_router.bgp_router.name
  region                    = "us-central1"
  peer_ip_address           = "169.254.0.2"
  peer_asn                  = 65001 # The On-Prem ASN
  advertised_route_priority = 100
  interface                 = google_compute_router_interface.router_if0.name
}

# Interface binds to Tunnel 1 ... (Repeated for secondary HA path, using 169.254.1.x subnet)
resource "google_compute_router_interface" "router_if1" {
  name       = "router-if-1"
  router     = google_compute_router.bgp_router.name
  region     = "us-central1"
  ip_range   = "169.254.1.1/30"
  vpn_tunnel = google_compute_vpn_tunnel.tunnel_1.name
}

resource "google_compute_router_peer" "router_peer_1" {
  name                      = "router-peer-1"
  router                    = google_compute_router.bgp_router.name
  region                    = "us-central1"
  peer_ip_address           = "169.254.1.2"
  peer_asn                  = 65001
  advertised_route_priority = 100
  interface                 = google_compute_router_interface.router_if1.name
}

Workflow Commands

terraform init
terraform apply -var="project_id=my-gcp-project-123"

# Verify the VPN gateways and tunnel configuration
gcloud compute vpn-tunnels list
gcloud compute routers get-status hybrid-bgp-router --region us-central1
# Status will show BGP sessions as DOWN since the mock 8.8.8.8 endpoint isn't 
# actually a responding VPN router configuring the other side of the handshake.

terraform destroy -var="project_id=my-gcp-project-123"