Azure Bastion is a service which acts as a managed RDP or SSH host, allowing you to use a web browser securely to connect to a virtual machine, even when that virtual machine does not have a public IP address. If you’re new to Azure networking, it may feel a little complicated, but let’s see how to configure and use Bastion.
Requirements and Configuration
In order to use Azure Bastion to connect to a virtual machine, we first need a virtual machine. So let’s create one.
Create a Virtual Machine
In case you’re not familiar with the concept of spot instances, stay tuned—I’ll have another blog post on it and how they can save you a lot of money in certain circumstances.
By default, Windows VMs open up port 3389 (for RDP) and Linux VMs open up port 22 (for SSH). The whole point of Azure Bastion is to be able to access this virtual machine without having these ports open to the broad, nasty world.
After filling out these details, I popped over to the Disks menu.
And finally, Networking:
This menu is where the magic begins. We are creating a new virtual network here. An extremely crude way of putting it is that a virtual network allows you to connect a set of resources together, as though they were all sitting behind the same router. Different Azure resources—like Virtual Machines, App Services, SQL databases, and more—can communicate with one another without needing to go over the public internet.
Inside a virtual network, we have a subnet, which gives us the allowable set of IP addresses. With IPv4 (long live IPv4), we have 32 bits that we could edit. By setting the Classless Interdomain-Routing (CIDR) scheme to
10.0.0.0/24, we are saying that we want to affix the first 24 bits of the IP address:
10.0.0, and the last 8 bits of the address are flexible. Given that we have 8 bits left, we have 2^8 possible IP addresses, meaning that our IP range goes from
10.0.0.255 for the default subnet.
At this point, you can create the VM and let it do its thing.
The Azure Bastion Subnet
What Azure Bastion needs is an additional subnet associated with our virtual network. Importantly, we only need one Bastion subnet per virtual network and it must be called
AzureBastionSubnet with a minimum of a
/26 CIDR prefix. A
/26 means that we affix two bits and only have 2^6 or 64 IP addresses available. If we create a subnet of
10.0.1.0/26, that would mean that our IP range would go from
10.0.1.63. You can, of course, make this range larger. Suppose you have a fairly large department, with hundreds of employees accessing hundreds of virtual machines on a single virtual network. Azure Bastion would still work fine in this case, so long as your subnet supports that many concurrent IP addresses.
Anyhow, let’s create a new subnet. To do that, I need to navigate to my virtual network, which I can do from the deployment screen.
On the virtual network, I can select the Subnets option from the Settings menu. Then, selecting + Subnet will allow me to create a new subnet.
By the way, you may notice that I said earlier that there’d be 256 IP addresses we could use, but Azure only lets us use 251 (remember that we’re using one already for the VM). The reason for this is that certain IP addresses (especially .0 and .255) have historically been off-limits because they’re useful for management and routing. Then, Azure retains a few more IP addresses for its monitoring and administrative services. What I’d say is, be willing to over-provision subnet ranges. You aren’t paying for hypothetical IP space used and you get the entire range from
10.255.255.255 to yourself—that’s because
10.* is called a Class A private IP range. And if you somehow manage to have approximately 250 * 250 * 250 ~ 15.6 million devices in your virtual network? Create a new virtual network to get a new 15.6 or so million IP addresses, and then give yourself a pat on the back for having an obscenely high Azure bill.
Remember that the subnet must have the name
AzureBastionSubnet. I don’t care if your company has subnet naming policies—it’s a requirement for the service. Now let’s save that puppy and see what we can do.
Connecting to a VM via Bastion
Now let’s hop on over to the Azure VM and, from the Connect menu, select Bastion from the list.
Now I need to use Bastion.
We can see that so far, we’ve successfully accomplished steps 1 and 2. Now it’s time to
pay finish configuring. Let’s do some basic configuration:
Okay, the biggest money-related topics on this page are the Tier and Instance count. There are two tiers for Azure Bastion: Basic and Standard. The big difference between the two is that the Standard tier will allow you to scale the number of instances, letting you have anywhere from 2-50 instances. Each instance is a separate Azure-hosted VM, which is good for approximately 10-12 concurrent RDP/SSH sessions. This means that you’ll max out at about 500 or so concurrent connections via Bastion in a single virtual network. Plan ahead if you have thousands of employees who all need to use Bastion for connections.
As far as pricing goes, Bastion is $0.19 per hour for the Basic tier and $0.29 per scale unit per hour. If you’re using the Standard tier, this 29 cents per hour covers 2 instances. Then, an additional instances (also known as scale units, because it wouldn’t be an Azure service without multiple names for the same thing) cost you $0.14 per hour. By my math, that’s $7.01 per hour if you’re maxing it out, or a healthy $5117.30 per month. But wait, there’s more! You’re also charged based on outbound data transfer, at approximately 8.5 cents per gigabyte. And it doesn’t look like there are any reservation discounts, so keep that in mind. Also note that you don’t need to create one Bastion per VM, just one per vNet. This means that if you have 40 or 50 VMs in a virtual network (because they’re all related in some way), a single Bastion can cover it. And frankly, most organizations can get away with Basic tier or Standard with the minimum of 2 instances for most virtual networks, as that will give you between 10-20 simultaneous connections. If you think about a slew of VMs that sysadmins manage, you probably don’t have more than a few sysadmins working on machines at a time. It’ll be fine…
Once you’re done doing the math, click the button and let’s go. Creating a Bastion will take a couple of minutes, so it’s time for a cloud-enforced coffee break.
Now it’s time to connect! I have an SSH key to my Linux VM that I saved locally and am ready to connect as me.
Once I’ve connected, I’m now in my Ubuntu VM, using a web browser as my terminal.
By the way, the little chevron blocking my Ubuntu banner? Click that and you can copy and paste text securely.
I hope I was able to show you just how easy it is to set up Azure Bastion. Using this service means that you won’t need to expose administrative ports on your VMs to the public internet, making them much more secure. Beyond that, you don’t even need a public IP address for your VMs! You connect to Bastion by the VM’s private IP, making it even less likely that somebody will find a way into your machines.
One of the best use cases for Bastion is building jump boxes in corporate networks. You could build a jump box VM with tools like SQL Server Management Studio or Azure Data Studio and only let people access it via Bastion. That VM would have access to private SQL Server instances which are otherwise inaccessible.
Another interesting use case for Bastion is to connect to remote servers using something like a Chromebook. All you need to connect is a browser which supports HTML5, so even on locked-down and stripped-down devices, you can still connect out to that VM and make use of all of the tooling you need.
If you haven’t tried out Bastion yet, I recommend giving it a go. Given that it costs about $140 a month in the Basic tier, it’s not the type of thing I’d want to have running all the time in a personal environment, and sadly, there is no way to pause or stop the service. The only way to stop getting billed for it is to delete the service altogether and then re-create it when you need to access the VM. That’ll save you cash, but add about 10 minutes to your workflow.