Overview and What You Will Learn
In this lab, you will deploy Azure Bastion into a VNet, connect to a VM with no public IP address at all through the Azure Portal's browser-based session, and confirm that VM's management port was never exposed to the internet at any point.
Why This Matters in Production
A team opens SSH directly to the internet on a production VM "just for now, I'll close it later," and that exposed port becomes exactly the kind of finding a real compromise starts from - automated scanners find open management ports within hours, not weeks. Azure Bastion removes the temptation entirely, since secure access is available without ever needing to expose the port in the first place.
Core Principles
Azure Bastion is deployed once per VNet and provides secure RDP and SSH access to every VM inside that VNet through the Azure Portal, with the VM's own management port never exposed publicly at all.
+------------------------------------------+| You, in a browser, logged into the Portal |+------------------------------------------+ | | (HTTPS, through the Portal) v+------------------------------------------+| Azure Bastion (deployed in its own subnet) |+------------------------------------------+ | | (private connection, inside | Azure's own network) v+------------------------------------------+| Your VM - port 22/3389 never exposed || to the public internet at all |+------------------------------------------+Bastion requires its own dedicated subnet, specifically named AzureBastionSubnet, within the same VNet as the VMs it will provide access to.
Detailed Step-by-Step Practical Lab
- Create a Resource Group and VNet with a subnet for VMs:
az group create --name rg-bastion-lab-mumbai --location centralindia az network vnet create \ --resource-group rg-bastion-lab-mumbai \ --name vnet-bastion-lab \ --address-prefix 10.0.0.0/16 \ --subnet-name subnet-vms \ --subnet-prefix 10.0.1.0/24- Add the dedicated Bastion subnet - the name must be exactly
AzureBastionSubnet:
az network vnet subnet create \ --resource-group rg-bastion-lab-mumbai \ --vnet-name vnet-bastion-lab \ --name AzureBastionSubnet \ --address-prefix 10.0.2.0/26- Create a public IP for the Bastion resource itself - this is the only public IP in the entire setup, and it belongs to Bastion, not to any VM:
az network public-ip create \ --resource-group rg-bastion-lab-mumbai \ --name pip-bastion-lab \ --sku Standard- Deploy Azure Bastion into the dedicated subnet:
az network bastion create \ --resource-group rg-bastion-lab-mumbai \ --name bastion-lab \ --public-ip-address pip-bastion-lab \ --vnet-name vnet-bastion-lab- Create a VM with no public IP address at all:
az vm create \ --resource-group rg-bastion-lab-mumbai \ --name vm-private-lab \ --image Ubuntu2204 \ --vnet-name vnet-bastion-lab \ --subnet subnet-vms \ --public-ip-address "" \ --admin-username azureadmin \ --generate-ssh-keys- Confirm the VM genuinely has no public IP:
az vm show \ --resource-group rg-bastion-lab-mumbai \ --name vm-private-lab \ --show-details \ --query "publicIps" --output tsv## Expected: empty output - no public IP existsIn the Azure Portal, navigate to the VM and select Connect, then Bastion - this opens a browser-based SSH session using Bastion's connection, with the VM's own SSH port never exposed to the internet at any point.
Clean up:
az group delete --name rg-bastion-lab-mumbai --yes --no-waitProduction Best Practices & Common Pitfalls
Common MistakeDeciding to skip Bastion "just for a quick one-time fix" and temporarily opening RDP or SSH to the internet instead. "Just for now" is exactly the situation real compromises come from - the moment that thought occurs is the exact moment to deploy Bastion instead.
TipOne Bastion deployment serves every VM in the VNet - it is not a per-VM cost or setup. Once deployed, it becomes the standard, default access path for the entire environment going forward.
- The
AzureBastionSubnetname is mandatory and exact. Azure specifically looks for this subnet name when deploying Bastion - a differently named subnet, even with an identical address range, will not work. - Bastion access still respects RBAC and NSG rules on the destination VM's subnet. Deploying Bastion does not bypass other access controls - it replaces the need for a public IP and open management port, not the need for proper permissions.
Quick Reference & Troubleshooting Commands
| Command | Description |
|---|---|
az network vnet subnet create --name AzureBastionSubnet |
Create the required dedicated subnet |
az network bastion create |
Deploy Azure Bastion into a VNet |
az vm create --public-ip-address "" |
Create a VM with no public IP at all |
az vm show --query "publicIps" |
Confirm a VM has no public IP assigned |