From 635fef1680dcc6ec2f85052e4508469f6b3fb32d Mon Sep 17 00:00:00 2001 From: Rhyan <7413853+MrCaedes@users.noreply.github.com> Date: Fri, 9 Jan 2026 15:14:12 +0000 Subject: [PATCH 1/3] Prevent Assignment of Reserved CIDRs to Subnets Addition of new policy definition under /Network, which facilitates blocking the use of reserved ranges - ideal in enterprise environments where ranges have/are being reserved for specific use-cases. Users can leverage exemptions or exclusions to facilitate subnet deployment; if Azure Policy becomes identity aware in the future, too, there is room for platform-team exclusions, etc. --- .../README.md | 43 +++++ .../azurepolicy.json | 162 ++++++++++++++++++ .../azurepolicy.parameters.json | 21 +++ .../azurepolicy.rules.json | 127 ++++++++++++++ 4 files changed, 353 insertions(+) create mode 100644 policyDefinitions/Network/prevent-assignment-of-reserved-cidrs-to-subnets/README.md create mode 100644 policyDefinitions/Network/prevent-assignment-of-reserved-cidrs-to-subnets/azurepolicy.json create mode 100644 policyDefinitions/Network/prevent-assignment-of-reserved-cidrs-to-subnets/azurepolicy.parameters.json create mode 100644 policyDefinitions/Network/prevent-assignment-of-reserved-cidrs-to-subnets/azurepolicy.rules.json diff --git a/policyDefinitions/Network/prevent-assignment-of-reserved-cidrs-to-subnets/README.md b/policyDefinitions/Network/prevent-assignment-of-reserved-cidrs-to-subnets/README.md new file mode 100644 index 00000000..5ce6d5e2 --- /dev/null +++ b/policyDefinitions/Network/prevent-assignment-of-reserved-cidrs-to-subnets/README.md @@ -0,0 +1,43 @@ +# Prevent Assignment of Reserved CIDRs to Subnets +In enterprise environments with centralized IP Address Management (IPAM), it is critical to prevent subnets from being assigned address ranges that overlap with reserved or protected CIDR blocks. This policy ensures that subnets cannot use IP ranges that have been designated for specific purposes such as on-premises connectivity, shared services, or future expansion. + +This policy leverages the `ipRangeContains` function to perform bidirectional overlap detection—checking whether the subnet's address range is contained within a restricted CIDR, or if the subnet's range contains a restricted CIDR. This comprehensive approach prevents both direct conflicts and supernet/subnet overlaps. + +## How It Works +The policy evaluates two resource types: +- **Microsoft.Network/virtualNetworks** - Checks all subnets defined within a VNet resource +- **Microsoft.Network/virtualNetworks/subnets** - Checks standalone subnet resources + +For each subnet, the policy examines both: +- `addressPrefix` - Single address prefix property +- `addressPrefixes` - Array of address prefixes (for dual-stack or multi-prefix scenarios) + +## Parameters +| Parameter | Type | Description | Default | +|-----------|------|-------------|---------| +| `restrictedCIDRs` | Array | Array of CIDR ranges that subnets cannot overlap with (e.g., `['10.0.0.0/8', '172.16.0.0/12']`) | Required | +| `effect` | String | The effect of the policy: `Audit`, `Deny`, or `Disabled` | `Deny` | + +## Use Cases +- **Protecting on-premises address space** - Prevent Azure subnets from overlapping with corporate network ranges routed via ExpressRoute or VPN +- **Reserving ranges for shared services** - Ensure specific CIDR blocks remain available for hub networks, DNS, or other shared infrastructure +- **Compliance with IPAM policies** - Enforce organizational IP allocation standards across all subscriptions + +# Deployment Options +The below sections provide examples of how this can be deployed - please note, when utilising the "Deploy to Azure" button, some properties are ignored by the portal (e.g. non-compliance message). This will need to be manually filled. + +## Deploy via Portal +[![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#blade/Microsoft_Azure_Policy/CreatePolicyDefinitionBlade/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FCommunity-Policy%2Fmaster%2FpolicyDefinitions%2FNetwork%2Fprevent-assignment-of-reserved-cidrs-to-subnets%2Fazurepolicy.json) + +## Deploy via PowerShell +```PowerShell +$definition = New-AzPolicyDefinition -Name "prevent-assignment-of-reserved-cidrs-to-subnets" -DisplayName "Prevent assignment of reserved CIDRs to subnets" -Description "This policy prevents subnets from being assigned address ranges that overlap with specified reserved CIDR ranges." -Policy 'https://raw.githubusercontent.com/Azure/Community-Policy/master/policyDefinitions/Network/prevent-assignment-of-reserved-cidrs-to-subnets/azurepolicy.json' -Mode All +$assignment = New-AzPolicyAssignment -Name -Scope -PolicyDefinition $definition -PolicyParameterObject @{"restrictedCIDRs"=@("10.0.0.0/8","172.16.0.0/12")} +``` + +## Deploy via Az CLI +```cli +az policy definition create --name 'prevent-assignment-of-reserved-cidrs-to-subnets' --display-name 'Prevent assignment of reserved CIDRs to subnets' --description 'This policy prevents subnets from being assigned address ranges that overlap with specified reserved CIDR ranges.' --rules 'https://raw.githubusercontent.com/Azure/Community-Policy/master/policyDefinitions/Network/prevent-assignment-of-reserved-cidrs-to-subnets/azurepolicy.json' --mode All + +az policy assignment create --name --scope --policy "prevent-assignment-of-reserved-cidrs-to-subnets" --params '{"restrictedCIDRs":{"value":["10.0.0.0/8","172.16.0.0/12"]}}' +``` \ No newline at end of file diff --git a/policyDefinitions/Network/prevent-assignment-of-reserved-cidrs-to-subnets/azurepolicy.json b/policyDefinitions/Network/prevent-assignment-of-reserved-cidrs-to-subnets/azurepolicy.json new file mode 100644 index 00000000..2e006997 --- /dev/null +++ b/policyDefinitions/Network/prevent-assignment-of-reserved-cidrs-to-subnets/azurepolicy.json @@ -0,0 +1,162 @@ +{ + "name": "prevent-assignment-of-reserved-cidrs-to-subnets", + "type": "Microsoft.Authorization/policyDefinitions", + "properties": { + "displayName": "Prevent assignment of reserved CIDRs to subnets", + "description": "This policy prevents subnets from being assigned address ranges that overlap with specified reserved CIDR ranges. It checks both VNet-level subnet definitions and standalone subnet resources to ensure no overlap occurs with restricted IP ranges.", + "metadata": { + "category": "Network", + "version": "1.0.0" + }, + "mode": "All", + "parameters": { + "restrictedCIDRs": { + "type": "Array", + "metadata": { + "displayName": "Restricted CIDR Ranges", + "description": "Array of CIDR ranges that subnets cannot overlap with (e.g., ['10.0.0.0/8', '172.16.0.0/12'])" + } + }, + "effect": { + "type": "String", + "metadata": { + "displayName": "Effect", + "description": "Enable or disable the execution of the policy" + }, + "allowedValues": [ + "Audit", + "Deny", + "Disabled" + ], + "defaultValue": "Deny" + } + }, + "policyRule": { + "if": { + "anyOf": [ + { + "allOf": [ + { + "field": "type", + "equals": "Microsoft.Network/virtualNetworks" + }, + { + "count": { + "field": "Microsoft.Network/virtualNetworks/subnets[*]", + "where": { + "anyOf": [ + { + "count": { + "value": "[parameters('restrictedCIDRs')]", + "name": "restrictedCIDR", + "where": { + "anyOf": [ + { + "value": "[ipRangeContains(current('restrictedCIDR'), if(empty(current('Microsoft.Network/virtualNetworks/subnets[*].addressPrefix')), '0.0.0.0/32', current('Microsoft.Network/virtualNetworks/subnets[*].addressPrefix')))]", + "equals": true + }, + { + "value": "[ipRangeContains(if(empty(current('Microsoft.Network/virtualNetworks/subnets[*].addressPrefix')), '0.0.0.0/32', current('Microsoft.Network/virtualNetworks/subnets[*].addressPrefix')), current('restrictedCIDR'))]", + "equals": true + } + ] + } + }, + "greater": 0 + }, + { + "count": { + "field": "Microsoft.Network/virtualNetworks/subnets[*].addressPrefixes[*]", + "where": { + "count": { + "value": "[parameters('restrictedCIDRs')]", + "name": "restrictedCIDR", + "where": { + "anyOf": [ + { + "value": "[ipRangeContains(current('restrictedCIDR'), current('Microsoft.Network/virtualNetworks/subnets[*].addressPrefixes[*]'))]", + "equals": true + }, + { + "value": "[ipRangeContains(current('Microsoft.Network/virtualNetworks/subnets[*].addressPrefixes[*]'), current('restrictedCIDR'))]", + "equals": true + } + ] + } + }, + "greater": 0 + } + }, + "greater": 0 + } + ] + } + }, + "greater": 0 + } + ] + }, + { + "allOf": [ + { + "field": "type", + "equals": "Microsoft.Network/virtualNetworks/subnets" + }, + { + "anyOf": [ + { + "count": { + "value": "[parameters('restrictedCIDRs')]", + "name": "restrictedCIDR", + "where": { + "anyOf": [ + { + "value": "[ipRangeContains(current('restrictedCIDR'), if(empty(field('Microsoft.Network/virtualNetworks/subnets/addressPrefix')), '0.0.0.0/32', field('Microsoft.Network/virtualNetworks/subnets/addressPrefix')))]", + "equals": true + }, + { + "value": "[ipRangeContains(if(empty(field('Microsoft.Network/virtualNetworks/subnets/addressPrefix')), '0.0.0.0/32', field('Microsoft.Network/virtualNetworks/subnets/addressPrefix')), current('restrictedCIDR'))]", + "equals": true + } + ] + } + }, + "greater": 0 + }, + { + "count": { + "field": "Microsoft.Network/virtualNetworks/subnets/addressPrefixes[*]", + "where": { + "count": { + "value": "[parameters('restrictedCIDRs')]", + "name": "restrictedCIDR", + "where": { + "anyOf": [ + { + "value": "[ipRangeContains(current('restrictedCIDR'), current('Microsoft.Network/virtualNetworks/subnets/addressPrefixes[*]'))]", + "equals": true + }, + { + "value": "[ipRangeContains(current('Microsoft.Network/virtualNetworks/subnets/addressPrefixes[*]'), current('restrictedCIDR'))]", + "equals": true + } + ] + } + }, + "greater": 0 + } + }, + "greater": 0 + } + ] + } + ] + } + ] + }, + "then": { + "effect": "[parameters('effect')]" + } + } + } +} diff --git a/policyDefinitions/Network/prevent-assignment-of-reserved-cidrs-to-subnets/azurepolicy.parameters.json b/policyDefinitions/Network/prevent-assignment-of-reserved-cidrs-to-subnets/azurepolicy.parameters.json new file mode 100644 index 00000000..d38fd731 --- /dev/null +++ b/policyDefinitions/Network/prevent-assignment-of-reserved-cidrs-to-subnets/azurepolicy.parameters.json @@ -0,0 +1,21 @@ +{ + "restrictedCIDRs": { + "type": "Array", + "metadata": { + "displayName": "Restricted CIDR Ranges", + "description": "Array of CIDR ranges that subnets cannot overlap with (e.g., ['10.0.0.0/8', '172.16.0.0/12'])" + } + }, + "effect": { + "type": "String", + "metadata": { + "displayName": "Effect", + "description": "Enable or disable the execution of the policy" + }, + "allowedValues": [ + "Audit", + "Deny" + ], + "defaultValue": "Deny" + } +} \ No newline at end of file diff --git a/policyDefinitions/Network/prevent-assignment-of-reserved-cidrs-to-subnets/azurepolicy.rules.json b/policyDefinitions/Network/prevent-assignment-of-reserved-cidrs-to-subnets/azurepolicy.rules.json new file mode 100644 index 00000000..66d0872d --- /dev/null +++ b/policyDefinitions/Network/prevent-assignment-of-reserved-cidrs-to-subnets/azurepolicy.rules.json @@ -0,0 +1,127 @@ +{ + "if": { + "anyOf": [ + { + "allOf": [ + { + "field": "type", + "equals": "Microsoft.Network/virtualNetworks" + }, + { + "count": { + "field": "Microsoft.Network/virtualNetworks/subnets[*]", + "where": { + "anyOf": [ + { + "count": { + "value": "[parameters('restrictedCIDRs')]", + "name": "restrictedCIDR", + "where": { + "anyOf": [ + { + "value": "[ipRangeContains(current('restrictedCIDR'), if(empty(current('Microsoft.Network/virtualNetworks/subnets[*].addressPrefix')), '0.0.0.0/32', current('Microsoft.Network/virtualNetworks/subnets[*].addressPrefix')))]", + "equals": true + }, + { + "value": "[ipRangeContains(if(empty(current('Microsoft.Network/virtualNetworks/subnets[*].addressPrefix')), '0.0.0.0/32', current('Microsoft.Network/virtualNetworks/subnets[*].addressPrefix')), current('restrictedCIDR'))]", + "equals": true + } + ] + } + }, + "greater": 0 + }, + { + "count": { + "field": "Microsoft.Network/virtualNetworks/subnets[*].addressPrefixes[*]", + "where": { + "count": { + "value": "[parameters('restrictedCIDRs')]", + "name": "restrictedCIDR", + "where": { + "anyOf": [ + { + "value": "[ipRangeContains(current('restrictedCIDR'), current('Microsoft.Network/virtualNetworks/subnets[*].addressPrefixes[*]'))]", + "equals": true + }, + { + "value": "[ipRangeContains(current('Microsoft.Network/virtualNetworks/subnets[*].addressPrefixes[*]'), current('restrictedCIDR'))]", + "equals": true + } + ] + } + }, + "greater": 0 + } + }, + "greater": 0 + } + ] + } + }, + "greater": 0 + } + ] + }, + { + "allOf": [ + { + "field": "type", + "equals": "Microsoft.Network/virtualNetworks/subnets" + }, + { + "anyOf": [ + { + "count": { + "value": "[parameters('restrictedCIDRs')]", + "name": "restrictedCIDR", + "where": { + "anyOf": [ + { + "value": "[ipRangeContains(current('restrictedCIDR'), if(empty(field('Microsoft.Network/virtualNetworks/subnets/addressPrefix')), '0.0.0.0/32', field('Microsoft.Network/virtualNetworks/subnets/addressPrefix')))]", + "equals": true + }, + { + "value": "[ipRangeContains(if(empty(field('Microsoft.Network/virtualNetworks/subnets/addressPrefix')), '0.0.0.0/32', field('Microsoft.Network/virtualNetworks/subnets/addressPrefix')), current('restrictedCIDR'))]", + "equals": true + } + ] + } + }, + "greater": 0 + }, + { + "count": { + "field": "Microsoft.Network/virtualNetworks/subnets/addressPrefixes[*]", + "where": { + "count": { + "value": "[parameters('restrictedCIDRs')]", + "name": "restrictedCIDR", + "where": { + "anyOf": [ + { + "value": "[ipRangeContains(current('restrictedCIDR'), current('Microsoft.Network/virtualNetworks/subnets/addressPrefixes[*]'))]", + "equals": true + }, + { + "value": "[ipRangeContains(current('Microsoft.Network/virtualNetworks/subnets/addressPrefixes[*]'), current('restrictedCIDR'))]", + "equals": true + } + ] + } + }, + "greater": 0 + } + }, + "greater": 0 + } + ] + } + ] + } + ] + }, + "then": { + "effect": "[parameters('effect')]" + } +} \ No newline at end of file From fe89447ed5e01460c020b28c7949870f8644139c Mon Sep 17 00:00:00 2001 From: Rhyan <7413853+MrCaedes@users.noreply.github.com> Date: Fri, 9 Jan 2026 15:15:58 +0000 Subject: [PATCH 2/3] nudge: addition of "Disabled" From `azurepolicy.json`, addition of `Disabled` as a valid parameter. --- .../azurepolicy.parameters.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/policyDefinitions/Network/prevent-assignment-of-reserved-cidrs-to-subnets/azurepolicy.parameters.json b/policyDefinitions/Network/prevent-assignment-of-reserved-cidrs-to-subnets/azurepolicy.parameters.json index d38fd731..99d06b96 100644 --- a/policyDefinitions/Network/prevent-assignment-of-reserved-cidrs-to-subnets/azurepolicy.parameters.json +++ b/policyDefinitions/Network/prevent-assignment-of-reserved-cidrs-to-subnets/azurepolicy.parameters.json @@ -14,7 +14,8 @@ }, "allowedValues": [ "Audit", - "Deny" + "Deny", + "Disabled" ], "defaultValue": "Deny" } From 1d17b1addd71ec85e7fdac0e35096316ac38e13f Mon Sep 17 00:00:00 2001 From: Rhyan <7413853+MrCaedes@users.noreply.github.com> Date: Thu, 15 Jan 2026 03:08:07 +0000 Subject: [PATCH 3/3] Switch Policy Name to Generated GUID https://github.com/Azure/Community-Policy/actions/runs/20856638564/job/60368641573 --- .../azurepolicy.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/policyDefinitions/Network/prevent-assignment-of-reserved-cidrs-to-subnets/azurepolicy.json b/policyDefinitions/Network/prevent-assignment-of-reserved-cidrs-to-subnets/azurepolicy.json index 2e006997..2ce97780 100644 --- a/policyDefinitions/Network/prevent-assignment-of-reserved-cidrs-to-subnets/azurepolicy.json +++ b/policyDefinitions/Network/prevent-assignment-of-reserved-cidrs-to-subnets/azurepolicy.json @@ -1,5 +1,5 @@ { - "name": "prevent-assignment-of-reserved-cidrs-to-subnets", + "name": "dd573e60-c793-4d20-b170-04fadf4d6298", "type": "Microsoft.Authorization/policyDefinitions", "properties": { "displayName": "Prevent assignment of reserved CIDRs to subnets",