Overview
Recently I have been working with Azure Virtual WAN to provide connectivity between Azure Regions, Branch Offices, and Remote Users. Azure Virtual WAN is a networking service that brings many of the commonly found connectivity services into a single area, providing simplified connectivity and management. These services include:
-
-
Branch connectivity.
-
Site-to-site VPN connectivity.
-
Remote user VPN connectivity (point-to-site).
-
Private connectivity (ExpressRoute).
-
Intra-cloud connectivity (transitive connectivity for virtual networks).
-
VPN ExpressRoute inter-connectivity.
-
Routing, Azure Firewall, and encryption for private connectivity.
-
You can read more about Azure Virtual WAN on the Microsoft Documentation page here: https://docs.microsoft.com/en-us/azure/virtual-wan/virtual-wan-about
Azure Virtual WAN is a great solution for multi-region deployments, and simplifies deployment where branch or remote user connectivity is required, by bringing all the features needed into a single area.
Most of the deployments I have been working on have been utilising Terraform to conduct the deployment, and that will be the focus of this post.
Why use Virtual WAN?
Virtual WAN provides an integrated approach to connectivity – bringing many features to a single area within Azure, and providing additional levels of automation and control. Use cases like branch and remote user connectivity are obvious, but also there are options that Virtual WAN enables – creating new Resource Deployments rapidly in new Regions for example, by virtue of the easily expanded connectivity. Technologies like Citrix and other third party solutions can benefit from Virtual WAN too. In many cases it is simply about getting a connectivity baseline into your Cloud estate – and in the case of Virtual WAN, a solution that offers easily expanded and branch site connectivity with ease.
Deploying Virtual WAN with Terraform – Demo Lab
To deploy Azure Virtual WAN with Terraform, we will be using the AzureRM provider. If you need a refresher on getting started or using Terraform with Azure, check out my series on this here. Within this post, I’ll be breaking down the steps taken to create my Virtual WAN Demo Environment, available within my GitHub Repo.
✅ This environment is a simple starting point for Virtual WAN – it is not intended for production use!
This environment deploys the following:
-
-
A Resource Group in each of the two Azure Regions.
-
A Virtual WAN in the Primary Region
-
A Virtual WAN Hub in two Azure Regions
-
A VNet in each Azure Region which is connected to the Virtual WAN Hub.
-
A Subnet and NSG in each of the above VNets.
-
A KeyVault, with an administrator password (generated randomly by Terraform) for the VMs.
-
A Virtual Machine in each Azure Region (in the Regional VNets), to allow testing of Connectivity. Note: these VMs have a Public IP and RDP is enabled for easy testing access.
-
A Custom Script Extension that runs on both VMs to add a few testing Apps (using Chocolatey) and allows ICMP through Windows Firewall for testing connectivity over Virtual WAN.
-
The diagram below shows the Lab environment:
The concept behind the Lab (other than demonstrating Virtual WAN using Terraform), is that whilst direct RDP to VMs would not normally be enabled, this allows for easy testing – so we can RDP to the VMs and prove connectivity between them over Azure Virtual WAN.
As you can see in the below diagram, Spoke to Spoke communication (so, in our case from VM to VM across Regions) will transit via Virtual WAN:
Virtual WAN Terraform – The Building Blocks
There are a number of important blocks of code we will need to define from the AzureRM Provider to create the Virtual WAN environment.
⚠ Note: the below aspects only cover the Virtual WAN elements, I’ve omitted aspects like the Virtual Machines – but you can download the full lab from my GitHub Repo if you’d rather just deploy it as a whole environment instead!
We need to create 3 core elements to setup Virtual WAN:
-
-
Virtual WAN
-
Virtual WAN Hubs
-
Virtual WAN Hub Connections to Spoke VNets
-
Creating the Virtual WAN:
The first element that we need to create is the Virtual WAN:
# Virtual WAN resource "azurerm_virtual_wan" "vwan1" { name = "${var.lab-name}-vWAN-01" resource_group_name = azurerm_resource_group.region1-rg1.name location = var.region1 # Configuration office365_local_breakout_category = "OptimizeAndAllow" tags = { Environment = var.environment_tag } }
https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/virtual_wan
Creating the Virtual WAN Hubs:
Virtual WAN Hubs are required in each Azure Region that we require connectivity within, so for this Lab environment we require two Virtual WAN Hubs:
# Virtual WAN Hubs resource "azurerm_virtual_hub" "region1-vhub1" { name = "${var.region1}-vWAN-hub-01" resource_group_name = azurerm_resource_group.region1-rg1.name location = var.region1 virtual_wan_id = azurerm_virtual_wan.vwan1.id address_prefix = var.vwan-region1-hub1-prefix1 tags = { Environment = var.environment_tag } } resource "azurerm_virtual_hub" "region2-vhub1" { name = "${var.region2}-vWAN-hub-02" resource_group_name = azurerm_resource_group.region2-rg1.name location = var.region2 virtual_wan_id = azurerm_virtual_wan.vwan1.id address_prefix = var.vwan-region2-hub1-prefix1 tags = { Environment = var.environment_tag } }
https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/virtual_hub
Creating the Hub to Spoke Connections:
To allow our VNet Spokes to communicate via Virtual WAN, we need to create a connection in each Region between the Virtual WAN Hub and Spoke VNet:
# Virtual WAN Connections resource "azurerm_virtual_hub_connection" "region1-connection1" { name = "${var.region1}-conn-vnet1-to-vwan-hub" virtual_hub_id = azurerm_virtual_hub.region1-vhub1.id remote_virtual_network_id = azurerm_virtual_network.region1-vnet1.id } resource "azurerm_virtual_hub_connection" "region2-connection1" { name = "${var.region2}-conn-vnet1-to-vwan-hub" virtual_hub_id = azurerm_virtual_hub.region2-vhub1.id remote_virtual_network_id = azurerm_virtual_network.region2-vnet1.id }
✅ To secure internet traffic and force this out via Azure Firewall, add the following line to the azurerm_virtual_hub_connection block. You will need a Secure Virtual Hub with Azure Firewall to achieve this.
internet_security_enabled = true
I want Azure Firewall too!
Should you wish to include Azure Firewall within the Virtual WAN Topology you can include this to create Secure Virtual Hubs, Firewalls, and Firewall Policies.
Firewalls
To create an Azure Firewall instance, use the code below – note that there is a difference in the “sku_name” and this is now referenced as “AZFW_Hub”.
# Firewalls resource "azurerm_firewall" "region1-fw01" { name = "${var.region1}-fw01" location = var.region1 resource_group_name = azurerm_resource_group.region1-rg1.name sku_tier = "Premium" sku_name = "AZFW_Hub" firewall_policy_id = azurerm_firewall_policy.fw-pol01.id virtual_hub { virtual_hub_id = azurerm_virtual_hub.region1-vhub1.id public_ip_count = 1 } }
https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/firewall
Firewall Policy & Ruleset
You will also need a Firewall Policy in place, to allow for traffic control. To create a Firewall Policy, use the code below:
#Firewall Policy resource "azurerm_firewall_policy" "fw-pol01" { name = "fw-pol01" resource_group_name = azurerm_resource_group.region1-rg1.name location = var.region1 } # Firewall Policy Rules resource "azurerm_firewall_policy_rule_collection_group" "region1-policy1" { name = "fw-pol01-rules" firewall_policy_id = azurerm_firewall_policy.fw-pol01.id priority = 100 network_rule_collection { name = "network_rules1" priority = 100 action = "Allow" rule { name = "network_rule_collection1_rule1" protocols = ["TCP", "UDP", "ICMP"] source_addresses = ["*"] destination_addresses = ["*"] destination_ports = ["*"] } } }
⚠ Note: by default, Private Traffic is NOT routed via Azure Firewall. You must enable this in the Portal. At the time of writing there does not appear to be a way to enable this using the AzureRM Terraform Provider.
✅Note: I would recommend reading this link around multi-region Virtual WAN and Azure Firewall deployment as there are currently some additional considerations: https://docs.microsoft.com/en-us/azure/virtual-wan/how-to-routing-policies#key-considerations
What about Connectivity?
Azure Virtual WAN also provides a range of connectivity options, supporting Site-to-Site VPNs, Point to Site VPNs, ExpressRoute and third-party integrations. I’ve outlined the Terraform required for Site-to-Site, Point to Site, and ExpressRoute below:
Site-to-Site Connectivity
To create a Site-to-Site connection, you will initially need a VPN Gateway. Remember, you will need one of these in each Virtual WAN Hub you wish to connect into. You can create this using the code below:
resource "azurerm_vpn_gateway" "region1-gateway1" { name = "${var.region1}-vpngw-01" location = var.region1 resource_group_name = azurerm_resource_group.region1-rg1.name virtual_hub_id = azurerm_virtual_hub.region1-vhub1.id }
https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/vpn_gateway
Once the Gateway is in place, you can create a VPN Site. These sites represent the Physical locations you wish to connect to:
resource "azurerm_vpn_site" "region1-officesite1" { name = "${var.region1}-officesite-01" location = azurerm_resource_group.region1-rg1.location resource_group_name = azurerm_resource_group.region1-rg1.name virtual_wan_id = azurerm_virtual_wan.vwan1.id address_cidrs = ["10.100.0.0/24"] link { name = "Office-Link-1" ip_address = "10.1.0.0" speed_in_mbps = "20" } }
https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/vpn_site
Once the site is created, you can then define the connection:
} resource "azurerm_vpn_gateway_connection" "region1-officesite1" { name = "${var.region1}-officesite1-conn" vpn_gateway_id = azurerm_vpn_gateway.region1-gateway1.id remote_vpn_site_id = azurerm_vpn_site.region1-officesite1.id vpn_link { name = "link1" vpn_site_link_id = azurerm_vpn_site.region1-officesite1.link[0].id } }
⚠ Note, you will also need to define a number of connection specific aspects here too, like connection modes/names/protocols etc. See here: https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/vpn_gateway_connection
Point to Site Connectivity
To create a Point to Site Connection, we need two items in place: a Gateway and a Configuration. To create the Gateway and Configuration, use the code below:
resource "azurerm_point_to_site_vpn_gateway" "region1-p2s-01" { name = "${var.region1}-p2s-01" location = var.region1 resource_group_name = azurerm_resource_group.region1-rg1.name virtual_hub_id = azurerm_virtual_hub.region1-vhub1.id vpn_server_configuration_id = azurerm_vpn_server_configuration.region1-p2s-conn-01.id scale_unit = 1 connection_configuration { name = "${var.region1}-p2s-01" vpn_client_address_pool { address_prefixes = [ "10.10.12.0/24" ] } } } resource "azurerm_vpn_server_configuration" "region1-p2s-conn-01" { name = "${var.region1}-p2s-conn-01" resource_group_name = azurerm_resource_group.region1-rg1.name location = var.region1 vpn_authentication_types = ["AAD"] azure_active_directory_authentication { audience = "GUID-goes-here" issuer = "https://sts.windows.net/your-Directory-ID/" tenant = "GUID-goes-here" } }
⚠ Note: You may need to customise the above depending on your required configuration, see here: https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/vpn_server_configuration
ExpressRoute
If you wish to utilised ExpressRoute with Virtual WAN, you will need to create an ExpressRoute Gateway within your Hub using the code below:
resource "azurerm_express_route_gateway" "region1-er-gateway-01" { name = "${var.region1}-er-gateway-01" resource_group_name = azurerm_resource_group.region1-rg1.name location = var.region1 virtual_hub_id = azurerm_virtual_hub.region1-vhub1.id scale_units = 1 tags = { environment = "Production" } }
Once this Gateway is in place the ExpressRoute Circuit, Peering and Connection can be created. There are range of options you can specify here, and for obvious reasons ExpressRoute is not available within my personal Lab environment (I wish! ?), so I will just provide links to the relevant AzureRM Provider Sections instead:
- https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/express_route_circuit
- https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/express_route_circuit_authorization
- https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/express_route_circuit_connection
- https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/express_route_circuit_peering
- https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/express_route_connection
Conclusion
Hopefully this post was helpful in running through the Terraform required to deploy Azure Virtual WAN, and providing a small testing Lab. If you have any questions please feel free to reach out via my contact page or twitter! ☺