Picture this: you’re knee-deep in JSON, juggling network peering scripts across dozens of virtual networks, double-checking NSG rules between prod and dev. One rogue IP rule and suddenly someone’s staging environment is blocking critical telemetry. Sound familiar? That’s the smell of burnt-out engineers and overcooked infrastructure.
Enter Azure Virtual Network Manager (AVNM) your new best mate when it comes to sorting out network complexity, without losing sight of policy or scalability. This blog series breaks down what it is, why you’ll want it in your toolbox, and how it’s changing the game for Azure environments with more than a few VNets to their name.
The Problem: Too Many VNets, Not Enough Control
Before AVNM, managing network topology and security rules across large environments was… let’s say “hands-on”:
- Manual VNet peering across subscriptions or regions is error-prone and hard to scale
- Copy-pasting NSGs like it’s 2015 which is inconsistent, hard to audit
- Lack of centralised visibility or enforcement no easy way to ensure a baseline security posture is consistent
- Resource sprawl managing dev, test, and prod with entirely separate rule sets or different peering requirements
The bigger your Azure estate, the more brittle your network governance becomes.
What is Azure Virtual Network Manager (AVNM)?
Azure Virtual Network Manager is a centralised service that lets you orchestrate and enforce network topology and security policies across all your virtual networks—regardless of region or subscription.
Key capabilities:
- Connectivity configuration: Automatically create fully-meshed or hub-and-spoke peering across VNets
- Security admin rules: Define organisation-wide inbound/outbound rules that override individual NSGs
- Scope policies with network groups: Easily apply configs to sets of VNets by tag or name
- Deployment modes: Choose between ‘Connectivity’ and ‘Security Admin’ configuration modes—use either or both
Bottom line: AVNM lets you define once, apply everywhere.
Soundbite Use Cases
Here’s where AVNM goes from nice to have to a absolute weapon:
-
Hub-and-spoke at scale
Automatically set up and maintain peering across hundreds of VNets with a single connectivity config. Perfect for centralised routing models.
-
Multi-region security guardrails
Enforce consistent egress/ingress rules across all VNets no matter what some rogue DevSecOps engineer deploys via Bicep.
-
Dev/test environment firewalls
Apply dev-specific outbound restrictions or block known risky destinations without touching per-VNet NSGs.
Before & After: AVNM’s Impact on Network Management
graph TD
subgraph Before AVNM
A[VNet A]
B[VNet B]
C[VNet C]
NSG1[NSG Copy 1]
NSG2[NSG Copy 2]
NSG3[NSG Copy 3]
A --> B
B --> C
A --> C
A --> NSG1
B --> NSG2
C --> NSG3
end
subgraph After AVNM
AVNM[Azure Virtual Network Manager]
VNet1[VNet A]
VNet2[VNet B]
VNet3[VNet C]
VNet1 --> AVNM
VNet2 --> AVNM
VNet3 --> AVNM
AVNM -->|Peering| VNet1
AVNM -->|Peering| VNet2
AVNM -->|Peering| VNet3
AVNM -->|Admin Rules| VNet1
AVNM -->|Admin Rules| VNet2
AVNM -->|Admin Rules| VNet3
end
AVNM vs Existing Approaches
Feature |
Manual Management |
Azure Virtual Network Manager |
VNet Peering |
Manual, per-VNet |
Auto via Connectivity Config |
NSGs |
Scoped per subnet/VNet |
Global admin rules override |
Multi-region |
DIY pain |
First-class native support |
Auditing |
Custom scripts/logs |
Centralised policy view |
Policy Drift |
High risk |
Low — single source of truth |
Real-World Impact
Teams using AVNM are seeing:
- Faster onboarding of new environments (no more peering scripts)
- Reduced blast radius through enforced isolation policies
- Simplified audits — centralised view of security posture
- Cleaner GitOps — define rules once in code, apply via configuration
- It’s not free — bear in mind AVNM comes at a cost Azure Virtual Network Manager pricing
Implementation Sneak Peek
In the Azure Portal
- Navigate to Azure Virtual Network Manager
- Create a new manager scoped to your management group or subscription
- Define Network Groups and add static vnet members (you can also add dynamic members using tags and Azure Policy)
- Create a Connectivity Configuration for your hub-and-spoke or mesh topology
- Define Security Admin Rules as needed (allow, deny, override NSG rules)
Using Bicep
In the below example we are deploying a Virtual Network Manager with 3 virtual networks (1 Hub and 2 Spokes) then connecting them in a hub-n-spoke configuration set. Then creating a User Assigned Identity and a deployment script to deploy the Connectivity Configuration
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
|
@description('Location for all resources')
param location string = resourceGroup().location
@description('Name of the Network Manager')
param networkManagerName string = 'myNetworkManager'
@description('Configuration type to deploy')
param configType string = 'Connectivity'
// Create AVNM
resource avnm 'Microsoft.Network/networkManagers@2024-07-01' = {
name: networkManagerName
location: location
properties: {
networkManagerScopeAccesses: [
configType
]
networkManagerScopes: {
subscriptions: [
subscription().id
]
}
}
}
// Create Hub VNet
resource hubVnet 'Microsoft.Network/virtualNetworks@2024-07-01' = {
name: 'MyHubVNet'
location: location
properties: {
addressSpace: {
addressPrefixes: [
'10.0.0.0/16'
]
}
}
}
// Create Spoke VNets
resource spokeVnet01 'Microsoft.Network/virtualNetworks@2024-07-01' = {
name: 'MySpokeVNet01'
location: location
properties: {
addressSpace: {
addressPrefixes: [
'10.1.0.0/16'
]
}
}
}
resource spokeVnet02 'Microsoft.Network/virtualNetworks@2024-07-01' = {
name: 'MySpokeVNet02'
location: location
properties: {
addressSpace: {
addressPrefixes: [
'10.2.0.0/16'
]
}
}
}
// Create Network Groups
resource hubGroup 'Microsoft.Network/networkManagers/networkGroups@2024-07-01' = {
parent: avnm
name: 'HubGroup'
properties: {
description: 'Hub VNet group'
}
}
resource spokeGroup 'Microsoft.Network/networkManagers/networkGroups@2024-07-01' = {
parent: avnm
name: 'SpokeGroup'
properties: {
description: 'Spoke VNets group'
}
}
// Add VNets to Network Groups
resource hubGroupMember 'Microsoft.Network/networkManagers/networkGroups/staticMembers@2024-07-01' = {
parent: hubGroup
name: 'HubVNetMember'
properties: {
resourceId: hubVnet.id
}
}
resource spokeGroupMember01 'Microsoft.Network/networkManagers/networkGroups/staticMembers@2024-07-01' = {
parent: spokeGroup
name: 'SpokeVNet01Member'
properties: {
resourceId: spokeVnet01.id
}
}
resource spokeGroupMember02 'Microsoft.Network/networkManagers/networkGroups/staticMembers@2024-07-01' = {
parent: spokeGroup
name: 'SpokeVNet02Member'
properties: {
resourceId: spokeVnet02.id
}
}
// Connectivity Configuration (Hub-and-Spoke)
resource connectivityConfig 'Microsoft.Network/networkManagers/connectivityConfigurations@2024-07-01' = {
parent: avnm
name: 'hubAndSpokeConfig'
properties: {
connectivityTopology: 'HubAndSpoke'
hubs: [
{
resourceId: hubVnet.id
resourceType: 'Microsoft.Network/virtualNetworks'
}
]
appliesToGroups: [
{
groupConnectivity: 'None'
networkGroupId: spokeGroup.id
useHubGateway: 'True'
isGlobal: 'False'
}
]
description: 'Hub-and-spoke connectivity'
}
}
// Creating a User Assigned Identity and giving it the "Network Contributor" Role in my resource group
resource userAssignedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2024-11-30' = {
name: 'avnmDeploymentScriptIdentity'
location: location
}
resource networkContributorRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
name: guid(resourceGroup().id, userAssignedIdentity.id, 'NetworkContributor')
scope: resourceGroup()
properties: {
roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7') // Network Contributor built-in role
principalId: userAssignedIdentity.properties.principalId
principalType: 'ServicePrincipal'
}
dependsOn: [
userAssignedIdentity
]
}
// Create a Deployment Script resource to perform the commit/deployment of the Network Manager connectivity configuration.
resource deploymentScript 'Microsoft.Resources/deploymentScripts@2023-08-01' = {
name: 'DeployAVNMConnectivityConfig'
location: location
kind: 'AzurePowerShell'
identity: {
type: 'UserAssigned'
userAssignedIdentities: {
'${userAssignedIdentity.id}': {}
}
}
properties: {
azPowerShellVersion: '8.3'
retentionInterval: 'PT1H'
timeout: 'PT1H'
arguments: '-networkManagerName "${networkManagerName}" -targetLocations ${location} -configIds ${connectivityConfig.id} -subscriptionId ${subscription().subscriptionId} -configType ${configType} -resourceGroupName ${resourceGroup().name}'
scriptContent: '''
param (
# AVNM subscription id
[parameter(mandatory=$true)][string]$subscriptionId,
# AVNM resource name
[parameter(mandatory=$true)][string]$networkManagerName,
# config ids to deploy
[parameter(mandatory=$true)][string[]]$configIds,
# deployment target region
[parameter(mandatory=$true)][string[]]$targetLocations,
# configuration type to deploy. must be either connectivity or securityadmin
[parameter(mandatory=$true)][ValidateSet('Connectivity','SecurityAdmin')][string]$configType,
# AVNM resource group name
[parameter(mandatory=$true)][string]$resourceGroupName
)
$null = Login-AzAccount -Identity -Subscription $subscriptionId
try {
Deploy-AzNetworkManagerCommit -Name $networkManagerName -ResourceGroupName $resourceGroupName -ConfigurationId $configIdList -TargetLocation $targetLocations -CommitType $configType -ErrorAction Stop
}
catch {
Write-Error "Deployment failed with error: $_"
throw "Deployment failed with error: $_"
}
'''
}
}
|
More implementation examples will be throughout the blog series.
Best Practices
- Start with ReadOnly mode to see the impact of your security rules before enforcing
- Use Tags to dynamically manage Network Groups. This does require you to deploy an Azure Policy but for those in large scale should be well versed with Azure Policy already.
- Test regionally before deploying global configurations
- Treat AVNM like IaC define all configs via Bicep for repeatability
🍺
Brewed Insight: AVNM isn’t just a new product — it’s a shift in how we think about network governance. Put bluntly: if you’re managing more than ten VNets, you’re wasting time without it. We’ve seen teams replace dozens of lines of infra code and hours of config audits with one AVNM deployment.
Do it once, roll it everywhere — just like a good batch brew.
Learn More