Native client connections with Azure Bastion

Azure Bastion supports native client connections, allowing you to connect to virtual machines directly from your desktop. In this blog post, we’ll explore how easy, useful, and intuitive this feature is. Native client connections are only available on the Standard and Premium Azure Bastion SKUs. Developer and Basic SKUs do not support this feature. With a native client connection, you can, for example, transfer files directly between the cloud instance and your computer, which can be highly beneficial. In this article, I’ll describe how to establish native client connections using macOS and Windows.

Prerequisites

Before establishing the connection, you need to have Azure Bastion deployed in your tenant along with a virtual machine to log into. Please note that you need the Standard or Premium SKU to use native client connections. Your local computer must have the Azure Command-Line Interface (Azure CLI) installed, along with the bastion and ssh extensions. To install the required extensions, run: az extension add -n extensionName. If they are already installed, ensure they are up to date with: az extension update -n extensionName.

The user that is connecting through Bastion needs to have reader role on virtual machine and its NIC with private IP, as well as reader role on the Azure Bastion resource. In case Entra ID sign-in method is used user also needs to have either Virtual Machine Administrator Login or Virtual Machine User Login role.

Establishing the connection

There are multiple ways to connect to your virtual machines. You can use either SSH or RDP and depending on your setup you can use Entra ID login, username and password, or key pair. In these examples, we mainly use a username and password to keep things simple. First, log in to Azure using the following command: az login.

Depending on the use case, one of the following connection commands can be used:
az network bastion rdp –name “<BastionName>” –resource-group “<ResourceGroupName>” –target-resource-id “<VMResourceID>”
az network bastion ssh –name “<BastionName>” –resource-group “<ResourceGroupName>” –target-resource-id “<VMResourceID>”

You must also specify the authentication type using –auth-type. Depending on the method, you either need to specify –ssh-key (with filepath for using SSH key pair) or –username (followed by your username if you are using username and password).

You can also use the private IP address of a virtual machine with –target-ip-address instead of –target-resource-id. However, using this method Entra ID authentication and custom ports and protocols are not supported. So if you have changed default RDP or SSH ports to something else you are unable to connect using target resource’s private IP address and should use target resource id instead.

Rather than connecting directly, you can also use a Bastion tunnel for connections. Using bastion tunnel is the way if you want to take RDP connection to Windows machine from macOS or Linux. Also, if you need to copy files between Linux VM and your own computer Bastion tunnel is your method of choice.

How to find target-resource-id?

Retrieving a virtual machine’s resource ID may seem straightforward, and it is—if you know where to look. You can obtain the Resource ID using the following methods.

The first method is to open the Azure Portal, navigate to the virtual machine, and click JSON view on the Overview page. Resource ID can then be found in the text box on a blade that opens.

Screenshot to show Resouce ID in Azure Portal

Another method is to use Azure CLI, which is likely already open. Running az vm list displays all virtual machines in your subscription. You can find the id field in the output. As this lists all of the Virtual machines it can be tedious task to find the right id. You can list virtual machines in certain Resource Group using az vm list -g “<ResourceGroupName>” which can lower the amount virtual machines listed but the amount of details is still quite plentiful. However, we can go a bit further and pipe a grep to find the exact machine name among the fields. With command az vm list -g “<ResourceGroupName>” | grep -w “id” | grep -w “<VirtualMachineName>” we’ll get nice output that only states the Resource ID of that particular virtual machine. Listing VMs by resource group isn’t required, but you can use grep after az vm list to filter the results.”

Screenshot of a command and output

After retrieving the Resource ID using one of these methods, you can copy and use it in the connection command. However, should you want it to a variable and you are running commands in Powershell you can do the following:
$resource = az vm show -g jukka-test-rg -n vm-test-01 | ConvertFrom-Json
$resourceID = $resource.id

This gives you virtual machines Resource ID in variable that you can use when connecting.

Connections using macOS

On macOS, you can use the built-in Terminal. To connect, I stored the virtual machine’s Resource ID in a variable and used the following command:
az network bastion ssh –name bastion-test-d-001 –resource-group jukka-test-rg –target-resource-id $resourceID –auth-type password –username jukka

Successful login from macOS using SSH

Now that we have connected to a Linux virtual machine, how can we do the same for a Windows VM? Well, if you are connecting using SSH the process is exactly the same. Please note that you need to have OpenSSH Server installed and running on your Windows virtual machine. To configure Windows properly please refer to this guide.

Successful login from macOS to Windows VM using SSH

If connection needs to be done from macOS to Windows using RDP we need to use Bastion tunnel in order to establish the connection. Unfortunately you’re not able to create Bastion tunnel currently on macOS. This is a known issue and hopefully gets solved soon. Issue can be found at Azure CLI GitHub.

Connections using Windows

SSH connections from Windows work exactly the same as in the macOS section. You can use the same command and expect the same output:
az network bastion ssh –name bastion-test-d-001 –resource-group jukka-test-rg –target-resource-id $resourceID –auth-type password –username jukka

Successful login from Windows 11 to Linux VM using SSH

If you need to RDP into Windows virtual machine from your own Windows computer it’s relatively easy with native Remote Desktop Connection client. This can be achieved by following command:
az network bastion rdp –name bastion-test-d-001 –resource-group jukka-test-rg –target-resource-id $resourceID
You don’t need to specify –auth-type or –username in this command.

Successful login from Windows 11 to Windows VM using RDP

Bastion tunnels work well on Windows. In the command you need to specify remote and local ports. –resource-port is the port on remote machine and –port is local port that you want to assign for tunnel. Tunnel can be opened using following command:
az network bastion tunnel –name bastion-test-d-001 –resource-group jukka-test-rg –target-resource-id $resourceID –resource-port 22 –port 8822

Successfully opened tunnel from Windows 11 to Linux VM

Once the Bastion tunnel is open, you can use Windows Command Prompt to connect to the virtual machine. Remember, since the tunnel is open, you must SSH to the local machine port you specified in the command.

Successful connection from Windows 11 to Linux VM through Bastion tunnel

Conclusion

Azure Bastion is a great tool to be able to have connections to virtual machines without exposing them to public internet. Using the Azure portal for connections is straightforward, but Native Client connections have a learning curve. However, once you get the hang of them, they are fairly easy to use. I recommend saving connection strings somewhere so you don’t need to re-type them every single time.

Native Client connections are especially useful for transferring files between your local machine and a virtual machine. Additionally, you don’t need to use a web browser and can utilize native tools configured to your preference. If you are working on Windows you most likely won’t run into any issues. That said, if you are working on macOS things change radically. As you cannot use Bastion tunnel at all currently you don’t get basically any benefit using Azure Bastion Native Client connections. You can achieve everything right from Azure portal.