Managing Azure ExpressRoute with Terraform
Learn how to set up and manage Azure ExpressRoute using Terraform, including circuit and peering configurations
Managing Azure ExpressRoute with Terraform
Azure ExpressRoute provides a private, dedicated, and high-bandwidth connection between your on-premises network and Azure. This guide demonstrates how to set up and manage ExpressRoute using Terraform.
Video Tutorial
Learn more about managing Azure ExpressRoute with Terraform in this comprehensive video tutorial:
Prerequisites
- Azure CLI configured with appropriate permissions
- Terraform installed (version 1.0.0 or later)
- Resource group created
- Understanding of networking concepts
- ExpressRoute service provider
Project Structure
terraform-azure-expressroute/
├── main.tf
├── variables.tf
├── outputs.tf
├── modules/
│ └── expressroute/
│ ├── main.tf
│ ├── variables.tf
│ └── outputs.tf
└── configs/
└── peering.json
ExpressRoute Configuration
Create modules/expressroute/main.tf
:
# ExpressRoute Circuit
resource "azurerm_express_route_circuit" "main" {
name = "${var.project_name}-circuit"
resource_group_name = var.resource_group_name
location = var.location
service_provider_name = "Equinix"
peering_location = "Silicon Valley"
bandwidth_in_mbps = 1000
sku {
tier = "Premium"
family = "MeteredData"
}
allow_classic_operations = false
tags = var.tags
}
# ExpressRoute Circuit Authorization
resource "azurerm_express_route_circuit_authorization" "main" {
name = "${var.project_name}-auth"
express_route_circuit_name = azurerm_express_route_circuit.main.name
resource_group_name = var.resource_group_name
}
# Private Peering
resource "azurerm_express_route_circuit_peering" "private" {
peering_type = "AzurePrivatePeering"
express_route_circuit_name = azurerm_express_route_circuit.main.name
resource_group_name = var.resource_group_name
primary_peer_address_prefix = "192.168.1.0/30"
secondary_peer_address_prefix = "192.168.2.0/30"
vlan_id = 100
shared_key = var.peering_shared_key
peer_asn = 65001
microsoft_peering_config {
advertised_public_prefixes = ["123.0.0.0/24"]
customer_asn = 65001
routing_registry_name = "ARIN"
}
route_filter_id = azurerm_express_route_route_filter.main.id
}
# Microsoft Peering
resource "azurerm_express_route_circuit_peering" "microsoft" {
peering_type = "MicrosoftPeering"
express_route_circuit_name = azurerm_express_route_circuit.main.name
resource_group_name = var.resource_group_name
primary_peer_address_prefix = "192.168.3.0/30"
secondary_peer_address_prefix = "192.168.4.0/30"
vlan_id = 200
shared_key = var.peering_shared_key
peer_asn = 65001
microsoft_peering_config {
advertised_public_prefixes = ["123.0.0.0/24"]
customer_asn = 65001
routing_registry_name = "ARIN"
}
route_filter_id = azurerm_express_route_route_filter.main.id
}
# Route Filter
resource "azurerm_express_route_route_filter" "main" {
name = "${var.project_name}-filter"
resource_group_name = var.resource_group_name
location = var.location
rule {
name = "allow-o365"
access = "Allow"
rule_type = "Community"
communities = ["12076:5010", "12076:5020"]
}
tags = var.tags
}
# ExpressRoute Gateway
resource "azurerm_virtual_network_gateway" "expressroute" {
name = "${var.project_name}-ergw"
location = var.location
resource_group_name = var.resource_group_name
type = "ExpressRoute"
sku = "ErGw2AZ"
ip_configuration {
name = "default"
public_ip_address_id = azurerm_public_ip.expressroute.id
private_ip_address_allocation = "Dynamic"
subnet_id = azurerm_subnet.gateway.id
}
tags = var.tags
}
# ExpressRoute Connection
resource "azurerm_virtual_network_gateway_connection" "expressroute" {
name = "${var.project_name}-connection"
location = var.location
resource_group_name = var.resource_group_name
type = "ExpressRoute"
virtual_network_gateway_id = azurerm_virtual_network_gateway.expressroute.id
express_route_circuit_id = azurerm_express_route_circuit.main.id
routing_weight = 10
enable_bgp = true
tags = var.tags
}
# FastPath
resource "azurerm_express_route_circuit_connection" "fastpath" {
name = "${var.project_name}-fastpath"
peering_id = azurerm_express_route_circuit_peering.private.id
peer_peering_id = azurerm_express_route_circuit_peering.private.id
address_prefix = "192.168.100.0/29"
}
# Global Reach
resource "azurerm_express_route_circuit_connection" "global" {
name = "${var.project_name}-global"
peering_id = azurerm_express_route_circuit_peering.private.id
peer_peering_id = var.peer_circuit_peering_id
address_prefix = "192.168.101.0/29"
}
Network Configuration
- Virtual Network Setup
resource "azurerm_virtual_network" "main" {
name = "${var.project_name}-vnet"
location = var.location
resource_group_name = var.resource_group_name
address_space = ["10.0.0.0/16"]
subnet {
name = "GatewaySubnet"
address_prefix = "10.0.255.0/24"
}
tags = var.tags
}
resource "azurerm_public_ip" "expressroute" {
name = "${var.project_name}-ergw-pip"
location = var.location
resource_group_name = var.resource_group_name
allocation_method = "Static"
sku = "Standard"
zones = ["1", "2", "3"]
tags = var.tags
}
Route Configuration
- Route Table
resource "azurerm_route_table" "main" {
name = "${var.project_name}-rt"
location = var.location
resource_group_name = var.resource_group_name
route {
name = "ToOnPremise"
address_prefix = "192.168.0.0/16"
next_hop_type = "VirtualNetworkGateway"
}
tags = var.tags
}
resource "azurerm_subnet_route_table_association" "main" {
subnet_id = azurerm_subnet.main.id
route_table_id = azurerm_route_table.main.id
}
Monitoring Configuration
- Diagnostic Settings
resource "azurerm_monitor_diagnostic_setting" "expressroute" {
name = "${var.project_name}-diag"
target_resource_id = azurerm_express_route_circuit.main.id
log_analytics_workspace_id = var.log_analytics_workspace_id
log {
category = "PeeringRouteLog"
enabled = true
retention_policy {
enabled = true
days = 30
}
}
metric {
category = "AllMetrics"
enabled = true
retention_policy {
enabled = true
days = 30
}
}
}
resource "azurerm_monitor_metric_alert" "expressroute" {
name = "${var.project_name}-bandwidth-alert"
resource_group_name = var.resource_group_name
scopes = [azurerm_express_route_circuit.main.id]
description = "Alert when bandwidth utilization is high"
criteria {
metric_namespace = "Microsoft.Network/expressRouteCircuits"
metric_name = "BitsInPerSecond"
aggregation = "Average"
operator = "GreaterThan"
threshold = 800000000
}
action {
action_group_id = var.action_group_id
}
}
Best Practices
-
Performance
- Use appropriate SKU
- Enable FastPath
- Configure BGP
- Optimize routing
-
High Availability
- Use zone-redundant gateways
- Configure redundant circuits
- Implement failover
- Monitor connections
-
Security
- Use private peering
- Implement encryption
- Configure authentication
- Monitor traffic
-
Cost Optimization
- Choose appropriate bandwidth
- Monitor usage
- Optimize connections
- Use appropriate tier
Conclusion
You’ve learned how to set up and manage Azure ExpressRoute using Terraform. This setup provides:
- Private connectivity
- High bandwidth
- Global reach
- Reliable performance
Remember to:
- Monitor circuit status
- Review peering settings
- Update route filters
- Maintain connections