AVNM Security Admin Rules in the Real World

Guardrails that don’t get in your way

When it comes to using Security Admin Rules in AVNM, the most common question I hear is this:

“How do I actually use AVNM’s security admin rules to improve my organisation’s network security posture without breaking apps or creating policy gridlock?”

That’s where AVNM Security Admin Rules shine. These aren’t your old-school NSGs rebadged. Think of them as centralised enforcement points that help you lock down traffic behaviour across your network estate with surgical intent.

In this post, you’ll learn how AVNM security rules actually work, how they play with NSGs, where to apply them, and a few patterns that’ll keep your auditors happy and your apps unbroken.

What Do AVNM Security Admin Rules Actually Do?

Security Admin Rules sit above your NSGs in the evaluation flow. They’re designed for:

  • Org-wide guardrails
  • Environment-level isolation
  • Clean separation between network security policy and application-level NSGs

They define:

  • Direction: inbound or outbound
  • Protocol: TCP, UDP, or all
  • IP ranges or prefixes: typically service endpoints or outbound limits
  • Allow, Deny behaviour — and “deny” means deny, no matter your NSG

They’re ideal for enforcing egress lockdowns, VNet segmentation, and that sweet combo of zero trust and operational sanity.

AVNM vs NSG: Rule Evaluation Order Matters

AVNM Security Admin Rules don’t replace NSGs — they precede them.

AVNM Security Rule Evaluation Flow

The following diagram shows how traffic is evaluated by AVNM Security Admin Rules before any NSG rules or UDRs are applied.

%% AVNM + NSG Rule Evaluation Order flowchart TD A[Network Traffic] --> B{AVNM Admin Rules} B -- Deny --> X[Blocked Immediately] B -- Allow --> C{Network Security Groups} C -- Deny --> X C -- Allow --> D[Route Table Evaluation] D --> E[Traffic Delivered]

Order of operations

  1. AVNM evaluates first
  2. If traffic is DENIED by AVNM, it’s blocked outright
  3. If it’s ALLOWED by AVNM, then NSGs still apply
  4. Only if NSG allows it too, does traffic proceed

This lets you set org-level no-go zones (e.g. “no internet access from dev VNets”) and still allow service-specific access via NSGs.

Use Case Patterns

Here are some brewed-in-the-wild patterns that work:

1. Dev/Test Egress Lockdown

Use AVNM to deny all outbound except key services:

 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
// Deny all outbound traffic
resource DenyOutboundRule 'Microsoft.Network/networkManagers/securityAdminConfigurations/ruleCollections/rules@2024-05-01' = {
  parent: SecurityRuleCollection
  name: 'DenyAllOutbound'
  kind: 'Custom'
  properties: {
    description: 'Deny All outbound traffic'
    protocol: '*'
    direction: 'Outbound'
    sourcePortRanges: ['0-65535']
    destinations: [
      {
        addressPrefixType: 'IPPrefix'
        addressPrefix: '*'
      }
    ]
    destinationPortRanges: ['0-65535']
    access: 'Deny'
    priority: 100
  }
}
  
// Allow DNS to Azure resolver
resource AllowDNSRule 'Microsoft.Network/networkManagers/securityAdminConfigurations/ruleCollections/rules@2024-05-01' = {
  parent: SecurityRuleCollection
  name: 'AllowDNS'
  kind: 'Custom'
  properties: {
    description: 'Allow outbound DNS traffic'
    protocol: 'UDP'
    direction: 'Outbound'
    sourcePortRanges: ['0-65535']
    destinations: [
      {
        addressPrefixType: 'IPPrefix'
        addressPrefix: '168.63.129.16'
      }
    ]
    destinationPortRanges: ['53']
    access: 'Allow'
    priority: 200
  }
}

Great for Dev/Test environments that shouldn’t be calling home or downloading packages outside approved endpoints.

2. Production Outbound Allow-list

Rather than deny-first, define only what’s allowed:

  • Allow outbound to Windows Update (20.190.128.0/18, Azure FrontDoor Frontend & Backend)
  • Allow CRL/OCSP traffic
  • Allow Azure AD, DNS, logging endpoints
  • Deny everything else

Helps enforce compliance while keeping patching and identity flows running.

3. Prevent Cross-Environment Access

Use rule scoping + group segmentation to stop VNet-to-VNet traffic between tiers:

  • Create a rule collection that explicitly denies traffic between:
    • Dev <-> Prod VNets
    • Non-critical apps <-> Core internal services

This avoids blind spots caused by transit rules baked into peerings or NSG misconfigurations.

Built-In vs Custom Rules

AVNM supports both Microsoft-managed built-in rule sets (e.g. common DNS/DHCP firewall baselines) and custom rule collections.

Built-in rules are currently limited in scope and can’t be modified, but might grow in the future. For now, most orgs stick to custom rule sets for policy enforcement.

  • Built-in: Good starting point, but you can’t customise them
  • Custom: Maximum control, required for serious policy enforcement

When in doubt, start with built-in deployment in ReadOnly mode to see its effect. Then grow into custom security rule sets over time.

Designing for Real-World Impact

Before you go full lockdown and set ten thousand fire rules ablaze, slow down and consider:

  • ReadOnly Mode: AVNM supports starting with rule simulations — always test before deploying hard Deny
  • Flow Logs: Keep NSG flow logs turned on during rollout to verify what’s really happening on the wire
  • Monitoring: Use Azure Monitor with AVNM diagnostic settings to keep an eye on rule enforcement and drift
  • Deploy Incrementally: Avoid rolling out to every region from day one — start with one or two controlled environments

Gotchas & Edge Cases

  • No FQDNs: AVNM rules can’t match domains — only IPs or CIDR prefixes. Use IP ranges and service tags where possible.
  • Rule Priorities: Numbering matters — AVNM rules use priority ordering, just like NSGs. Lower number = higher priority.
  • Implicit Deny at the End: Unspecified traffic is dropped by default.
  • Overlapping Rules: A VNet in two Network Groups with conflicting rules will still get both sets evaluated. Be deliberate with group design.

Bicep Example: Custom Admin Rule Collection

Here’s how to define an AVNM Security Admin Configuration and a rule collection in Bicep:

  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
@description('Location for all resources')
param location string = resourceGroup().location

@description('Name of the Network Manager')
param networkManagerName string = 'myNetworkManager'

// Create the Azure Virtual Network Manager (AVNM)
resource avnm 'Microsoft.Network/networkManagers@2024-07-01' = {
  name: networkManagerName
  location: location
  properties: {
    networkManagerScopeAccesses: ['Connectivity', 'SecurityAdmin']
    networkManagerScopes: {
      subscriptions: [subscription().id]
    }
  }
}

// Dynamic Network Group
resource avnmDevGroup 'Microsoft.Network/networkManagers/networkGroups@2024-07-01' = {
  parent: avnm
  name: 'dev-vnets'
  properties: {
    description: 'Development VNets tagged environment=development'
    dynamicMembershipDefinition: {
      criteria: [
        {
          memberType: 'Microsoft.Network/virtualNetworks'
          field: 'tag.environment'
          operator: 'Equals'
          value: 'development'
        }
      ]
    }
  }
}

// Security Admin Configuration
resource SecureAdminConfig 'Microsoft.Network/networkManagers/securityAdminConfigurations@2024-05-01' = {
  parent: avnm
  name: 'prod-security-admin'
  properties: {
    appliesToGroups: [
      {
        networkGroupId: avnmDevGroup.id
      }
    ]
    description: 'Security admin configuration for production VNets'
  }
}

// Security Admin Rule Collection
resource SecurityRuleCollection 'Microsoft.Network/networkManagers/securityAdminConfigurations/ruleCollections@2024-05-01' = {
  parent: SecureAdminConfig
  name: 'prod-egress-rules'
  properties: {
    appliesToGroups: [
      {
        networkGroupId: avnmDevGroup.id
      }
    ]
  }
}

// Security Admin Rule to Deny Outbound Traffic
resource DenyOutboundRule 'Microsoft.Network/networkManagers/securityAdminConfigurations/ruleCollections/rules@2024-05-01' = {
  parent: SecurityRuleCollection
  name: 'DenyAllOutbound'
  kind: 'Custom'
  properties: {
    description: 'Deny All outbound traffic'
    protocol: '*'
    direction: 'Outbound'
    sourcePortRanges: ['0-65535']
    destinations: [
      {
        addressPrefixType: 'IPPrefix'
        addressPrefix: '*'
      }
    ]
    destinationPortRanges: ['0-65535']
    access: 'Deny'
    priority: 100
  }
}
  
// Allow DNS to Azure resolver
resource AllowDNSRule 'Microsoft.Network/networkManagers/securityAdminConfigurations/ruleCollections/rules@2024-05-01' = {
  parent: SecurityRuleCollection
  name: 'AllowDNS'
  kind: 'Custom'
  properties: {
    description: 'Allow outbound DNS traffic'
    protocol: 'UDP'
    direction: 'Outbound'
    sourcePortRanges: ['0-65535']
    destinations: [
      {
        addressPrefixType: 'IPPrefix'
        addressPrefix: '168.63.129.16'
      }
    ]
    destinationPortRanges: ['53']
    access: 'Allow'
    priority: 200
  }
}

// Create Azure Policy for dynamic network group
module avnmDynamicDevNetworkGroup 'avnm-policy-networkgroup.bicep' = {
  scope: subscription()
  name: 'avnm-dynamic-development-network-group-policy'
  params: {
    networkManagerName: networkManagerName
  }
  dependsOn: [
    avnmDevGroup
  ]
}

// Create a Deployment Script resource to perform the commit/deployment of the Network Manager connectivity configuration.
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 to deploy the Security Admin configuration
resource deploymentScriptSecurityAdmin 'Microsoft.Resources/deploymentScripts@2023-08-01' = {
  name: 'DeployAVNMSecurityAdminConfig'
  location: location
  kind: 'AzurePowerShell'
  identity: {
    type: 'UserAssigned'
    userAssignedIdentities: {
      '${userAssignedIdentity.id}': {}
    }
  }
  properties: {
    azPowerShellVersion: '8.3'
    retentionInterval: 'PT1H'
    timeout: 'PT1H'
    arguments: '-networkManagerName "${networkManagerName}" -targetLocations ${location} -configIds ${SecureAdminConfig.id} -subscriptionId ${subscription().subscriptionId} -configType SecurityAdmin -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 $configIds -TargetLocation $targetLocations -CommitType $configType -ErrorAction Stop
    }
    catch {
      Write-Error "Deployment failed with error: $_"
      throw "Deployment failed with error: $_"
    }
    '''
    }
}

Best Practices

  • Start in ReadOnly mode: test your policy impact before enforcing
  • Use separate rule collections: for each environment or use case
  • Stick to clear tagging conventions: for your VNet groups
  • Limit scope per deployment: deploy configurations only where needed
  • Document intent: inline good policy-as-code habits make a big difference two months in
🍺
Brewed Insight:

Security Admin Rules aren’t here to replace NSGs — they’re here to protect you from yourself. Most AVNM value comes from stopping accidental exposure, not catching malicious insiders.

Think of it like this: NSGs are espresso shots per workload — fast, strong, tailored. AVNM rules are the double-walled mug that makes sure it all stays inside the cup.

Brew both well, and you’ll never spill into the wrong subnet again.

Learn More