Azure Bastion Overview: Secure VM Access Without Public SSH

Azure Bastion is a managed service that lets you connect to Azure VMs over SSH and RDP through your browser, using the Azure portal. No public IP on the VM, no open SSH or RDP ports in the NSG, no VPN client required. Bastion acts as a secure gateway between the internet and your private VMs, with all session activity logged to Azure Monitor.

What problem Bastion solves

The traditional way to SSH into an Azure VM is to give it a public IP and open port 22 in the Network Security Group. That works, but creates two problems:

  • Attack surface. Any public IP with port 22 open immediately attracts brute-force attempts, credential stuffing, and exploit probing. Even with key-based auth blocking password guessing, you are still exposing the SSH daemon and any vulnerabilities in it.
  • Operational complexity. Maintaining allowlists of IP ranges for developers, updating them when IPs change, and auditing who connected when is ongoing manual work.

Bastion removes both problems. The VM has no public IP. Port 22 and 3389 are not open in the NSG. Your developers connect through the Azure portal using their Entra ID credentials — the same credentials that control access to every other Azure resource. Access is revoked by removing the RBAC role assignment, not by editing NSG rules or SSH key files.

How Bastion works

Azure Bastion deploys into a dedicated subnet called AzureBastionSubnet (the name is required — Azure will not recognise a differently-named subnet). The Bastion service gets a public IP and exposes an HTTPS endpoint. When you connect through the portal:

  1. Your browser opens an HTTPS connection to the Bastion service’s public IP.
  2. Bastion authenticates you with your Entra ID session.
  3. Bastion opens an SSH or RDP connection to your VM using the VM’s private IP inside the VNet.
  4. The terminal or remote desktop session runs in your browser over WebSocket.

The VM sees an SSH connection originating from the AzureBastionSubnet range, not from the internet. The NSG on the VM needs to allow SSH from that subnet only.

Deploying Azure Bastion

Bastion requires a dedicated subnet in the VNet where your VMs live. The subnet must be named exactly AzureBastionSubnet and must be at least /26 (64 addresses).

# Add the AzureBastionSubnet to your existing VNet
az network vnet subnet create \
  --resource-group my-rg \
  --vnet-name my-vnet \
  --name AzureBastionSubnet \
  --address-prefix 10.0.255.0/26

# Create a public IP for Bastion (Standard SKU required)
az network public-ip create \
  --resource-group my-rg \
  --name my-bastion-pip \
  --sku Standard \
  --location eastus

# Create the Bastion host (Basic SKU)
az network bastion create \
  --resource-group my-rg \
  --name my-bastion \
  --vnet-name my-vnet \
  --public-ip-address my-bastion-pip \
  --location eastus \
  --sku Basic

Bastion provisioning takes 5–10 minutes. Once deployed, navigate to any VM in the portal, click Connect, and choose Bastion. You authenticate with your Entra ID account (and the VM’s admin username and SSH key or password), and a browser-based terminal opens.

Tip

The Developer SKU is a lower-cost single-session option useful for personal accounts or small teams where concurrent access is not needed. It shares the Bastion infrastructure with other customers (similar to burstable VM tiers) and does not require a dedicated Bastion subnet — making it easier to test.

Native client support (Standard SKU)

The Standard SKU adds the ability to use your local SSH or RDP client rather than the browser. This is useful when you need SSH features that the browser terminal does not support — such as SCP file transfers, port forwarding, or terminal multiplexers.

# Connect to a VM using the Azure CLI and your local SSH client
az network bastion ssh \
  --resource-group my-rg \
  --name my-bastion \
  --target-resource-id /subscriptions/.../virtualMachines/my-vm \
  --auth-type ssh-key \
  --username azureuser \
  --ssh-key ~/.ssh/azure-vm-key

With native client support, Bastion tunnels the SSH session through HTTPS. Your local SSH client connects to a localhost port that Bastion maps to the VM’s private SSH port. The session looks and behaves like a normal SSH connection, but traffic never leaves Azure’s network unencrypted and no public IP is needed on the VM.

SKU comparison

FeatureDeveloperBasicStandard
Dedicated subnet requiredNoYesYes
Concurrent sessions1Up to 25Up to 50 (scalable)
Native client (local SSH/RDP)NoNoYes
VNet peering supportNoNoYes
Shareable linksNoNoYes
Approximate cost~$0.04/hour~$0.19/hour~$0.29/hour base

When Bastion is not the right tool

Bastion is a good fit for most teams, but not all:

  • If you need SCP or SFTP file transfers, the basic browser terminal does not support them. The Standard SKU with native client solves this, but adds cost.
  • If you run dozens of VMs and need bulk SSH automation, tools like Ansible, Azure Run Command, or SSH via a VPN are more practical than connecting through Bastion for each VM.
  • If cost is a hard constraint, a jump host (a small VM in the same VNet with a public IP) can serve the same isolation purpose at lower cost — though with more operational overhead.

Common Bastion mistakes

  1. Naming the subnet incorrectly. The subnet must be named exactly AzureBastionSubnet — Azure will reject any other name. This is a hard requirement, not a recommendation.
  2. Sizing AzureBastionSubnet too small. The minimum is /26 (64 addresses). Azure reserves addresses within the subnet for Bastion’s internal components. A /28 subnet will fail deployment. For Standard SKU with scaling enabled, use /26 or larger.
  3. Still leaving port 22 open on VM NSGs. Deploying Bastion but not removing the direct SSH access rule in the VM’s NSG means you paid for Bastion without getting the security benefit. After deploying Bastion, update VM NSGs to allow SSH only from the AzureBastionSubnet address range, not from the internet.

Frequently asked questions

Do I need a public IP on my VM to use Azure Bastion?

No. That is the point. Bastion connects to your VM using its private IP inside the Virtual Network. The VM needs no public IP and no open port 22 or 3389 in its NSG. All the public-facing infrastructure lives in the AzureBastionSubnet, not on the VM itself.

How much does Azure Bastion cost?

Bastion is billed per hour the resource exists, plus data transfer. The Basic SKU costs roughly $0.19/hour in most regions (about $140/month). Developer SKU is cheaper but limited to one concurrent session. Standard SKU is more expensive but adds features like native client support, scaling for concurrent sessions, and shareable links. For a team of developers connecting regularly, Bastion is usually worth the cost compared to the risk of exposed SSH ports.

Can I use Azure Bastion with VMs in a peered VNet?

Yes, with the Standard SKU and VNet peering enabled on the Bastion host. The Basic SKU only allows connections to VMs in the same VNet. If you have a hub-and-spoke network topology, deploy Bastion in the hub VNet with Standard SKU to reach VMs in all spoke VNets through peering.

Last verified: 19 March 2026 Cloud services change frequently. Verify details against official documentation before making infrastructure decisions.