Skip to content

Azure Bastion VM Configuration

Overview

This document describes the Azure Bastion and Jump Box VM configuration for secure access to private VNet resources (ADR-050).

Architecture

Internet → Azure Bastion (Public IP) → Jump Box VM (Private IP 10.0.0.4) → Private VNet Resources

Components

1. Azure Bastion

  • Name: ldfdev5-dev-bastion
  • SKU: Basic
  • Public IP: ldfdev5-dev-bastion-pip
  • Subnet: AzureBastionSubnet (10.0.4.0/26)
  • Purpose: Browser-based secure access (no client VPN needed)

2. Jump Box VM

  • Name: ldfdev5-dev-jumpbox
  • OS: Windows Server 2022 Datacenter Azure Edition
  • Size: Standard_D2s_v3
  • Private IP: 10.0.0.4
  • Subnet: compute-subnet (10.0.0.0/23)
  • Purpose: Development access to private VNet resources

Network Security

NSG Rules (compute-subnet)

The following NSG rule allows Bastion to connect to the Jump Box:

{
  name: 'AllowBastionSSHInbound'
  properties: {
    description: 'Allow SSH and RDP from Azure Bastion subnet (ADR-050)'
    protocol: 'Tcp'
    sourcePortRange: '*'
    destinationPortRanges: ['22', '3389']
    sourceAddressPrefix: '10.0.4.0/26'  // Bastion subnet
    destinationAddressPrefix: '10.0.0.0/23'  // Compute subnet
    access: 'Allow'
    priority: 90
    direction: 'Inbound'
  }
}

Location: infrastructure/bicep/modules/networking.bicep

Credentials Management

Key Vault Storage

VM credentials are stored in Key Vault (ldfdev5-dev-kv) with three secrets:

  1. ldfdev5-foundation-vmadminusername - Plain text username
  2. ldfdev5-foundation-vmadminpassword - Plain text password (secure)
  3. vm-credentials-dev - Base64 encoded JSON with all connection info

Bicep Configuration

Location: infrastructure/bicep/foundation.bicep

// Store individual secrets
resource vmUsernameSecret 'Microsoft.KeyVault/vaults/secrets@2023-07-01' = if (deployBastion) {
  name: '${keyVaultName}/vm-admin-username'
  properties: {
    value: vmAdminUsername
    contentType: 'text/plain'
  }
}

resource vmPasswordSecret 'Microsoft.KeyVault/vaults/secrets@2023-07-01' = if (deployBastion) {
  name: '${keyVaultName}/vm-admin-password'
  properties: {
    value: vmAdminPassword
    contentType: 'text/plain'
  }
}

// Store combined credentials
resource vmCredentialsSecret 'Microsoft.KeyVault/vaults/secrets@2023-07-01' = if (deployBastion) {
  name: '${keyVaultName}/vm-credentials-${environment}'
  properties: {
    value: base64(string({
      username: vmAdminUsername
      password: vmAdminPassword
      bastionName: bastionVm.outputs.bastionName
      vmName: bastionVm.outputs.vmName
      connectionInstructions: 'Connect via Azure Portal: VM → Connect → Bastion'
    }))
    contentType: 'application/json'
  }
}

Deployment Script

Location: infrastructure/scripts/deploy-foundation.sh

The deployment script: 1. Generates a secure random password (25 characters) 2. Passes it as a secure parameter to Bicep deployment 3. Stores it in Key Vault after successful deployment

# Generate VM Admin Password
VM_ADMIN_PASSWORD=$(openssl rand -base64 32 | tr -d "=+/" | cut -c1-25)

# Deploy with password parameter
az deployment group create \
  --parameters vmAdminPassword="$VM_ADMIN_PASSWORD"

# Store in Key Vault (via helper function)
push_endpoint_to_keyvault "$RESOURCE_GROUP" "foundation" "vmAdminPassword" "$VM_ADMIN_PASSWORD"

Connection Methods

  1. Navigate to Azure Portal → Virtual Machines → ldfdev5-dev-jumpbox
  2. Click ConnectBastion
  3. Enter credentials from Key Vault
  4. Click Connect (opens in browser)

Method 2: Azure CLI

# Retrieve credentials
USERNAME=$(az keyvault secret show \
  --vault-name ldfdev5-dev-kv \
  --name ldfdev5-foundation-vmadminusername \
  --query value -o tsv)

PASSWORD=$(az keyvault secret show \
  --vault-name ldfdev5-dev-kv \
  --name ldfdev5-foundation-vmadminpassword \
  --query value -o tsv)

# Connect via Bastion
az network bastion ssh \
  --name ldfdev5-dev-bastion \
  --resource-group ldfdev5-rg \
  --target-resource-id /subscriptions/.../virtualMachines/ldfdev5-dev-jumpbox \
  --auth-type password \
  --username "$USERNAME"

Password Reset

If the password needs to be reset:

# Generate new password
NEW_PASSWORD=$(openssl rand -base64 32 | tr -d "=+/" | cut -c1-25)

# Reset VM password
az vm user update \
  --resource-group ldfdev5-rg \
  --name ldfdev5-dev-jumpbox \
  --username azureuser \
  --password "$NEW_PASSWORD"

# Update Key Vault
az keyvault secret set \
  --vault-name ldfdev5-dev-kv \
  --name ldfdev5-foundation-vmadminpassword \
  --value "$NEW_PASSWORD"

Troubleshooting

Issue: "Network connection to Bastion Host appears unstable"

Cause: Missing NSG rule to allow Bastion → VM traffic

Solution: Verify NSG rule exists:

az network nsg rule show \
  --resource-group ldfdev5-rg \
  --nsg-name ldfdev5-dev-vnet-compute-nsg \
  --name AllowBastionSSHInbound

If missing, the rule will be created on next Foundation deployment.

Issue: "Login Failed"

Cause: Password mismatch between VM and Key Vault

Solution: Reset the VM password (see Password Reset section above)

Issue: Cannot access Key Vault secrets

Cause: Insufficient Key Vault permissions

Solution: Grant yourself Key Vault Secrets User role:

az role assignment create \
  --role "Key Vault Secrets User" \
  --assignee $(az ad signed-in-user show --query id -o tsv) \
  --scope $(az keyvault show --name ldfdev5-dev-kv --query id -o tsv)

Files Modified (2025-10-26)

1. infrastructure/bicep/modules/networking.bicep

  • Added AllowBastionSSHInbound NSG rule (priority 90)
  • Allows SSH (22) and RDP (3389) from Bastion subnet to compute subnet

2. infrastructure/bicep/foundation.bicep

  • Enhanced VM credentials storage with separate username and password secrets
  • Maintains backward compatibility with combined vm-credentials-{env} secret
  • Added proper dependsOn for Key Vault resources

3. infrastructure/scripts/deploy-foundation.sh

  • Already correctly stores password in Key Vault via helper function
  • No changes needed

References

  • ADR-050: Azure Bastion replaces VPN Gateway for cost savings and simplicity
  • ADR-048: Key Vault for cross-layer dependency management
  • Bicep Module: infrastructure/bicep/modules/bastion-vm.bicep