As you might know, Azure Bastion enables management connectivity to virtual machines without having to assign them public IP addresses, and without having to maintain jump hosts in your Virtual Network.
Up to recently, the virtual machines needed to be immediately peered to the VNet where Azure Bastion was deployed, but with IP-based connections Azure Bastion now supports new topologies, like connecting to on-premises systems or to VMs that are not directly connected. This feature also allows for the integration of Azure Bastion into Virtual WAN networks.
Two Small Things
There are two details about Azure Bastion that you need to know to avoid nasty surprises. The first one is that you should not override the default route (
0.0.0.0/0) of the Azure Bastion subnet going to Internet as next hop, because otherwise you will break public connectivity to the Azure Bastion. This public connectivity is not only used by clients to connect to Azure Bastion over the Internet, but by Microsoft as well to manage the service.
The second important piece of information is that at the time of this writing you cannot attach a route table to the subnet where Azure Bastion is deployed (originally called
AzureBastionSubnet). If you try to do so you will get an error message, as this example using the Azure CLI shows:
❯ az network vnet subnet update -n AzureBastionSubnet --vnet-name bastionVNet -g $rg --route-table bastionrt (RouteTableCannotBeAttachedForAzureBastionSubnet) Route Table bastionrt cannot be attached to Azure Bastion Subnet AzureBastionSubnet. Code: RouteTableCannotBeAttachedForAzureBastionSubnet Message: Route Table bastionrt cannot be attached to Azure Bastion Subnet AzureBastionSubnet.
Virtual WAN environment
In my lab I have a Virtual WAN setup with 3 VNet connections: one for Azure Bastion, and two other ones with virtual machines:
Spoiler alert: the fact that Internet traffic is not secured in the bastion VNet is important, but more to this later. The virtual machines in the workload VNets have no public IP addresses allocated:
❯ az vm list-ip-addresses -g $rg -o table VirtualMachine PublicIPAddresses PrivateIPAddresses ---------------- ------------------- -------------------- testvm2 10.11.1.4 testvm 10.12.1.4
So when a user connects to Azure Bastion, it will set another connection to the target virtual machine over the Virtual WAN Hub:
I will use Azure Bastion’s tunneling functionality to connect from my shell:
❯ vm_id=$(az vm show -n testvm -g $rg --query id -o tsv) ❯ az network bastion tunnel -n mybastion -g $rg --target-resource-id $vm_id --resource-port 22 --port 50001 &  12521 ❯ Command group 'network bastion' is in preview and under development. Reference and support levels: https://aka.ms/CLI_refstatus Opening tunnel on port: 50001 Tunnel is ready, connect on port 50001 ❯ ssh localhost -p 50001 Welcome to Ubuntu 18.04.6 LTS (GNU/Linux 5.4.0-1090-azure x86_64) ... jose@testvm:~$
The previous commands are fairly easy to understand:
- First I get the ARM ID of the VM I want to connect to into a bash variable
- As second step I open a TCP tunnel between my machine and port 22 of the target VM, identified by that ARM ID I got in step 1. I am using TCP port 50001 to expose that tunnel in my local machine
- Lastly, I can just use that tunnel with my SSH client, connecting to localhost and port 50001
Why no Internet Security in the Bastion VNet connection?
A Virtual WAN secured hub configured for Internet and private traffic security will inject certain routes into the NICs in the VNets connected to it. We can verify these routes in one of our virtual machines:
❯ az network nic show-effective-route-table -n testvmVMNic -g $rg -o table Source State Address Prefix Next Hop Type Next Hop IP --------------------- ------- ---------------- --------------------- ------------- Default Active 10.12.0.0/16 VnetLocal Default Active 10.0.0.0/16 VNetPeering VirtualNetworkGateway Active 192.168.0.0/16 VirtualNetworkGateway 10.0.64.4 VirtualNetworkGateway Active 0.0.0.0/0 VirtualNetworkGateway 10.0.64.4 VirtualNetworkGateway Active 10.0.0.0/8 VirtualNetworkGateway 10.0.64.4 VirtualNetworkGateway Active 172.16.0.0/12 VirtualNetworkGateway 10.0.64.4
Hence, unless we do anything about it, the Azure Bastion is going to receive the same routes, including the 0.0.0.0/0 that as we discussed earlier would break Internet connectivity and the control plane. No problem, we can associate a route table with a route for 0.0.0.0/0 and next hop Internet to the AzureBastionSubnet. Oh wait, we said earlier that is not supported!
Luckily Virtual WAN VNet connections offer us a knob that can be used to prevent the advertisement of a 0.0.0.0/0 route to a VNet, and that is what Firewall Manager calls “Remove Internet Traffic Security”. If you configured your Firewall Manager as the picture at the beginning of this post, and you went back to the VNet connection configuration, you would see this:
Note that this setting affects to the whole VNet where the Azure Bastion is deployed, hence I would personally recommend having the VNet dedicated to Azure Bastion without any other workload, so that you don’t inadvertently bypass the secured hub for production workloads.
What about traditional Hub and Spoke?
In traditional hub and spoke setups (not using Virtual WAN) similar concepts apply: since you cannot use route tables in the AzureBastionSubnet, you need to inject routes in a different way. That way is the Azure Route Server.
In a traditional hub and spoke deployment though the use case would be different than in Virtual WAN: you would probably have Azure Bastion in the hub VNet, but you might want to firewall the flows between the Azure Bastion and the target VMs, like the following picture shows:
Unfortunately, that one would be difficult to achieve because Azure Route Server cannot override the routes learnt via VNet peering. Hence, if you wanted to filter flows between Bastion and the target VM, you might want to revert to a topology similar to the one we saw earlier for Virtual WAN (note however that Azure Route Server doesn’t have a mechanism to filter out 0.0.0.0/0 advertisements for specific VNets, as Virtual WAN does):
In these diagrams I am using the icon of Azure Firewall, but since Azure Firewall doesn’t speak BGP and hence cannot interact with Azure Route Server, that would rather be a Network Virtual Appliance (unless you are using some trick like the one I describe in this blog post).
Long story short
Azure Bastion IP-based connections open a brand new collection of designs. The thing to remember here is that no route tables are supported in the AzureBastionSubnet (at this time), hence any route that you want to inject needs to be advertised with either Virtual WAN or Azure Route Server
2 thoughts on “Azure Bastion routing in Virtual WAN”
Thanks for the great description! Think that will be useful in many situations.
Today I tested another alternative which seems to work. Would like to get an opinion on that, if possible.
Let’s assume we have a secured virtual WAN hub with Azure Firewall. Two spokes are connected to the hub, all inter-vnet traffic and internet traffic routed via the firewall.
For the bastion, I created a /26 virtual network, created a /26 AzureBastionSubnet and peered this virtual network directly to the two spoke virtual networks. Each spoke than has two peerings, one to the vWan hub, one to the central AzBastion Vnet.
I like it because you can connect directly on the blade of the VMs, no copy & pase of the vm ip-address necessary.
It also seems secure, as traffic cannot traverse two peering connections (i.e. from spoke A to Bastion to spoke B).
Two downsides might be that on-premises destinations cannot be reached with that bastion, and you end up with additional peerings (probably challenging for very large environments).
What do you think?
I like that setup as well, I think it is very clean. Plus it is easy to configure with AVNM (preview today)