Task 01: Virtual Network & Subnets
DOCUMENT CATEGORY: Runbook SCOPE: Virtual network deployment PURPOSE: Create management VNet and subnets MASTER REFERENCE: Microsoft Learn - Virtual Networks
Status: Active
Overview
This task creates the management Virtual Network (VNet) and all required subnets for Azure Local infrastructure. This VNet hosts management VMs (Domain Controllers, Utility Server, NDM Server, Lighthouse Server) and provides connectivity to on-premises via VPN.
Execution Target: Azure-Only (control-plane API operation) Tab Profile: 3 tabs — Azure Portal · Azure CLI / PowerShell · Standalone Script
Module: azurelocal-toolkit
File: network.tf
Mode: Management
Components Created
| Resource | Name Pattern | Purpose |
|---|---|---|
| Virtual Network | vnet-azrl-{env}-{region}-01 | Management address space |
| GatewaySubnet | GatewaySubnet | VPN Gateway (required name) |
| Management Subnet | snet-azrl-{env}-{region}-01 | Management VMs |
| Bastion Subnet | AzureBastionSubnet | Azure Bastion (required name, /26 min) |
| Endpoints Subnet | snet-endpoints-{env}-{region}-01 | Private Endpoints |
Default Subnet Layout
| Subnet | Default CIDR | Notes |
|---|---|---|
GatewaySubnet | 10.x.x.0/27 | Required name, no NSG |
snet-azrl-* | 10.x.x.32/27 | DCs, Utility, NDM, Lighthouse |
AzureBastionSubnet | 10.x.x.64/26 | Required name, /26 minimum |
snet-endpoints-* | 10.x.x.128/27 | Key Vault, Storage endpoints |
Prerequisites
- Phase 01: Landing Zones completed — subscription and resource groups exist
- Phase 03: RBAC Permissions completed — deployment identity has Network Contributor role
- Network IP address ranges documented and confirmed (no conflicts with on-prem)
- Landing zone model confirmed (Single Subscription or CAF/WAF)
Variables from variables.yml
| Variable | Config Path | Example (IIC) |
|---|---|---|
| Subscription ID | azure.subscriptions.<name>.id | (per environment) |
| Resource Group | network.azure_vnets.management.resource_group | rg-azrlmgmt-azl-eus-01 |
| VNet Name | network.azure_vnets.management.name | vnet-azrl-azl-eus-01 |
| Location | network.azure_vnets.management.location | eastus |
| Address Space | network.azure_vnets.management.cidr | 10.250.1.0/24 |
| GatewaySubnet CIDR | network.azure_vnets.management.subnets.gateway.cidr | 10.250.1.0/27 |
| Management Subnet CIDR | network.azure_vnets.management.subnets.management.cidr | 10.250.1.32/27 |
| Bastion Subnet CIDR | network.azure_vnets.management.subnets.bastion.cidr | 10.250.1.64/26 |
| Endpoints Subnet CIDR | network.azure_vnets.management.subnets.endpoints.cidr | 10.250.1.128/27 |
Single Subscription Model
In the single subscription model, all management infrastructure is deployed to a single subscription under one resource group.
Landing Zone Placement
| Field | Value | Config Path |
|---|---|---|
| Subscription | Customer subscription | azure.subscriptions.<name>.id |
| Resource Group | rg-azrlmgmt-{env}-{region}-01 | network.azure_vnets.management.resource_group |
| VNet Name | vnet-azrl-{env}-{region}-01 | network.azure_vnets.management.name |
| Location | Azure region | network.azure_vnets.management.location |
| Address Space | 10.x.x.0/24 | network.azure_vnets.management.cidr |
Execution Options
- Azure Portal
- Azure CLI / PowerShell
- Standalone Script
Azure Portal
When to use: Learning Azure Local, single deployment, prefer visual interface
Procedure
- Navigate to Virtual Networks:
- In Azure Portal, search for Virtual networks
- Click + Create
-
Basics tab: | Field | Value | Source | |-------|-------|--------| | Subscription | Your subscription |
azure.subscriptions.<name>.id| | Resource group |rg-azrlmgmt-{env}-{region}-01|network.azure_vnets.management.resource_group| | Virtual network name |vnet-azrl-{env}-{region}-01|network.azure_vnets.management.name| | Region | Your region |network.azure_vnets.management.location| -
IP Addresses tab:
- Set IPv4 address space to value from
network.azure_vnets.management.cidr - Add subnets:
| Subnet Name | Address Range | Source |
|---|---|---|
GatewaySubnet | /27 range | network.azure_vnets.management.subnets.gateway.cidr |
| Management subnet | /27 range | network.azure_vnets.management.subnets.management.cidr |
AzureBastionSubnet | /26 range | network.azure_vnets.management.subnets.bastion.cidr |
| Endpoints subnet | /27 range | network.azure_vnets.management.subnets.privateendpoints.cidr |
-
Security tab: Leave defaults (no Bastion/Firewall/DDoS at this stage)
-
Tags tab: Apply standard tags per
tags.*config paths -
Review + create: Verify settings → Click Create
Validation
- VNet created successfully in the correct resource group
- All four subnets visible under the VNet
- Address space matches
network.azure_vnets.management.cidr - GatewaySubnet has no NSG attached
Links
Azure CLI / PowerShell
When to use: Scripted Azure operations from management workstation or pipeline — config-driven via
variables.yml
Script
Primary: scripts/deploy/02-azure-foundation/phase-04-azure-management-infrastructure/task-01-virtual-network/powershell/New-VirtualNetwork.ps1
Alternatives:
| Variant | Path |
|---|---|
| PowerShell + Azure CLI | scripts/deploy/02-azure-foundation/phase-04-azure-management-infrastructure/task-01-virtual-network/azure-cli/New-VirtualNetwork.azcli.ps1 |
| Bash + Azure CLI | scripts/deploy/02-azure-foundation/phase-04-azure-management-infrastructure/task-01-virtual-network/bash/invoke-virtual-network.sh |
This script reads variables.yml directly — subscription, resource group, and all resource names come from the config. The config is pre-populated for your landing zone model during Planning & Discovery, so one script works for both models.
Code
# ============================================================================
# Script: New-VirtualNetwork.ps1
# Execution: Run from management workstation — reads variables.yml
# Prerequisites: Az.Network module, authenticated to Azure
# ============================================================================
#Requires -Modules Az.Network, Az.Resources
param(
[Parameter(Mandatory = $false)]
[ValidateScript({Test-Path $_})]
[string]$ConfigPath = "config/variables.yml"
)
$ErrorActionPreference = "Stop"
$scriptRoot = $PSScriptRoot
# Import helpers
. "$scriptRoot/../../../../../common/utilities/helpers/config-loader.ps1"
. "$scriptRoot/../../../../../common/utilities/helpers/logging.ps1"
# Load configuration
$config = Get-InfrastructureConfig -ConfigPath $ConfigPath
# Extract values from configuration
$SubscriptionId = $config.azure.subscriptions.($config.network.azure_vnets.management.subscription).id
$ResourceGroup = $config.network.azure_vnets.management.resource_group
$VNetName = $config.network.azure_vnets.management.name
$Location = $config.network.azure_vnets.management.location
$AddressSpace = $config.network.azure_vnets.management.cidr
# Subnet definitions from config
$Subnets = @(
@{ Name = $config.network.azure_vnets.management.subnets.gateway.name
Prefix = $config.network.azure_vnets.management.subnets.gateway.cidr },
@{ Name = $config.network.azure_vnets.management.subnets.management.name
Prefix = $config.network.azure_vnets.management.subnets.management.cidr },
@{ Name = $config.network.azure_vnets.management.subnets.bastion.name
Prefix = $config.network.azure_vnets.management.subnets.bastion.cidr },
@{ Name = $config.network.azure_vnets.management.subnets.privateendpoints.name
Prefix = $config.network.azure_vnets.management.subnets.privateendpoints.cidr }
)
# Set subscription context
Set-AzContext -SubscriptionId $SubscriptionId | Out-Null
Write-LogInfo "Context set to subscription: $SubscriptionId"
# Build subnet configurations
$subnetConfigs = foreach ($subnet in $Subnets) {
New-AzVirtualNetworkSubnetConfig -Name $subnet.Name -AddressPrefix $subnet.Prefix
}
# Create VNet
Write-LogInfo "Creating VNet: $VNetName in $ResourceGroup ($Location)"
$vnet = New-AzVirtualNetwork `
-Name $VNetName `
-ResourceGroupName $ResourceGroup `
-Location $Location `
-AddressPrefix $AddressSpace `
-Subnet $subnetConfigs
Write-LogSuccess "VNet created: $($vnet.Id)"
# Return object for pipeline
$vnet
Validation
# Verify VNet creation
$vnet = Get-AzVirtualNetwork -Name $VNetName -ResourceGroupName $ResourceGroup
$vnet | Format-List Name, Location, AddressSpace
$vnet.Subnets | Format-Table Name, AddressPrefix
Validation Script: scripts/validation/02-azure-foundation/phase-04/Test-VirtualNetwork.ps1
Standalone Script
When to use: Copy-paste ready script with no external dependencies — no config file, no helpers needed. Ideal for sharing, demos, or environments without the toolkit.
Code
# ============================================================================
# Script: New-VirtualNetwork-Standalone.ps1
# Execution: Run anywhere — fully self-contained, no external dependencies
# Prerequisites: Az.Network module, authenticated to Azure
# ============================================================================
#Requires -Modules Az.Network, Az.Resources
#region CONFIGURATION
# ── Edit these values to match your environment ──────────────────────────────
$SubscriptionId = "00000000-0000-0000-0000-000000000000" # Target subscription ID
$ResourceGroup = "rg-azrlmgmt-azl-eus-01" # Management resource group
$VNetName = "vnet-azrl-azl-eus-01" # Virtual network name
$Location = "eastus" # Azure region
$AddressSpace = "10.250.1.0/24" # VNet address space
# Subnet definitions
$GatewaySubnetCidr = "10.250.1.0/27" # GatewaySubnet (VPN Gateway)
$MgmtSubnetName = "snet-azrl-azl-eus-01" # Management subnet name
$MgmtSubnetCidr = "10.250.1.32/27" # Management subnet CIDR
$BastionSubnetCidr = "10.250.1.64/26" # AzureBastionSubnet (/26 min)
$EndpointsSubnetName = "snet-endpoints-azl-eus-01" # Private endpoints subnet name
$EndpointsSubnetCidr = "10.250.1.128/27" # Private endpoints CIDR
#endregion CONFIGURATION
# Set subscription context
Set-AzContext -SubscriptionId $SubscriptionId | Out-Null
# Build subnet configurations
$subnetConfigs = @(
New-AzVirtualNetworkSubnetConfig -Name "GatewaySubnet" -AddressPrefix $GatewaySubnetCidr
New-AzVirtualNetworkSubnetConfig -Name $MgmtSubnetName -AddressPrefix $MgmtSubnetCidr
New-AzVirtualNetworkSubnetConfig -Name "AzureBastionSubnet" -AddressPrefix $BastionSubnetCidr
New-AzVirtualNetworkSubnetConfig -Name $EndpointsSubnetName -AddressPrefix $EndpointsSubnetCidr
)
# Create VNet
Write-Host "Creating VNet: $VNetName" -ForegroundColor Cyan
$vnet = New-AzVirtualNetwork `
-Name $VNetName `
-ResourceGroupName $ResourceGroup `
-Location $Location `
-AddressPrefix $AddressSpace `
-Subnet $subnetConfigs
Write-Host "✅ VNet '$VNetName' created successfully" -ForegroundColor Green
# Verify
$vnet.Subnets | Format-Table Name, AddressPrefix
This script is completely self-contained. All values are defined in the #region CONFIGURATION block above. Edit those values and run — no variables.yml, no config-loader, no helpers required.
Validation
- VNet created in the correct resource group
- All four subnets present with correct CIDRs
- GatewaySubnet has no NSG attached
- Address space does not conflict with on-premises networks
CAF/WAF Landing Zone Model
In the CAF/WAF model, networking resources are deployed to the Connectivity subscription under the Connectivity management group, separate from management and identity resources.
Landing Zone Placement
| Field | Value | Config Path |
|---|---|---|
| Subscription | Connectivity subscription | azure.subscriptions.connectivity.id |
| Resource Group | rg-azrlconn-{env}-{region}-01 | network.azure_vnets.management.resource_group |
| VNet Name | vnet-azrl-{env}-{region}-01 | network.azure_vnets.management.name |
| Location | Azure region | network.azure_vnets.management.location |
| Address Space | 10.x.x.0/24 | network.azure_vnets.management.cidr |
In CAF/WAF, this VNet is created in the Connectivity subscription — not the same subscription as management VMs. VNet peering or cross-subscription subnet references may be required for VM NICs.
Execution Options
- Azure Portal
- Azure CLI / PowerShell
- Standalone Script
Azure Portal
When to use: Learning Azure Local, single deployment, prefer visual interface
Procedure
- Navigate to Virtual Networks:
- In Azure Portal, search for Virtual networks
- Click + Create
-
Basics tab: | Field | Value | Source | |-------|-------|--------| | Subscription | Connectivity subscription |
azure.subscriptions.connectivity.id| | Resource group |rg-azrlconn-{env}-{region}-01|network.azure_vnets.management.resource_group| | Virtual network name |vnet-azrl-{env}-{region}-01|network.azure_vnets.management.name| | Region | Your region |network.azure_vnets.management.location| -
IP Addresses tab:
- Set IPv4 address space to value from
network.azure_vnets.management.cidr - Add subnets identical to Single Subscription model (same names, same CIDRs)
-
Security tab: Leave defaults
-
Tags tab: Apply standard tags per
tags.*config paths -
Review + create: Verify settings → Click Create
Validation
- VNet created in the Connectivity subscription and resource group
- All four subnets visible under the VNet
- Address space matches config
- GatewaySubnet has no NSG attached
Links
Azure CLI / PowerShell
When to use: Scripted Azure operations from management workstation or pipeline — config-driven via
variables.yml
The orchestrated script is identical to the Single Subscription version. The variables.yml is pre-populated with the correct Connectivity subscription and resource group for your CAF/WAF landing zone. No code change required.
Script
Primary: scripts/deploy/02-azure-foundation/phase-04-azure-management-infrastructure/task-01-virtual-network/powershell/New-VirtualNetwork.ps1
See the Single Subscription → Azure CLI / PowerShell tab above for the full script. The only difference is the values in variables.yml.
Validation
# Verify VNet in Connectivity subscription
$vnet = Get-AzVirtualNetwork -Name $VNetName -ResourceGroupName $ResourceGroup
$vnet | Format-List Name, ResourceGroupName, Location, AddressSpace
Standalone Script
When to use: Copy-paste ready script — edit the CONFIGURATION block for CAF/WAF naming patterns.
Code
# ============================================================================
# Script: New-VirtualNetwork-Standalone.ps1
# Execution: Run anywhere — fully self-contained (CAF/WAF Landing Zone)
# Prerequisites: Az.Network module, authenticated to Azure
# ============================================================================
#Requires -Modules Az.Network, Az.Resources
#region CONFIGURATION
# ── CAF/WAF Landing Zone values ──────────────────────────────────────────────
$SubscriptionId = "00000000-0000-0000-0000-000000000000" # Connectivity subscription ID
$ResourceGroup = "rg-azrlconn-azl-eus-01" # Connectivity resource group
$VNetName = "vnet-azrl-azl-eus-01" # Virtual network name
$Location = "eastus" # Azure region
$AddressSpace = "10.250.1.0/24" # VNet address space
# Subnet definitions (same as single-sub model)
$GatewaySubnetCidr = "10.250.1.0/27" # GatewaySubnet
$MgmtSubnetName = "snet-azrl-azl-eus-01" # Management subnet name
$MgmtSubnetCidr = "10.250.1.32/27" # Management subnet CIDR
$BastionSubnetCidr = "10.250.1.64/26" # AzureBastionSubnet
$EndpointsSubnetName = "snet-endpoints-azl-eus-01" # Endpoints subnet name
$EndpointsSubnetCidr = "10.250.1.128/27" # Endpoints CIDR
#endregion CONFIGURATION
# Set subscription context
Set-AzContext -SubscriptionId $SubscriptionId | Out-Null
# Build subnet configurations
$subnetConfigs = @(
New-AzVirtualNetworkSubnetConfig -Name "GatewaySubnet" -AddressPrefix $GatewaySubnetCidr
New-AzVirtualNetworkSubnetConfig -Name $MgmtSubnetName -AddressPrefix $MgmtSubnetCidr
New-AzVirtualNetworkSubnetConfig -Name "AzureBastionSubnet" -AddressPrefix $BastionSubnetCidr
New-AzVirtualNetworkSubnetConfig -Name $EndpointsSubnetName -AddressPrefix $EndpointsSubnetCidr
)
# Create VNet
Write-Host "Creating VNet: $VNetName in Connectivity subscription" -ForegroundColor Cyan
$vnet = New-AzVirtualNetwork `
-Name $VNetName `
-ResourceGroupName $ResourceGroup `
-Location $Location `
-AddressPrefix $AddressSpace `
-Subnet $subnetConfigs
Write-Host "✅ VNet '$VNetName' created successfully" -ForegroundColor Green
# Verify
$vnet.Subnets | Format-Table Name, AddressPrefix
This script is completely self-contained. Edit the #region CONFIGURATION block for your CAF/WAF Connectivity subscription values.
Validation
- VNet created in the Connectivity subscription resource group
- All four subnets present with correct CIDRs
- Address space does not conflict with on-premises or other VNets
- GatewaySubnet has no NSG attached
Troubleshooting
| Issue | Root Cause | Remediation |
|---|---|---|
| Address space overlaps | Conflict with existing VNet or on-prem range | Choose non-overlapping CIDR from Planning & Discovery |
| Subnet creation fails | Address prefix outside VNet address space | Verify subnet CIDRs fit within VNet CIDR |
| GatewaySubnet too small | Less than /27 | Use /27 minimum for VPN Gateway |
| AzureBastionSubnet too small | Less than /26 | Use /26 minimum for Azure Bastion |
| Permission denied | Missing Network Contributor role | Verify RBAC from Phase 03 |
Navigation
| Previous | Up | Next |
|---|---|---|
| Manual Deployment Index | Manual Deployment Index | Task 02: VPN Gateway |
Version Control
- Created: 2025-09-15 by Hybrid Cloud Solutions
- Last Updated: 2026-03-03 by Hybrid Cloud Solutions
- Version: 4.0.0
- Tags: azure-local, virtual-network, subnets, networking, management-infrastructure
- Keywords: virtual network, VNet, subnets, GatewaySubnet, AzureBastionSubnet, IP addressing
- Author: Hybrid Cloud Solutions