Azure VM may fail to activate over ExpressRoute

Customers can advertise a default route (also known as forced tunneling) over their ExpressRoute circuit to force all traffic destined for the internet destined traffic to be routed through their on-premises infrastructure and out their on-premises edge devices. This enables you to leverage your existing on-premises investments such as security appliances or WAN accelerators to manage traffic leaving their Azure virtual networks.

Azure VMs running a Windows guest need connectivity to kms.core.windows.net to activate. Activation requests coming from an Azure VM must have an Azure public IP address as the source IP in order to successfully activate against kms.core.windows.net. As a result of the forced tunneling, activation will fail because the activation request is seen as coming from the customer's on-premises edge instead of from an Azure public IP. SUSE’s update servers use similar logic, so are also susceptible to this problem.

There are two ways to mitigate the activation problem. Customers can mitigate this by enabling public peering for their ExpressRoute circuit. With public peering, both on-premises and Azure VM traffic destined for Azure public services (e.g. Azure Storage, Azure SQL Database) is routed across the ExpressRoute circuit. Without forced tunneling, this traffic hairpins at the Azure side of the ExpressRoute circuit.  With forced tunneling enabled, this traffic hairpins at the customer’s side of the ExpressRoute circuit.

Due to the hairpinning, public peering isn’t ideal for customers who want to inspect all outgoing traffic without having to implement a network virtual appliance in each of their Azure VNETs. Therefore, some customers want a more granular solution. These customers can employ a User Defined Route (UDR) to route activation traffic directly to the Azure activation host IPs rather than through the on-premises infrastructure. This provides the best of both situations and does not change the security risk.

For Azure Resource Manager, it can be implemented as follows:

 # First, we will get the virtual network. In this case, I'm getting virtual network ArmVNet-DM in Resource Group ArmVNet-DM
 $vnet = Get-AzureRmVirtualNetwork -ResourceGroupName "ArmVNet-DM" -Name "ArmVNet-DM"
 # Next, we create a route table and specify that traffic bound to the KMS IP (23.102.135.246) will go directly out
 $RouteTable = New-AzureRmRouteTable -Name "ArmVNet-DM-KmsDirectRoute" -ResourceGroupName "ArmVNet-DM" -Location "centralus"
 Add-AzureRmRouteConfig -Name "DirectRouteToKMS" -AddressPrefix 23.102.135.246/32 -NextHopType Internet -RouteTable $RouteTable
 Set-AzureRmRouteTable -RouteTable $RouteTable
 # Apply KMS direct route table to the subnet (in this case, I will apply it to the subnet named Subnet-1)
 $forcedTunnelVNet = $vnet.Subnets | ? Name -eq "Subnet-1"
 $forcedTunnelVNet.RouteTable = $RouteTable
 Set-AzureRmVirtualNetwork -VirtualNetwork $vnet

For Classic Virtual Networks, it can be implemented as follows:

 # First, we will create a new route table
 New-AzureRouteTable -Name "VNet-DM-KmsRouteGroup" -Label "Route table for KMS" -Location "Central US"
 # Next, get the routetable that was created
 $rt = Get-AzureRouteTable -Name "VNet-DM-KmsRouteTable"
 # Next, create a route
 Set-AzureRoute -RouteTable $rt -RouteName "AzureKMS" -AddressPrefix "23.102.135.246/32" -NextHopType Internet
 # Apply KMS route table to the subnet (in this case, I will apply it to the subnet named Subnet-1)
 Set-AzureSubnetRouteTable -VirtualNetworkName "VNet-DM" -SubnetName "Subnet-1" -RouteTableName "VNet-DM-KmsRouteTable"

If you are using SUSE images, you will want to do something similar. For the sake of brevity, only the commands that create
the specific routes are listed.

Azure Resource Manager:

 Add-AzureRmRouteConfig -Name "DirectRouteToSUSEUpdate" -AddressPrefix 104.47.192.0/21 -NextHopType Internet -RouteTable $RouteTable
 Add-AzureRmRouteConfig -Name "DirectRouteToSUSEUpdate" -AddressPrefix 104.209.96.0/19 -NextHopType Internet -RouteTable $RouteTable
 Add-AzureRmRouteConfig -Name "DirectRouteToSUSEUpdate" -AddressPrefix 104.210.224.0/19 -NextHopType Internet -RouteTable $RouteTable

Classic Virtual Networks:

 Set-AzureRoute -RouteTable $rt -RouteName "DirectRouteToSUSEUpdate" -AddressPrefix "104.47.192.0/21" -NextHopType Internet
 Set-AzureRoute -RouteTable $rt -RouteName "DirectRouteToSUSEUpdate" -AddressPrefix "104.209.96.0/19" -NextHopType Internet
 Set-AzureRoute -RouteTable $rt -RouteName "DirectRouteToSUSEUpdate" -AddressPrefix "104.210.224.0/19" -NextHopType Internet