Microsoft offers the ability to create a direct, private connection between Azure data centers and infrastructure located on-premises or in a colocation with Azure ExpressRoute. ExpressRoute offers a network route for your connection to Azure data centers that connects directly and does not traverse the public Internet. The ExpressRoute connection also offers a faster speed, lower latency, and higher reliability connection than a typical Internet connection would.
These connections are purchased through a Service Provider that provide the direct connection. When an Azure ExpressRoute connection is being setup, the connection is purchased from a Service Provider, then the Azure ExpressRoute Circuit resource needs to be deployed into your Azure subscription and connected by the Service Provider to activate it.
In this article, we’ll take a look at the Terraform code using the azurerm
Provider to deploy an Azure ExpressRoute Circuit with Azure Private Peering that is connected to a Virtual Network. This setup will enable on-premises resources to have a network route through the Azure ExpressRoute connection to resources within Microsoft Azure.
Table of Contents
Azure ExpressRoute Resources
The Azure ExpressRoute circuit resource is the specific resource in Microsoft Azure for setting up an Azure ExpressRoute connection with a Service Provider. However, this alone wont get everything configured to use the ExpressRoute connection. Setting up an ExpressRoute Peeing is needed to configure the connection from on-premises to Azure resources. Also, to connect at a networking level to resources connected to an Azure Virtual Network (VNet) then an Azure Virtual Network Gateway must be deployed and connected to the ExpressRoute as well.
To deploy and configure this Azure ExpressRoute, there are a few Azure resources necessary:
- Azure ExpressRoute circuit – This is the Azure ExpressRoute connection.
- Azure Virtual Network – This is the VNet in Azure that will be connected to on-premises through the ExpressRoute connection.
- Azure Virtual Network Gateway – This is the VNet Gateway that connects the ExpressRoute circuit and VNet together.
- Azure Public IP – This is the Azure Public IP that is required for the VNet Gateway.

ExpressRoute Deployment Terraform Code
Before we look at all the Azure resources and their Terraform code to get this Azure ExpressRoute circuit and VNet Gateway deployed, the proceeding Terraform examples will require the following local
variables and azure_resource_group
to be deployed:
locals {
# Azure region to deploy to
azure_region = "eastus"
# define the Azure resource names
resource_name_prefix= "E1-B59-PRD-NET" # {region}-{org}-{env}-{app}
}
# The Azure Resource group for all the resources to reside
resource azurerm_resource_group "rg" {
name = "${local.resource_name_prefix}-rg"
location = local.azure_region
}
NOTE: This article uses an Azure resource naming convention of
{region}-{org}-{env}-{app}-{type}
This enables all the Azure resources to have a unique name and be organized with a naming convention that keeps all the resources named similar. You can learn more about coming up with a naming convention for your Azure resources in the “Azure Resource Naming Conventions and Best Practices” article here on Build5Nines.
Azure ExpressRoute Circuit
To deploy the Azure ExpressRoute itself, the azurerm_express_route_circuit
resource needs to be defined within the Terraform code. This resource will need to have the service_provider_name
attribute set to the specific name Azure ExpressRoute expects for the Service Provider you are purchasing the ExpressRoute connection from. You will also need to set the peering_location
correctly to the location of the ExpressRoute Service Provider for your connection. The peering_location
is not an Azure Region, but the location for the ExpressRoute Service Providers network exchange.
# Azure ExpressRoute Circuit
resource azurerm_express_route_circuit "express_route" {
name = "${local.resource_name_prefix}-erc"
resource_group_name = azurerm_resource_group.rg.name
location = azurerm_resource_group.rg.location
# https://docs.microsoft.com/en-us/azure/expressroute/expressroute-locations-providers
service_provider_name = "Equinix"
peering_location = "Washington DC"
bandwidth_in_mbps = 1000
sku {
tier = "Standard"
family = "MeteredData"
}
}
Once, the Azure ExpressRoute circuit is deployed to your Azure Subscription, you will need to grab the Service key from Azure and give it to the Service Provider so they can use it to finish the provisioning of the ExpressRoute circuit. This Service key is easily accessible within the Azure Portal.

Azure Private Peering needs be configured to enable connections to Azure resources through the Azure ExpressRoute circuit. The azurerm_express_route_circuit_peering
resource is deployed to setup the peerings on the ExpressRoute circuit. The following is a simple example that configured Azure Private Peering on the ExpressRoute circuit:
# Azure ExpressRoute Private Peering
resource azurerm_express_route_circuit_peering "express_route_peering" {
resource_group_name = azurerm_resource_group.rg.name
express_route_circuit_name = azurerm_express_route_circuit.express_route.name
peering_type = "AzurePrivatePeering"
primary_peer_address_prefix = "10.0.0.0/30"
secondary_peer_address_prefix = "10.0.0.0/30"
vlan_id = 100
}
Be sure to configure the correct IP Address prefixes necessary for your organizations networking environment.
Azure Virtual Network and Subnet
Before the Azure Virtual Network Gateway can be deployed and connected to the Azure ExpressRoute circuit, there will need to be an Azure Virtual Network (VNet) resource (azurerm_virtual_network
) to be deployed with a GatewaySubnet
subnet.
# Azure Virtual Network
resource azurerm_virtual_network "virtual_network" {
name = "${local.resource_name_prefix}-vnet"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
address_space = ["172.16.0.0/12"]
}
# GatewaySubnet within the Virtual Network
resource azurerm_subnet "gateway_subnet" {
name = "GatewaySubnet"
resource_group_name = azurerm_resource_group.rg.name
virtual_network_name = azurerm_virtual_network.virtual_network.name
address_prefixes = ["172.16.0.0/24"]
enforce_private_link_endpoint_network_policies = true
}
Be sure to configure the correct IP Address address space on the VNet and address prefix on the Subnet for your organization.
The GatewaySubnet
is the Subnet within the Azure Virtual Network that is configured with the IP Address range for which the IP Address of the Azure Virtual Network Gateway will be granted. This subnet must be named exactly GatewaySubnet
and cannot be named differently.
Public IP Address for VNet Gateway
Another item before the Virtual Network Gateway can be deployed is an Azure Public IP address resource (azurerm_public_ip
) that will be assigned to the Azure Virtual Network Gateway.
The following is the basic Terraform code to deploy the Azure Public IP address resource needed:
# Azure Public IP Address for the VNet Gateway
resource azurerm_public_ip "vnet_gateway_public_ip" {
name = "${local.resource_name_prefix}-vgw-pip"
resource_group_name = azurerm_resource_group.rg.name
location = azurerm_resource_group.rg.location
sku = "Basic"
allocation_method = "Dynamic"
}
Azure Virtual Network Gateway
An Azure Virtual Network Gateway resource (azurerm_virtual_network_gateway
) will be deployed to make the networking connection between the Azure ExpressRoute circuit and the Azure Virtual Network. This Virtual Network Gateway will be configured with the type
set to ExpressRoute
since this Gateway will be connected to an Azure ExpressRoute circuit.
The following is the basic code to deploy the Azure Virtual Network Gateway:
# Azure Virtual Network Gateway
resource azurerm_virtual_network_gateway "virtual_network_gateway" {
name = "${local.resource_name_prefix}-vgw"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
type = "ExpressRoute"
vpn_type = "PolicyBased"
sku = "HighPerformance"
active_active = false
enable_bgp = false
ip_configuration {
name = "default"
private_ip_address_allocation = "Dynamic"
subnet_id = azurerm_subnet.gateway_subnet.id
public_ip_address_id = azurerm_public_ip.vnet_gateway_public_ip.id
}
}
The ip_configuration
of the Virtual Network Gateway in the previous code configures the Virtual Network Gateway to use the Public IP address that was previously deployed, as well as the GatewaySubnet
subnet within the VNet that was deployed.
The Virtual Network Gateway isn’t configured itself with the Azure ExpressRoute circuit to connect to. For this, an Azure Virtual Network Gateway Connection resource (azurerm_virutal_network_gateway_connection
) needs to be deployed to setup the connection between the Azure ExpressRoute circuit and the Virtual Network Gateway.
The following is the basic code to deploy the Azure Virtual Network Gateway Connection:
# Azure Virtual Network Gateway Connection to Express Route
resource azurerm_virtual_network_gateway_connection "virtual_network_gateway_connection" {
name = "${local.resource_name_prefix}-vgw-con"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
type = "ExpressRoute"
virtual_network_gateway_id = azurerm_virtual_network_gateway.virtual_network_gateway.id
express_route_circuit_id = azurerm_express_route_circuit.express_route.id
}
The Build5Nines: Terraform Quickstart Templates open source project contains a full source code example for deploying Azure ExpressRoute with a Virtual Network Gateway that can be referenced here: https://github.com/Build5Nines/terraform-quickstart-templates/tree/main/microsoft-azure/workloads/azure-express-route-with-vnet-gateway