Managing Azure Virtual WAN with Terraform

Learn how to set up and manage Azure Virtual WAN using Terraform, including hubs, connections, and routing

Managing Azure Virtual WAN with Terraform

Azure Virtual WAN is a networking service that provides optimized and automated branch-to-branch connectivity through Azure. This guide demonstrates how to set up and manage Virtual WAN using Terraform.

Video Tutorial

Learn more about managing Azure Virtual WAN 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

Project Structure

terraform-azure-virtualwan/
├── main.tf
├── variables.tf
├── outputs.tf
├── modules/
│   └── virtualwan/
│       ├── main.tf
│       ├── variables.tf
│       └── outputs.tf
└── configs/
    └── routing.json

Virtual WAN Configuration

Create modules/virtualwan/main.tf:

# Virtual WAN
resource "azurerm_virtual_wan" "main" {
  name                = "${var.project_name}-vwan"
  resource_group_name = var.resource_group_name
  location            = var.location
  
  type                       = "Standard"
  disable_vpn_encryption     = false
  allow_branch_to_branch_traffic = true
  office365_local_breakout_category = "OptimizeAndAllow"

  tags = var.tags
}

# Virtual Hub
resource "azurerm_virtual_hub" "main" {
  name                = "${var.project_name}-hub"
  resource_group_name = var.resource_group_name
  location            = var.location
  virtual_wan_id      = azurerm_virtual_wan.main.id
  address_prefix      = "10.0.0.0/24"
  sku                 = "Standard"

  route {
    address_prefixes    = ["10.0.1.0/24"]
    next_hop_ip_address = "10.0.0.4"
  }

  tags = var.tags
}

# VPN Gateway
resource "azurerm_vpn_gateway" "main" {
  name                = "${var.project_name}-vpngw"
  location            = var.location
  resource_group_name = var.resource_group_name
  virtual_hub_id      = azurerm_virtual_hub.main.id
  scale_unit         = 2

  bgp_settings {
    asn         = 65515
    peer_weight = 0
  }

  tags = var.tags
}

# ExpressRoute Gateway
resource "azurerm_express_route_gateway" "main" {
  name                = "${var.project_name}-ergw"
  resource_group_name = var.resource_group_name
  location            = var.location
  virtual_hub_id      = azurerm_virtual_hub.main.id
  scale_units        = 2

  tags = var.tags
}

# Virtual Network Connection
resource "azurerm_virtual_hub_connection" "main" {
  name                      = "${var.project_name}-connection"
  virtual_hub_id            = azurerm_virtual_hub.main.id
  remote_virtual_network_id = azurerm_virtual_network.spoke.id

  routing {
    associated_route_table_id = azurerm_virtual_hub_route_table.main.id
    propagated_route_table {
      labels = ["default"]
      route_table_ids = [azurerm_virtual_hub_route_table.main.id]
    }
    static_vnet_route {
      name                = "default"
      address_prefixes    = ["10.0.0.0/16"]
      next_hop_ip_address = "10.0.0.4"
    }
  }

  internet_security_enabled = true
}

# Route Table
resource "azurerm_virtual_hub_route_table" "main" {
  name           = "${var.project_name}-rt"
  virtual_hub_id = azurerm_virtual_hub.main.id
  labels         = ["default"]

  route {
    name              = "default"
    destinations_type = "CIDR"
    destinations      = ["0.0.0.0/0"]
    next_hop_type     = "ResourceId"
    next_hop          = azurerm_firewall.main.id
  }
}

# Firewall
resource "azurerm_firewall" "main" {
  name                = "${var.project_name}-fw"
  location            = var.location
  resource_group_name = var.resource_group_name
  sku_name            = "AZFW_Hub"
  sku_tier            = "Premium"

  virtual_hub {
    virtual_hub_id  = azurerm_virtual_hub.main.id
    public_ip_count = 1
  }

  firewall_policy_id = azurerm_firewall_policy.main.id

  tags = var.tags
}

# Firewall Policy
resource "azurerm_firewall_policy" "main" {
  name                = "${var.project_name}-policy"
  resource_group_name = var.resource_group_name
  location            = var.location

  sku                      = "Premium"
  threat_intelligence_mode = "Alert"

  dns {
    proxy_enabled = true
    servers       = ["168.63.129.16"]
  }

  insights {
    enabled                            = true
    default_log_analytics_workspace_id = var.log_analytics_workspace_id
    retention_in_days                  = 30
  }

  intrusion_detection {
    mode = "Alert"
  }

  tags = var.tags
}

# Secure Hub
resource "azurerm_virtual_hub_security_partner_provider" "main" {
  name                   = "${var.project_name}-security"
  resource_group_name    = var.resource_group_name
  location               = var.location
  virtual_hub_id         = azurerm_virtual_hub.main.id
  security_provider_name = "ZScaler"

  tags = var.tags
}

# P2S VPN Gateway
resource "azurerm_point_to_site_vpn_gateway" "main" {
  name                = "${var.project_name}-p2s"
  location            = var.location
  resource_group_name = var.resource_group_name
  virtual_hub_id      = azurerm_virtual_hub.main.id
  scale_unit         = 2
  
  vpn_server_configuration_id = azurerm_vpn_server_configuration.main.id

  connection_configuration {
    name = "connection-config"

    vpn_client_address_pool {
      address_prefixes = ["172.16.0.0/24"]
    }
  }

  tags = var.tags
}

# VPN Server Configuration
resource "azurerm_vpn_server_configuration" "main" {
  name                     = "${var.project_name}-vpn-config"
  resource_group_name      = var.resource_group_name
  location                 = var.location
  vpn_authentication_types = ["AAD"]

  azure_active_directory_authentication {
    audience = "41b23e61-6c1e-4545-b367-cd054e0ed4b4"
    issuer   = "https://sts.windows.net/${data.azurerm_client_config.current.tenant_id}/"
    tenant   = "https://login.microsoftonline.com/${data.azurerm_client_config.current.tenant_id}"
  }
}

Monitoring Configuration

  1. Diagnostic Settings
resource "azurerm_monitor_diagnostic_setting" "virtualwan" {
  name                       = "${var.project_name}-diag"
  target_resource_id        = azurerm_virtual_wan.main.id
  log_analytics_workspace_id = var.log_analytics_workspace_id

  log {
    category = "AllLogs"
    enabled  = true

    retention_policy {
      enabled = true
      days    = 30
    }
  }

  metric {
    category = "AllMetrics"
    enabled  = true

    retention_policy {
      enabled = true
      days    = 30
    }
  }
}

# Virtual WAN Alerts
resource "azurerm_monitor_metric_alert" "vpn_bandwidth" {
  name                = "${var.project_name}-vpn-bandwidth-alert"
  resource_group_name = var.resource_group_name
  scopes              = [azurerm_vpn_gateway.main.id]
  description         = "Alert when VPN bandwidth is high"

  criteria {
    metric_namespace = "Microsoft.Network/vpnGateways"
    metric_name      = "AverageBandwidth"
    aggregation      = "Average"
    operator         = "GreaterThan"
    threshold        = 800
  }

  action {
    action_group_id = var.action_group_id
  }
}

resource "azurerm_monitor_metric_alert" "er_bandwidth" {
  name                = "${var.project_name}-er-bandwidth-alert"
  resource_group_name = var.resource_group_name
  scopes              = [azurerm_express_route_gateway.main.id]
  description         = "Alert when ExpressRoute bandwidth is high"

  criteria {
    metric_namespace = "Microsoft.Network/expressRouteGateways"
    metric_name      = "ErGatewayConnectionBitsInPerSecond"
    aggregation      = "Average"
    operator         = "GreaterThan"
    threshold        = 800000000
  }

  action {
    action_group_id = var.action_group_id
  }
}

Best Practices

  1. Architecture

    • Plan hub locations
    • Size appropriately
    • Configure routing
    • Enable security
  2. Performance

    • Use Standard SKU
    • Monitor bandwidth
    • Optimize routing
    • Scale resources
  3. Security

    • Enable Firewall
    • Configure policies
    • Monitor traffic
    • Implement logging
  4. Cost Optimization

    • Choose right SKU
    • Monitor usage
    • Optimize connections
    • Review metrics

Conclusion

You’ve learned how to set up and manage Azure Virtual WAN using Terraform. This setup provides:

  • Global connectivity
  • Branch networking
  • Security services
  • Optimized routing

Remember to:

  • Monitor performance
  • Review security
  • Update configurations
  • Maintain connections