Terraform GCP Azure site-to-site VPN

Hey in this blog post I will present the recipe for creating a static route site-to-site vpn between GCP and Azure using Terraform.

!Disclaimer I am not following any kind of best practice my only goal was to create a working Site-to-site VPN connection between a GCP and Azure - so please don’t think that this is a production ready example!

The main catch I got out of this is that if you need a connection that is bi-directional you must create a gateway on each site you want to connect and also to create connections for each one - the recomended number of connections is 2 but in the example for the sake of saving some pennies I used just a connection.

GCP :

Azure :

GCP

Public ip GCP

resource "google_compute_address" "gcp_vpn_ip" {
  name   = "gcp_vpn_ip"
  region = "${var.gcp_region}"
}

Google compute vpn gateway

resource "google_compute_vpn_gateway" "gcp_vpn_gateway" {
  name    = "gcp_vpn_gateway"
  network = "${google_compute_network.gcp_network.name}"
  region  = "${var.gcp_region}"
}

Loose forwarding rules

resource "google_compute_forwarding_rule" "fr_esp" {
  name        = "fr_esp"
  ip_protocol = "ESP"
  ip_address  = "${google_compute_address.gcp_vpn_ip.address}"
  target      = "${google_compute_vpn_gateway.gcp_vpn_gateway.self_link}"
}

resource "google_compute_forwarding_rule" "fr_udp500" {
  name        = "fr_udp500"
  ip_protocol = "UDP"
  port_range  = "500_500"
  ip_address  = "${google_compute_address.gcp_vpn_ip.address}"
  target      = "${google_compute_vpn_gateway.gcp_vpn_gateway.self_link}"
}

resource "google_compute_forwarding_rule" "fr_udp4500" {
  name        = "fr_udp4500"
  ip_protocol = "UDP"
  port_range  = "4500_4500"
  ip_address  = "${google_compute_address.gcp_vpn_ip.address}"
  target      = "${google_compute_vpn_gateway.gcp_vpn_gateway.self_link}"
}

Google compute vpn tunnel

  resource "google_compute_vpn_tunnel" "gcp_vpn_tunnel" {
  name        = "gcp_vpn_tunnel"
  peer_ip     = "${data.azurerm_public_ip.vpn_ipv4.ip_address}"
  ike_version = 2

  shared_secret = "123456789" 

  target_vpn_gateway = "${google_compute_vpn_gateway.gcp_vpn_gateway.self_link}"

  local_traffic_selector  = ["${var.gcp_vpc_range}"]
  remote_traffic_selector = ["${var.azure_vpc_range}"]

  depends_on = [
    "google_compute_forwarding_rule.fr_esp",
    "google_compute_forwarding_rule.fr_udp500",
    "google_compute_forwarding_rule.fr_udp4500",
    "data.azurerm_public_ip.vpn_ipv4",
  ]
}

Google compute route

resource "google_compute_route" "azure_route" {
  name                = "azure_route"
  dest_range          = "${var.azure_vpc_range}"
  network             = "${google_compute_network.gcp_network.self_link}"
  next_hop_vpn_tunnel = "${google_compute_vpn_tunnel.gcp_vpn_tunnel.self_link}"
  priority            = 100
  depends_on = [
    "google_compute_vpn_tunnel.gcp_vpn_tunnel"
  ]
}

Azure

Public ip Azure

resource "azurerm_public_ip" "vpn_ipv4" {
  name                = "vpn_ipv4"
  location            = "${azurerm_resource_group.resource_group_1.location}"
  resource_group_name = "${azurerm_resource_group.resource_group_1.name}"
  allocation_method   = "Dynamic"
}

data "azurerm_public_ip" "vpn_ipv4" {
  name                = "vpn_ipv4"
  resource_group_name = "${azurerm_resource_group.resource_group_1.name}"
  depends_on = [
    "azurerm_virtual_network_gateway.az_vnet_gw"
  ]
}

Local network gateway

resource "azurerm_local_network_gateway" "gcp_local_vnet_gw" {
  name = "gcp_local_vnet_gw"

  location            = "${azurerm_resource_group.resource_group_1.location}"
  resource_group_name = "${azurerm_resource_group.resource_group_1.name}"

  gateway_address = "${google_compute_address.gcp_vpn_ip.address}"
  address_space   = ["${var.gcp_vpc_range}"]
}

Virtual network gateway

resource "azurerm_virtual_network_gateway" "az_vnet_gw" {
  name                = "az_vnet_gw"
  location            = "${azurerm_resource_group.resource_group_1.location}"
  resource_group_name = "${azurerm_resource_group.resource_group_1.name}"

  type     = "vpn"
  vpn_type = "RouteBased"

  active_active = false
  enable_bgp    = false
  sku           = "HighPerformance"

  ip_configuration {
    name                          = "vnetGatewayConfig"
    public_ip_address_id          = "${azurerm_public_ip.vpn_ipv4.id}"
    private_ip_address_allocation = "Dynamic"
    subnet_id                     = "${azurerm_subnet.mygwsubnet.id}"
  }
}

Virtual network gateway connection

resource "azurerm_virtual_network_gateway_connection" "gcp_gw_conn" {
  name = "gcp_gw_conn"

  location            = "${azurerm_resource_group.resource_group_1.location}"
  resource_group_name = "${azurerm_resource_group.resource_group_1.name}"

  type = "IPsec"

  virtual_network_gateway_id = "${azurerm_virtual_network_gateway.az_vnet_gw.id}"
  local_network_gateway_id   = "${azurerm_local_network_gateway.gcp_local_vnet_gw.id}"

  shared_key = "123456789"
}

A repository containing all the code to run a terraform deploy will be added soon.

Thanks for reading !

Written on October 4, 2019