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 (Premium required). 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 and the customer must send the traffic back over the public peering.  For more information on this see: https://azure.microsoft.com/en-us/documentation/articles/expressroute-faqs/

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.

Note: in the directions below, the IP 23.102.135.246 referenced is for the Azure public cloud regions and corresponds to the DNS name kms.core.windows.net.  For national clouds, look up the relevant IP for the DNS name that corresponds to the appropriate cloud and use that IP instead.  DNS names by national cloud:

  • Azure public cloud regions: kms.core.windows.net
  • Azure China national cloud regions: kms.core.chinacloudapi.cn
  • Azure Germany national cloud regions: kms.core.cloudapi.de
  • Azure US Government national cloud regions: kms.core.usgovcloudapi.net

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.  Instead of specifying 23.102.135.246/32, specify the SUSE update server IP for your region.  The IP addresses for each region is specified here: https://susepubliccloudinfo.suse.com/v1/microsoft/servers/smt.xml.  Note, you may want to specify both the Windows KMS as well as the SUSE update server.

For Azure Resource Manager:

Change:

Add-AzureRmRouteConfig -Name "DirectRouteToKMS" -AddressPrefix 23.102.135.246/32 -NextHopType Internet -RouteTable $RouteTable

To the following (assuming the Virtual Network was in Central US):

Add-AzureRmRouteConfig -Name "DirectRouteToKMS" -AddressPrefix 23.102.135.246/32 -NextHopType Internet -RouteTable $RouteTable
Add-AzureRmRouteConfig -Name "DirectRouteToSUSE1" -AddressPrefix 23.101.123.131/32 -NextHopType Internet -RouteTable $RouteTable
Add-AzureRmRouteConfig -Name "DirectRouteToSUSE2" -AddressPrefix 23.101.127.162/32 -NextHopType Internet -RouteTable $RouteTable

For Classic Virtual Networks:

Change:

Set-AzureRoute -RouteTable $rt -RouteName "AzureKMS" -AddressPrefix "23.102.135.246/32" -NextHopType Internet

To the following (assuming the Virtual Network was in Central US):

Set-AzureRoute -RouteTable $rt -RouteName "AzureKMS" -AddressPrefix "23.102.135.246/32" -NextHopType Internet
Set-AzureRoute -RouteTable $rt -RouteName "SUSEUpdate1" -AddressPrefix "23.101.123.131/32" -NextHopType Internet
Set-AzureRoute -RouteTable $rt -RouteName "SUSEUpdate2" -AddressPrefix "23.101.127.162/32" -NextHopType Internet