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.

Deploy Azure ExpressRoute via Terraform
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
}
Error: Provider Status shows “Not provisioned”
The VNet Gateway Connection will show an error if the Azure Express Route Circuit “Provider Status” is in a “Not provisioned” state. You will need to wait for the ExpressRoute Provider to finish setting things up before the Azure VNet Gateway Connection resource can be provisioned.
Note, when this “Not Provisioned” error occurs, the azurerm Terraform Provider may also return the following message for the virtual_network_gateway_connection Azure resource:
Error: ID was missing the virtualNetworkGateways element
Once the ExpressRoute provider has completed their setup and the provisioning status is updated, the error should resolve itself, allowing you to proceed with the Azure VNet Gateway Connection resource provisioning.
Build5Nines Terraform Quickstart Templates: The
Build5Nines/terraform-quickstart-templatesGitHub project contains a full code example for deploying Azure ExpressRoute with a Virtual Network Gateway using Terraform, as well as other Terraform examples.
Original Article Source: Terraform: Deploy Azure ExpressRoute Circuit with VNet Gateway written by Chris Pietschmann (If you're reading this somewhere other than Build5Nines.com, it was republished without permission.)
Microsoft Azure Regions: Interactive Map of Global Datacenters
Create Azure Architecture Diagrams with Microsoft Visio
Unlock GitHub Copilot’s Full Potential: Why Every Repo Needs an AGENTS.md File
Azure Network Security Best Practices to Protect Your Cloud Infrastructure
New Book: Build and Deploy Apps using Azure Developer CLI by Chris Pietschmann



