Skip to main content

Challenge 23: Virtual WAN routing and NVA integration

Estimated time and cost

60–90 minutes | ~$0.36/h (Virtual WAN Standard + gateways) | Exam weight: 20–25%

Scenario

Contoso has deployed Azure Virtual WAN with a Standard hub and multiple connected spokes (from Challenge 22). Now they need advanced routing: isolating development spoke VNets from production spokes, routing all internet-bound traffic through a centralized Network Virtual Appliance (NVA) for inspection, and controlling which spokes can communicate with each other.

Their requirements:

  • Production spokes (vnet-prod-1, vnet-prod-2) must communicate with each other and shared services
  • Development spokes (vnet-dev-1, vnet-dev-2) must be isolated from production
  • All internet traffic from both environments must route through a centralized firewall/NVA
  • The NVA is deployed as a managed application from the Azure Marketplace within the virtual hub

Exam skills measured

SkillDescription
Configure virtual hub routingCreate custom route tables, static routes, and routing associations
Integrate third-party NVADeploy and route traffic through NVAs in the virtual hub

Architecture overview

Virtual Hub (East US)RT_PRODlabel: prodRT_DEVlabel: devNVA / Azure FirewallRouting intent: 0.0.0.0/0prod-1(RT_PROD)prod-2(RT_PROD)dev-1(RT_DEV)dev-2(RT_DEV)Isolated

Key concepts

Virtual WAN default routing behavior

When a VNet connection is created without explicit routing configuration:

  • It is associated with the defaultRouteTable
  • It propagates routes to the defaultRouteTable
  • All spokes learn each other's routes (full mesh connectivity)

Custom route tables for isolation

To isolate groups of spokes, you create custom route tables and configure:

  • Association: Which route table a connection uses to look up routes (determines where it sends traffic)
  • Propagation: Which route tables learn the connection's routes (determines who can reach it)

Routing intent and routing policies

Routing intent simplifies routing configuration by allowing you to define:

  • Internet traffic policy: Routes 0.0.0.0/0 to a next-hop resource (Azure Firewall or NVA)
  • Private traffic policy: Routes RFC 1918 prefixes (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16) to a next-hop resource

When routing intent is enabled, it takes precedence over individual static routes in the defaultRouteTable.


Task 1: Understand default routing

Before making changes, examine the default routing configuration to understand baseline behavior.

Azure CLI

# Define variables (assumes resources from Challenge 22 exist)
RG="rg-vwan-challenge22"
HUB_NAME="hub-eastus"

# List route tables in the hub
az network vhub route-table list \
--resource-group $RG \
--vhub-name $HUB_NAME \
--output table

# Show the default route table
az network vhub route-table show \
--name "defaultRouteTable" \
--resource-group $RG \
--vhub-name $HUB_NAME

# Check which route table a connection is associated with
az network vhub connection show \
--name "conn-spoke1" \
--resource-group $RG \
--vhub-name $HUB_NAME \
--query "routingConfiguration"

Azure PowerShell

$RG = "rg-vwan-challenge22"
$HubName = "hub-eastus"

# List route tables
Get-AzVHubRouteTable -ResourceGroupName $RG -VirtualHubName $HubName

# Get default route table details
Get-AzVHubRouteTable `
-ResourceGroupName $RG `
-VirtualHubName $HubName `
-Name "defaultRouteTable"

# Check connection routing configuration
Get-AzVirtualHubVnetConnection `
-ResourceGroupName $RG `
-VirtualHubName $HubName `
-Name "conn-spoke1" |
Select-Object -ExpandProperty RoutingConfiguration

Task 2: Create custom route tables for isolation

Create separate route tables for production and development workloads. Labels allow you to reference groups of route tables during propagation configuration.

Azure CLI

# Create route table for production spokes
az network vhub route-table create \
--name "RT_PROD" \
--resource-group $RG \
--vhub-name $HUB_NAME \
--labels "prod"

# Create route table for development spokes
az network vhub route-table create \
--name "RT_DEV" \
--resource-group $RG \
--vhub-name $HUB_NAME \
--labels "dev"

# Verify route tables were created
az network vhub route-table list \
--resource-group $RG \
--vhub-name $HUB_NAME \
--output table

Azure PowerShell

# Create route table for production
New-AzVHubRouteTable `
-ResourceGroupName $RG `
-VirtualHubName $HubName `
-Name "RT_PROD" `
-Label @("prod")

# Create route table for development
New-AzVHubRouteTable `
-ResourceGroupName $RG `
-VirtualHubName $HubName `
-Name "RT_DEV" `
-Label @("dev")

Task 3: Associate spoke connections with custom route tables

Update existing connections or create new ones with explicit routing configuration. Production spokes associate with RT_PROD and propagate only to RT_PROD. Development spokes associate with RT_DEV and propagate only to RT_DEV.

Azure CLI

# Create production spoke VNets
az network vnet create \
--name "vnet-prod-1" \
--resource-group $RG \
--location "eastus" \
--address-prefixes "10.30.0.0/16" \
--subnet-name "workload" \
--subnet-prefixes "10.30.1.0/24"

az network vnet create \
--name "vnet-prod-2" \
--resource-group $RG \
--location "eastus" \
--address-prefixes "10.40.0.0/16" \
--subnet-name "workload" \
--subnet-prefixes "10.40.1.0/24"

# Create dev spoke VNets
az network vnet create \
--name "vnet-dev-1" \
--resource-group $RG \
--location "eastus" \
--address-prefixes "10.50.0.0/16" \
--subnet-name "workload" \
--subnet-prefixes "10.50.1.0/24"

# Get the route table resource IDs
RT_PROD_ID=$(az network vhub route-table show \
--name "RT_PROD" \
--resource-group $RG \
--vhub-name $HUB_NAME \
--query "id" -o tsv)

RT_DEV_ID=$(az network vhub route-table show \
--name "RT_DEV" \
--resource-group $RG \
--vhub-name $HUB_NAME \
--query "id" -o tsv)

# Connect production spoke with routing configuration
az network vhub connection create \
--name "conn-prod-1" \
--resource-group $RG \
--vhub-name $HUB_NAME \
--remote-vnet "vnet-prod-1" \
--associated-route-table $RT_PROD_ID \
--propagated-route-tables $RT_PROD_ID \
--labels "prod"

az network vhub connection create \
--name "conn-prod-2" \
--resource-group $RG \
--vhub-name $HUB_NAME \
--remote-vnet "vnet-prod-2" \
--associated-route-table $RT_PROD_ID \
--propagated-route-tables $RT_PROD_ID \
--labels "prod"

# Connect development spoke with routing configuration
az network vhub connection create \
--name "conn-dev-1" \
--resource-group $RG \
--vhub-name $HUB_NAME \
--remote-vnet "vnet-dev-1" \
--associated-route-table $RT_DEV_ID \
--propagated-route-tables $RT_DEV_ID \
--labels "dev"

Azure PowerShell

# Create production spoke VNet
$vnetProd1 = New-AzVirtualNetwork `
-ResourceGroupName $RG `
-Name "vnet-prod-1" `
-Location "eastus" `
-AddressPrefix "10.30.0.0/16"

Add-AzVirtualNetworkSubnetConfig `
-Name "workload" `
-VirtualNetwork $vnetProd1 `
-AddressPrefix "10.30.1.0/24"
$vnetProd1 | Set-AzVirtualNetwork

# Get route table objects
$rtProd = Get-AzVHubRouteTable `
-ResourceGroupName $RG `
-VirtualHubName $HubName `
-Name "RT_PROD"

$rtDev = Get-AzVHubRouteTable `
-ResourceGroupName $RG `
-VirtualHubName $HubName `
-Name "RT_DEV"

# Create routing configuration for production
$routingConfig = New-AzRoutingConfiguration `
-AssociatedRouteTable $rtProd.Id `
-PropagatedRouteTable @($rtProd.Id) `
-Label @("prod")

# Connect with routing config
$vnetRef = Get-AzVirtualNetwork -ResourceGroupName $RG -Name "vnet-prod-1"
New-AzVirtualHubVnetConnection `
-ResourceGroupName $RG `
-VirtualHubName $HubName `
-Name "conn-prod-1" `
-RemoteVirtualNetwork $vnetRef `
-RoutingConfiguration $routingConfig

Task 4: Add static routes to a hub route table

Add a static route to force internet-bound traffic (0.0.0.0/0) through an NVA or Azure Firewall. The next hop is specified as a resource ID.

Azure CLI

# Add a default route pointing to an NVA/Firewall resource
# Replace <firewall-resource-id> with actual Azure Firewall or NVA resource ID
FIREWALL_ID="/subscriptions/<sub-id>/resourceGroups/$RG/providers/Microsoft.Network/azureFirewalls/fw-hub-eastus"

az network vhub route-table route add \
--name "RT_PROD" \
--resource-group $RG \
--vhub-name $HUB_NAME \
--route-name "default-to-firewall" \
--destination-type CIDR \
--destinations "0.0.0.0/0" \
--next-hop-type ResourceId \
--next-hop $FIREWALL_ID

# Verify routes in the table
az network vhub route-table route list \
--name "RT_PROD" \
--resource-group $RG \
--vhub-name $HUB_NAME

Azure PowerShell

# Define the route
$route = New-AzVHubRoute `
-Name "default-to-firewall" `
-DestinationType "CIDR" `
-Destination @("0.0.0.0/0") `
-NextHopType "ResourceId" `
-NextHop $firewallId

# Update the route table with the new route
Update-AzVHubRouteTable `
-ResourceGroupName $RG `
-VirtualHubName $HubName `
-Name "RT_PROD" `
-Route @($route)
![Challenge 23 - Network Topology](/img/az-700/challenge-23-topology.svg)


### Azure PowerShell

```powershell
# Create routing policies
$internetPolicy = New-AzRoutingPolicy `
-Name "InternetTraffic" `
-Destination @("Internet") `
-NextHop $firewallId

$privatePolicy = New-AzRoutingPolicy `
-Name "PrivateTrafficPolicy" `
-Destination @("PrivateTraffic") `
-NextHop $firewallId

# Create routing intent
New-AzRoutingIntent `
-ResourceGroupName $RG `
-VirtualHubName $HubName `
-Name "RoutingIntent-EastUS" `
-RoutingPolicy @($internetPolicy, $privatePolicy)
Routing intent constraints

When routing intent is enabled on a hub:

  • All connections to that hub will have their next hop for internet and/or private traffic set to the specified resource (Azure Firewall or NVA)
  • You cannot configure static routes in the defaultRouteTable that conflict with routing intent
  • Routing intent applies to all new and existing connections in the hub
  • You must use a supported next-hop type: Azure Firewall or a managed NVA from the Marketplace

Task 6: NVA deployment in virtual hub (conceptual)

Third-party NVAs can be deployed directly into the virtual hub from the Azure Marketplace. This is different from deploying an NVA in a spoke VNet -- hub-integrated NVAs participate directly in the hub routing infrastructure.

Supported NVA partners (examples)

VendorProductUse case
Barracuda NetworksCloudGen WANSD-WAN, firewall
CiscoViptela SD-WANSD-WAN
FortinetFortiGateNext-gen firewall
Palo Alto NetworksCloud NGFWNext-gen firewall
Versa NetworksSD-WANSD-WAN

Deployment steps (portal-based)

NVA-in-hub deployment is managed through the Azure Marketplace and the partner's management plane:

  1. Navigate to the virtual hub in the Azure Portal
  2. Select Third-party security providers or Network Virtual Appliance
  3. Choose the NVA vendor from the Marketplace
  4. Select infrastructure units (analogous to scale units for throughput)
  5. Complete the vendor-specific configuration
  6. The NVA deploys as a managed application within the hub

Using NVA as next-hop in routing

Once deployed, the NVA resource ID can be used as a next-hop in route tables and routing intent:

# Reference the NVA in a static route
NVA_ID="/subscriptions/<sub-id>/resourceGroups/<managed-rg>/providers/Microsoft.Network/networkVirtualAppliances/nva-hub-eastus"

az network vhub route-table route add \
--name "RT_PROD" \
--resource-group $RG \
--vhub-name $HUB_NAME \
--route-name "inspect-traffic" \
--destination-type CIDR \
--destinations "10.0.0.0/8" \
--next-hop-type ResourceId \
--next-hop $NVA_ID

Break & fix

Scenario 1: Spoke in wrong route table

Symptom: A production VM (in vnet-prod-1) cannot reach shared services that are in the defaultRouteTable, but can reach other production spokes.

Root cause: The production connection is associated with RT_PROD and only propagates to RT_PROD. Shared services VNets propagate only to defaultRouteTable. There is no route exchange between RT_PROD and defaultRouteTable.

Diagnosis:

# Check what routes RT_PROD contains
az network vhub route-table route list \
--name "RT_PROD" \
--resource-group $RG \
--vhub-name $HUB_NAME

# Check shared services connection propagation
az network vhub connection show \
--name "conn-shared-services" \
--resource-group $RG \
--vhub-name $HUB_NAME \
--query "routingConfiguration.propagatedRouteTables"

Fix: Ensure the shared services VNet propagates to both defaultRouteTable and RT_PROD:

# Update shared services to propagate to both route tables
DEFAULT_RT_ID=$(az network vhub route-table show \
--name "defaultRouteTable" \
--resource-group $RG \
--vhub-name $HUB_NAME \
--query "id" -o tsv)

az network vhub connection update \
--name "conn-shared-services" \
--resource-group $RG \
--vhub-name $HUB_NAME \
--propagated-route-tables $DEFAULT_RT_ID $RT_PROD_ID $RT_DEV_ID \
--labels "default" "prod" "dev"

Scenario 2: Routing intent conflicts with static routes

Symptom: After enabling routing intent, manually configured static routes in the defaultRouteTable stop working. Traffic no longer follows the expected path.

Root cause: Routing intent takes precedence over static routes in the defaultRouteTable. When routing intent is configured for private traffic, it programs 10.0.0.0/8, 172.16.0.0/12, and 192.168.0.0/16 routes automatically. Manual 0.0.0.0/0 static routes become redundant.

Diagnosis:

# Check routing intent status
az network vhub routing-intent show \
--name "RoutingIntent-EastUS" \
--resource-group $RG \
--vhub $HUB_NAME

# Check effective routes to see what is programmed
az network vhub get-effective-routes \
--name $HUB_NAME \
--resource-group $RG

Fix: Remove conflicting static routes from the defaultRouteTable. Use routing intent as the sole mechanism for traffic steering:

# Remove the conflicting static route (by index, starting at 1)
az network vhub route-table route remove \
--name "defaultRouteTable" \
--resource-group $RG \
--vhub-name $HUB_NAME \
--index 1

Scenario 3: NVA next-hop unreachable

Symptom: Traffic destined for the NVA is dropped. The route table shows the correct next-hop but connectivity fails.

Root cause: The NVA managed application has not completed provisioning or the NVA infrastructure units are set to 0 (effectively disabled).

Diagnosis:

# Check the NVA provisioning state
az network virtual-appliance show \
--name "nva-hub-eastus" \
--resource-group $RG \
--query "{provisioningState:provisioningState, deploymentType:deploymentType}"

Fix: Verify the NVA is in a Succeeded state and has at least 2 infrastructure units configured. If the NVA is unhealthy, check the vendor management portal for appliance-level issues.


Cleanup

# If you created new resources beyond Challenge 22, delete them
# Or delete the entire resource group
az group delete --name $RG --yes --no-wait
Remove-AzResourceGroup -Name "rg-vwan-challenge22" -Force -AsJob

Knowledge check

1. In Virtual WAN, what does 'associating' a VNet connection with a custom route table accomplish?

2. Contoso wants development spokes to reach each other but not production spokes. Production spokes should reach each other but not dev. Both environments need internet access through a firewall. Which configuration achieves this?

3. What are valid destinations for a routing policy within a routing intent configuration?

4. After enabling routing intent with a private traffic policy, which of the following is true about the defaultRouteTable?

5. Which next-hop types are supported for routing intent policies in a Virtual WAN hub?