Jump box part 1: Secure access to private cloud VM using Azure Bastion

When you work with Azure and Azure IoT, at some point you have to think about a jump box (aka jump server).

This is a device in your network that supports access to other devices in a secure way.

Yes, you can probably access devices in some sort of secure way already using device-specific credentials. Think about an RDP session or using an SSH connection. Still, credentials once remembered by a user, are hard to forget.

The trick with a jump box is to work with multiple layers of security.

First, you have to log in to one device. From there, you ‘jump’ to the next one:

The jump box should be made accessible using other credentials apart from the other connection.

Even better, if these credentials are put in AAD so the login credentials are related to the user logging in, access can be revoked once people are not part of that trusted group of users anymore (e.g. when someone is resigning or fired).

Last year, I wrote this blog post about Azure Bastion already because it is a service that we can use for exactly this:

Diagram showing Azure Bastion architecture.

Using Azure Bastion, only people having access to the Azure portal can make use of that service to access other specific Azure resources (living in the same virtual network, on one or more subnets).

The opposite is true. Azure Bastion only works while using the Azure portal.

Let’s set up a jump box in Azure in a number of blog posts. Let’s start with Azure Bastion. Later on, we look at securing connections to the next device.

The steps we perform in this post are:

  1. Set up a VNET
  2. Create a VM living inside the VNET
  3. Add an Azure Bastion service
  4. Connect to the VM in a secure way
  5. Review Azure Bastion

This results in a VM that is only accessible for those having access to the Azure subscription:

Let’s start.

Note: although the solution is known to be secure, please check everything with e.g. your security officer, company policies, penetration testers, or your mom 🙂

Set up a VNET

We start with setting up a virtual network in Azure. Give it a nice name and resource group:

A virtual network spans a certain range of (private) IP addresses. I provide an address space of for a sufficient range of IP addresses:

Note: ignore the VNet1 message. This is from another unrelated experiment within the same subscription. VNets can be peered when the private IP ranges do not overlap.

Note: it is advised to use another IP address range than your own local range. This way, you better understand what resources are living where.

Both to satisfy the VNet creation wizard (you need at least one subnet) and because resources (like the VM we are about to add) need to be part of a subnet, we add this ‘frontend’ subnet within the VNet:

After filling in the (smaller) range, click the Add button.

This results in adding this one subnet within the wizard:

Regarding security, we leave everything for now:

Note: here we are offered to add a Bastion Host already. We will check this out separately.

Note: basic DDoS Protection is good enough for us.

Now, review and create the VNet:

The VNet is still empty, it has no devices (Azure services) yet.

Let’s add a Virtual Machine that will act as a jump box later on.

Add a Virtual Machine to the subnet

We will add a VM that has NO public endpoint, inside the VNet. The outside world will never know it exists.


We start with a separate resource group (I use ‘jumpbox-vm-weu-rg’) and add a Ubuntu Server 20.04 LTS VM:

Note: because this VM has only a command line to access it, we will use SSH to access it. If needed, adding a VM with a full Windows operating system and RDP access is possible too.

I create the Linux VM having a name and password. For now, it has no inbound ports:

Yes, the VM has its own credentials but later on, we will see that the VM is only accessible using the Bastion connection. There you need to pass additional ADD credentials for Azure Portal access. So technically, two layers of credentials will be in place.

Notice that we do not offer public inbound ports…

This will render the VM to be useless at first but it also provides the insights we do not offer public access. We will add SSH access later on.

For now, we continue with the Networking settings:

We place the VM within the subnet named ‘FrontEnd’, part of our VNet.

The VM does not get a public IP address. So, it’s not accessible (attackable) from the outside world. There are no public inbound ports.

Although not needed for this exercise, I encourage enabling auto-shutdown for test VMs to limit extra costs:

Review and create the VM. This will result with these resources:

At this point, we have a running VM. But, because it has no inbound ports or public IP addresses, we cannot access it.

Notice, it has only that single private network address:

And, the inbound ports are not usable for e.g. access over SSH:

Finally, let’s add SSH access now, at least within the VNet subnet:

Yes, now we provide SSH access to the VM. Still, the VM is living inside a VNet without public endpoints so only resources already within the VNet can access it.

For example, check out the SSH usage dialog:

The IP address is a private range. This address is not available on the internet.

Enters the solution named Azure Bastion.

It works with a separate service in the network, acting as a man-in-the-middle (in a positive way).

Add an Azure Bastion service

To add that Azure Bastion service, we could just follow this standard tutorial or my previous blog.

In the tutorial, a new Bastion service is created (notice we already created that VNet so you can skip that step in the tutorial).

In this new post, we take an alternative approach by adding the Bastion service using the wizard offered by the VM.

First, add an extra subnet named ‘AzureBastionSubnet’ (THIS IS A NAMING CONVENTION) and with a separate (small) range like ‘’:

Note: The name of the subnet should be spelled like this: ‘AzureBastionSubnet’, nothing else.

Add this new subnet to the VNet.

Then, once the subnet is added, navigate to the overview page of the VM and start an Azure Bastion connection for the VM:

The Azure Bastion dialog needs some one-time information to be added:

Azure Bastion is not free. A service will be running full-time. Also, that’s what the public IP address is reserved for.

You will be charged both for the hours the service is running and for data transfer when connections are made (the first 5GB of data transfer per month is free of charge).

Here, I go for the Basic tier (opposite to the Standard tier). It’s less scalable and the native client support (now in preview) is not available. Still, this is fine for me.

See how I rename the public IP address for the Azure Bastion service endpoint. We will see more public IP addresses so naming them in a recognizable way is needed.

Note: The public IP address used by Bastion is a static address.

Check out the help icons if needed for more background information.

Finally, create the Azure Bastion using the defaults (this step will take some time).

After creating the service, from now on this updated dialog is shown when you request Bastion access for a specific service:

Just enter the VM login name and password and hit connect (you entered them ben then when you created the VM).

This opens a new browser tab page with the SSH connection:

You are probably asked to allow copy and paste using the browser clipboard. Accept this.

If no tab page is provided, probably pop-ups are not allowed. Then, check the top of your browser. Allow pop-ups from portal.azure.com.

For more options regarding the Bastion experience, please see my previous blog post.

We now have a secure connection. We are doing SSH in a browser that is only available after being logged in to the Azure portal. When your Azure Portal access rights are revoked or your ‘work-or-school’ AAD account is disabled, you cannot use the connection anymore.

This is expected behavior.

Azure Bastion resources

Both the Bastion resource and its public IP address were created when we ran that Bastion wizard for the first time:

Within the Bastion service, we can see the current connection (when the browser with the SHH access is still open):

We can even disconnect any running client connections.

It’s also possible to change the (basic/standard) tier of the Bastion service and the number of instances.

Notice, you are not able to pause the Bastion service. You can only delete it. So, you are charged for the service, even during the night if nobody is connected.

Within the VNet, you now have two ‘devices’:

These are the VM we created and the Bastion service.


You now have experienced how a VM without any public IP address, living in an Azure VNet can be accessed in a secure way using Azure Bastion:

Azure Bastion is perfect for securing access to specific resources like a virtual machine. Microsoft secures our single public IP address, all other resources do not ‘leak’ IP addresses to the outside world.

You also learned a little bit about VNets, Subnets, ports, and IP addresses.

This VM can now act as a jump box to connect to other devices living on the internet. Again, we need to support secure communication. For that, we will set up a VPN connection in my next blog post…

2 gedachten over “Jump box part 1: Secure access to private cloud VM using Azure Bastion

Reacties zijn gesloten.