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..2ce97780 --- /dev/null +++ b/policyDefinitions/Network/prevent-assignment-of-reserved-cidrs-to-subnets/azurepolicy.json @@ -0,0 +1,162 @@ +{ + "name": "dd573e60-c793-4d20-b170-04fadf4d6298", + "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..99d06b96 --- /dev/null +++ b/policyDefinitions/Network/prevent-assignment-of-reserved-cidrs-to-subnets/azurepolicy.parameters.json @@ -0,0 +1,22 @@ +{ + "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" + } +} \ 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