Skip to content

Lab 04: Azure Bastion and JIT Access

Build a private administration path using Azure Bastion and Defender for Cloud Just-In-Time access instead of public management ports.

Prerequisites

  • Azure subscription with contributor-level access to compute, network, backup, and monitoring resources
  • Azure CLI installed and signed in
  • Variables set for the lab:
    • RG
    • VM_NAME
    • LOCATION
    • VNET_NAME
    • SUBNET_NAME
  • A Log Analytics workspace or backup vault where the lab requires it

Architecture Diagram

graph TD
    A[Lab 04: Azure Bastion and JIT Access] --> B[Resource group and networking baseline]
    B --> C[Virtual machine deployment]
    C --> D[Security and access controls]
    D --> E[Observability and validation]
    E --> F[Cleanup and cost review]

Lab Metadata

Field Value
Lab file lab-04-azure-bastion-jit-access.md
Estimated duration 45-75 minutes
Difficulty Intermediate
Focus technologies Azure Bastion, NSG, JIT access
Cost profile Moderate; deallocate or clean up immediately after validation

Step-by-step Instructions

Step 1: Create the resource group and network baseline

az group create \
    --name $RG \
    --location $LOCATION \
    --output json

az network vnet create \
    --resource-group $RG \
    --name $VNET_NAME \
    --address-prefixes 10.40.0.0/16 \
    --subnet-name $SUBNET_NAME \
    --subnet-prefixes 10.40.1.0/24 \
    --output json
Command Purpose
az group create Create the resource group for the lab.
--name Name of the resource group to create.
--location Azure region for the resource group.
--output Output format for the response (JSON here).
az network vnet create Create the virtual network and its initial subnet.
--resource-group Resource group that will contain the virtual network.
--name Name of the virtual network to create.
--address-prefixes Address space (CIDR) for the virtual network.
--subnet-name Name of the initial subnet to create.
--subnet-prefixes CIDR range assigned to the subnet.
--output Output format for the response (JSON here).

Expected outcome:

  • The resource group exists in the intended region.
  • The virtual network and subnet are available for VM deployment.

Step 2: Deploy the base VM

az vm create \
    --resource-group $RG \
    --name $VM_NAME \
    --image Ubuntu2204 \
    --size Standard_D4s_v5 \
    --admin-username azureuser \
    --generate-ssh-keys \
    --vnet-name $VNET_NAME \
    --subnet $SUBNET_NAME \
    --public-ip-sku Standard \
    --storage-sku Premium_LRS \
    --output json
Command Purpose
az vm create Create a virtual machine in the lab virtual network.
--resource-group Resource group that will contain the virtual machine.
--name Name of the virtual machine to create.
--image Marketplace image or alias for the OS (Ubuntu2204).
--size VM size (SKU) to provision.
--admin-username Administrator user name for the guest OS.
--generate-ssh-keys Generate an SSH key pair if one does not already exist.
--vnet-name Existing virtual network to attach the VM to.
--subnet Subnet within the virtual network for the VM NIC.
--public-ip-sku SKU for the public IP address (Standard).
--storage-sku Managed-disk storage SKU for the OS disk (Premium_LRS).
--output Output format for the response (JSON here).

Expected outcome:

  • The VM deploys with Premium SSD-backed storage and a predictable network baseline.
  • You have enough CPU, memory, and NIC capability to test the scenario without using a tiny burstable SKU.

Step 3: Record the pre-hardening management exposure

Before you introduce Bastion or JIT, capture how the VM is currently exposed so you can prove the hardening change reduced the management attack surface.

az vm show \
    --resource-group $RG \
    --name $VM_NAME \
    --show-details \
    --query "{name:name,privateIps:privateIps,publicIps:publicIps,powerState:powerState}" \
    --output json
Command Purpose
az vm show Retrieve the current configuration of the virtual machine.
--resource-group Resource group that contains the virtual machine.
--name Name of the virtual machine to inspect.
--show-details Include runtime details such as IP address information.
--query JMESPath expression selecting private IPs, public IPs, and power state.
--output Output format for the response (JSON here).

Recommended operator notes:

  • Record whether the VM currently has a public IP or any other direct management exposure.
  • Note the subnet and addressing assumptions you must preserve when you add Bastion.
  • Record which ports and approval duration you expect JIT to control in production.

Step 4: Validate the scenario end to end

Run both control-plane and workload validation so you can compare the exposed baseline with the hardened access path after Bastion and JIT are in place.

az vm get-instance-view \
    --resource-group $RG \
    --name $VM_NAME \
    --output json

az monitor activity-log list \
    --resource-group $RG \
    --offset 2h \
    --output table
Command Purpose
az vm get-instance-view Retrieve the runtime instance view (power and provisioning state) of the VM.
--resource-group Resource group that contains the virtual machine.
--name Name of the virtual machine to inspect.
--output Output format for the response (JSON here).
az monitor activity-log list List recent control-plane activity-log events.
--resource-group Resource group to scope activity-log events to.
--offset Look-back window for events (2h here).
--output Output format for the response (table here).

Step 5: Optional operational hardening

  • Review whether Bastion, JIT, and NSG rules should be deployed together as one repeatable access pattern.
  • Review whether break-glass access requires different approval or logging requirements.
  • Review whether the VM should lose its public IP entirely after the lab proves the private path.

Validation Steps

Use the following validation checklist before marking the lab complete:

  • [ ] The VM is in the expected power and provisioning state
  • [ ] The intended feature change is visible in Azure resource properties
  • [ ] At least one CLI verification command was captured after the change
  • [ ] You can explain how the lab outcome would change production design or troubleshooting

Cleanup Instructions

az vm delete \
    --resource-group $RG \
    --name $VM_NAME \
    --yes

az network nic delete \
    --resource-group $RG \
    --name "${VM_NAME}VMNic"

az group delete \
    --name $RG \
    --yes \
    --no-wait
Command Purpose
az vm delete Delete the virtual machine.
--resource-group Resource group that contains the virtual machine.
--name Name of the virtual machine to delete.
--yes Skip the confirmation prompt.
az network nic delete Delete the network interface left behind by the VM.
--resource-group Resource group that contains the network interface.
--name Name of the network interface to delete.
az group delete Delete the resource group and all remaining lab resources.
--name Name of the resource group to delete.
--yes Skip the confirmation prompt.
--no-wait Return immediately without waiting for deletion to finish.

Cleanup notes:

  • Delete associated disks, public IPs, Bastion hosts, vault items, or replication resources if the lab created them.
  • Review whether backup vaults or recovery services still hold retained items that continue billing after VM deletion.

See Also

Sources