Azure PowerShell Networking Lab: Create a VNet, Add Subnets, and Lock Down Traffic with NSGs
Azure Lab: Secure App-to-Database Networking with VNets, Subnets, Delegation, and NSGs
Scenario
Contoso Coffee Roasters runs a small on-premises office network and is launching a new cloud ordering system in Azure.
They need:
- A secure private network in Azure for workloads to communicate
- A dedicated subnet for a managed database service
- Tight inbound access controls for any admin connectivity
- Clean structure to expand later without redesigning the network
You will build a VNet, create a subnet, optionally delegate it (for managed database services), and lock it down with an NSG.
Lab Overview
What you will create
- Resource Group:
ContosoRG - Virtual Network:
ContosoVNetwith10.20.0.0/16 - Subnet:
dbSubnetwith10.20.1.0/24 - Delegation:
Microsoft.Sql/managedInstances(optional but included) - NSG:
nsg-Contoso-DBattached todbSubnet - Rule: Allow inbound RDP 3389 from your public IP (demo rule)
Note: In production, you should prefer Azure Bastion over public RDP. This lab uses RDP purely to demonstrate NSG rule behavior.
Prerequisites
- Azure subscription with permissions to create RG, VNet, NSG
- PowerShell + Az module
0) Pre-Lab Setup
0.1 Install and import Az module
Install-Module Az -Scope CurrentUser -Repository PSGallery -Force
Import-Module Az
0.2 Sign in and set subscription context
Connect-AzAccount
Get-AzSubscription | Select-Object Name, Id
Set-AzContext -Subscription "<SUBSCRIPTION_ID>"
1) Create the Resource Group
$location = "Canada Central"
$rgName = "ContosoRG"
New-AzResourceGroup -Name $rgName -Location $location
Validate
Get-AzResourceGroup -Name $rgName
2) Create the Virtual Network (VNet)
Contoso uses a private address space sized for growth:
/16gives room for many future subnets (apps, db, management, integration)
$vnetName = "ContosoVNet"
$vnetCidr = "10.20.0.0/16"
New-AzVirtualNetwork `
-Name $vnetName `
-ResourceGroupName $rgName `
-Location $location `
-AddressPrefix $vnetCidr
Validate
Get-AzVirtualNetwork -Name $vnetName -ResourceGroupName $rgName |
Select-Object Name, Location, @{n="AddressSpace";e={$_.AddressSpace.AddressPrefixes}}
3) Create the Database Subnet
$subnetName = "dbSubnet"
$subnetCidr = "10.20.1.0/24"
$vnet = Get-AzVirtualNetwork -Name $vnetName -ResourceGroupName $rgName
Add-AzVirtualNetworkSubnetConfig `
-Name $subnetName `
-VirtualNetwork $vnet `
-AddressPrefix $subnetCidr
# Commit changes
$vnet | Set-AzVirtualNetwork
Validate
$vnet = Get-AzVirtualNetwork -Name $vnetName -ResourceGroupName $rgName
$vnet.Subnets | Select-Object Name, AddressPrefix
4) Delegate the Subnet (Managed Database Readiness)
Contoso plans to use Azure SQL Managed Instance, which requires subnet delegation.
$vnet = Get-AzVirtualNetwork -Name $vnetName -ResourceGroupName $rgName
$subnet = Get-AzVirtualNetworkSubnetConfig -Name $subnetName -VirtualNetwork $vnet
Add-AzDelegation `
-Name "dbDelegation" `
-ServiceName "Microsoft.Sql/managedInstances" `
-Subnet $subnet
Set-AzVirtualNetwork -VirtualNetwork $vnet
Validate
$vnet = Get-AzVirtualNetwork -Name $vnetName -ResourceGroupName $rgName
($vnet.Subnets | Where-Object Name -eq $subnetName).Delegations |
Select-Object Name, ServiceName
5) Create an NSG for the Database Subnet
$nsgName = "nsg-Contoso-DB"
$nsg = New-AzNetworkSecurityGroup `
-Name $nsgName `
-ResourceGroupName $rgName `
-Location $location
Validate
Get-AzNetworkSecurityGroup -Name $nsgName -ResourceGroupName $rgName |
Select-Object Name, Location
6) Attach the NSG to the Subnet
$vnet = Get-AzVirtualNetwork -Name $vnetName -ResourceGroupName $rgName
$nsg = Get-AzNetworkSecurityGroup -Name $nsgName -ResourceGroupName $rgName
Set-AzVirtualNetworkSubnetConfig `
-Name $subnetName `
-VirtualNetwork $vnet `
-AddressPrefix $subnetCidr `
-NetworkSecurityGroup $nsg
Set-AzVirtualNetwork -VirtualNetwork $vnet
Validate
$vnet = Get-AzVirtualNetwork -Name $vnetName -ResourceGroupName $rgName
($vnet.Subnets | Where-Object Name -eq $subnetName).NetworkSecurityGroup.Id
Expected: NSG resource ID is returned.
7) Add an Inbound Rule (Demo: Allow RDP from Your IP)
7.1 Get your current public IP
$myIp = (Invoke-RestMethod -Uri "https://api.ipify.org?format=json").ip
$myIp
7.2 Add allow rule
$nsg = Get-AzNetworkSecurityGroup -Name $nsgName -ResourceGroupName $rgName
Add-AzNetworkSecurityRuleConfig `
-Name "Allow-RDP-Admin" `
-NetworkSecurityGroup $nsg `
-Protocol "Tcp" `
-Direction "Inbound" `
-Priority 300 `
-SourceAddressPrefix $myIp `
-SourcePortRange "*" `
-DestinationAddressPrefix "*" `
-DestinationPortRange 3389 `
-Access "Allow"
Set-AzNetworkSecurityGroup -NetworkSecurityGroup $nsg
Validate
(Get-AzNetworkSecurityGroup -Name $nsgName -ResourceGroupName $rgName).SecurityRules |
Where-Object Name -eq "Allow-RDP-Admin" |
Select-Object Name, Priority, Direction, Protocol, SourceAddressPrefix, DestinationPortRange, Access
8) Recommended โReal Worldโ Rule Set (Optional Upgrade)
If you want a cleaner, production-like DB subnet posture:
- Remove public admin rules
- Allow only traffic from an appSubnet (10.20.2.0/24)
- Deny everything else inbound
If you want this version, tell me and Iโll provide the exact rules and priorities.
9) Troubleshooting Checklist
Subnet changes donโt appear
You likely forgot to commit:
Set-AzVirtualNetwork -VirtualNetwork $vnet
Delegation missing
Re-fetch the VNet and re-check delegation after applying updates.
Rule exists but connectivity fails
- The destination resource must exist and be reachable (VM NIC, public IP, OS firewall)
- Your public IP may have changed
- Check effective security rules on the NIC and subnet (Portal: VM NIC โ Effective security rules)
10) Cleanup (Avoid Charges)
Remove-AzResourceGroup -Name $rgName -Force
