Getting started with Azure and Terraform – Part 4

In this part of the series I want to add the VPN to the solution and this includes the Virtual Network Gateway, the Local Gateway and the Connection objects in Azure and then I will also show you the setup in my ubiquiti setup I run at home. The VPN connection is a great way to get something running in Azure fast without having to install domain controllers and so on, instead we can use the existing environment we have on-premises so we can get up and running.

The first item I need to create is a public IP address for the VPN connection. Below is the code I use to create this IP address, and notice that I have a depends-on for the hub vNet. I could make this a dependency on the resource group creation instead, but I like to have the vNet created before since the Virtual Network Gateway that needs the vNet will be created after the public IP address.

resource "azurerm_public_ip" "VPN-PIP" {
  name                = "S2S-VPNGateway-PIP"
  location            = var.Location
  resource_group_name = var.ResourceGroups.HubNetwork

  allocation_method = "Dynamic"
  depends_on = [module.HubvNet]

Now I can create my Virtual Network Gateway, notice the depends-on is now set to the public IP address that I just created. Also, notice that I am referring the subnet_id to module.HubvNet.vnet_subnets[0] the [0] reference the first subnet I created in the hub vNet, and I always create the GatewaySubnet as the first one when I have a vNet with a gateway in. I would like this to be dynamic, so please let me know if you know how I can that.

resource "azurerm_virtual_network_gateway" "S2S-VPNGateway" {
  name                = "S2S-VPNGateway"
  location            = var.Location
  resource_group_name = var.ResourceGroups.HubNetwork

  type     = "Vpn"
  vpn_type = "RouteBased"

  active_active = false
  enable_bgp    = false
  sku           = "Basic"

  ip_configuration {
    name                          = "S2S-VPN-Config"
    public_ip_address_id          =
    private_ip_address_allocation = "Dynamic"
    subnet_id                     = module.HubvNet.vnet_subnets[0]
  depends_on = [azurerm_public_ip.VPN-PIP]

It is now time to create the local gateway. This part has the information on the network I have on-premises. This is my public IP and the network address space I am using.

resource "azurerm_local_network_gateway" "S2S-LocalGateway" {
  name                = "S2S-LocalGateway"
  location            = var.Location
  resource_group_name = var.ResourceGroups.HubNetwork
  gateway_address     = var.LocalGateway.gateway_address
  address_space       = [var.LocalGateway.address_space]

  depends_on = [module.HubvNet]

The last part of this configuration is what Microsoft refers to as the Connection. This part couples the Virtual Network Gateway with the Local Network Gateway and holds the pre-shared key for the VPN connection. Because of this coupling, I have depends on both the resources before I start creating the Connection part.

resource "azurerm_virtual_network_gateway_connection" "S2S-Connection" {
  name                = "S2S-Connection"
  location            = var.Location
  resource_group_name = var.ResourceGroups.HubNetwork

  type                       = "IPsec"
  virtual_network_gateway_id =
  local_network_gateway_id   =

  shared_key = var.pre-shared-key

  depends_on = [azurerm_virtual_network_gateway.S2S-VPNGateway, azurerm_local_network_gateway.S2S-LocalGateway]

I can now run the command “terraform plan -out network.plan” again to create the updated network plan. I can now deploy the updated plan with the ’terraform apply “network.plan”’ command. The deployment takes over 30 mins in my case, and will look something like the image below.

When the deployment is complete, I can update my local VPN endpoint with the public IP address. In my case, this is a Ubiquiti USG that handles my VPN, so my configuration is as shown below.

In Azure, I can now see that the VPN tunnel is up and running.

This concludes my network creation in this blog series. The next part will be creating a virtual machine in the network we just created. Stay tuned.