Azure / enterprise-azure-policy-as-code

Enterprise-ready Azure Policy-as-Code (PaC) solution (includes Az DevOps pipeline)
https://azure.github.io/enterprise-azure-policy-as-code/
MIT License
412 stars 218 forks source link

Invalid Policy entry referenced in Policy Set #350

Closed glsutter closed 1 year ago

glsutter commented 1 year ago

I am creating a policy set (legacy-network-guardrails) that includes two policies:

But Build-DeploymentPlan keeps throwing thw error below.

I can see earlier in the output that the new policies are recognized: New 'Require a specific NSG on every subnet' New 'Restrict Source IPs in NSG Inbound Rules'

After some debugging, it appears that the the policy isn't present in the AllDefinitions hashtable passed to Confirm-PolicyDefinitionUsedExists. But I could be wrong about that, just my initial observation.

I'm inserting my policy set definition file and the two policy definition files below. Wondering if I have a typo somewhere?

Write-Error: /builds/xcloud/azure/elz-epac/Scripts/Helpers/Build-PolicySetPolicyDefinitionIds.ps1:45
Line |
  45 |              $policyId = Confirm-PolicyDefinitionUsedExists `
     |                          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     |     Policy
     | '/providers/Microsoft.Authorization/policyDefinitions/require-nsg-on-subnet' not found.
Write-Error: /builds/xcloud/azure/elz-epac/Scripts/Deploy/Build-DeploymentPlans.ps1:136
Line |
 136 |  Build-PolicySetPlan `
     |  ~~~~~~~~~~~~~~~~~~~~~
     | Legacy subscription network guardrails: One or more invalid
     | Policy entries referenced in Policy Set 'Legacy subscription
     | network guardrails' from 'legacy-network-guardrails.jsonc'.

Cleaning up project directory and file based variables
00:02
ERROR: Job failed: exit code 1

Policy Set Definition { "name": "legacy-network-guardrails", "properties": { "displayName": "Legacy subscription network guardrails", "description": "This initiative contains policies that require a specific NSG on subnets and allow only certain inbound source IPs", "metadata": { "version": "1.0.0", "category": "Network" }, "parameters": { "rgName": { "type": "String", "defaultValue": "nsg-rg" }, "nsgName": { "type": "String", "defaultValue": "Baseline-NSG" }, "allowedIPRanges": { "type": "Array", "defaultValue": [ "129.83.0.0/16", "128.29.0.0/16" ] } }, "PolicyDefinitions": [ { "policyDefinitionReferenceId": "require-nsg-on-subnet", "policyDefinitionId": "/providers/Microsoft.Authorization/policyDefinitions/require-nsg-on-subnet", "parameters": { "nsgName": { "value": "[parameters('nsgName')]" }, "rgName": { "value": "[parameters('rgName')]" } } }, { "policyDefinitionReferenceId": "restrict-nsg-inbound-ips", "policyDefinitionId": "/providers/Microsoft.Authorization/policyDefinitions/restrict-nsg-inbound-ips", "parameters": { "allowedIPRanges": { "value": "[parameters('allowedIPRanges')]" } } } ] } }

Policy 1 { "name": "require-nsg-on-subnet", "properties": { "policyType": "Custom", "displayName": "Require a specific NSG on every subnet", "description": "This policy enforces a specific NSG on every subnet", "mode": "All", "metadata": { "version": "1.0.0", "category": "Network", "pedigree": "See Community-Policy c8178b2d-ab54-4c43-9620-7a2aa854049e" }, "parameters": { "rgName": { "type": "String", "metadata": { "description": "Name of the resource group containing the NSG", "displayName": "Resource group name" }, "defaultValue": "nsg-rg" }, "nsgName": { "type": "String", "metadata": { "description": "Name of the Network Security Group", "displayName": "NSG Name" } } }, "policyRule": { "if": { "anyOf": [ { "allOf": [ { "field": "type", "equals": "Microsoft.Network/virtualNetworks" }, { "not": { "field": "Microsoft.Network/virtualNetworks/subnets[*].networkSecurityGroup.id", "equals": "[concat(subscription().id, '/resourceGroups/', parameters('rgName'), '/providers/Microsoft.Network/networkSecurityGroups/',parameters('nsgName'))]" } } ] }, { "allOf": [ { "field": "type", "equals": "Microsoft.Network/virtualNetworks/subnets" }, { "not": { "field": "Microsoft.Network/virtualNetworks/subnets/networkSecurityGroup.id", "equals": "[concat(subscription().id, '/resourceGroups/', parameters('rgName'), '/providers/Microsoft.Network/networkSecurityGroups/',parameters('nsgName'))]" } } ] } ] }, "then": { "effect": "deny" } } } }

Policy 2 { "name": "restrict-nsg-inbound-ips", "properties": { "policyType": "Custom", "displayName": "Restrict Source IPs in NSG Inbound Rules", "description": "This policy restricts source IPs in NSG inbound rules to a specific set of allowed IPs or CIDRs", "mode": "All", "metadata": { "version": "1.0.0", "category": "Network", "pedigree": "See Community-Policy 995ee9de-5f92-40bd-a795-696323068dff" }, "parameters": { "destinationPort": { "type": "Array", "metadata": { "displayName": "destinationPort", "description": null }, "default": "" }, "allowedIPRanges": { "type": "Array", "metadata": { "displayName": "allowedIPRanges", "description": null } }, "effect": { "type": "String", "metadata": { "displayName": "Effect", "description": "Deny, Audit or Disabled the execution of the Policy" }, "allowedValues": [ "Deny", "Audit", "Disabled" ], "defaultValue": "Deny" } }, "policyRule": { "if": { "allOf": [ { "field": "type", "equals": "Microsoft.Network/networkSecurityGroups/securityRules" }, { "field": "Microsoft.Network/networkSecurityGroups/securityRules/access", "equals": "Allow" }, { "field": "Microsoft.Network/networkSecurityGroups/securityRules/direction", "equals": "Inbound" }, { "anyOf": [ { "count": { "value": "[parameters('allowedIPRanges')]", "name": "allowedIPRanges", "where": { "value": "[if(empty(field('Microsoft.Network/networkSecurityGroups/securityRules/sourceAddressPrefix')), bool('true'), ipRangeContains(current('allowedIPRanges'), if(or(greaterOrEquals(first(field('Microsoft.Network/networkSecurityGroups/securityRules/sourceAddressPrefix')), 'a'), equals(field('Microsoft.Network/networkSecurityGroups/securityRules/sourceAddressPrefix'), '')), current('allowedIPRanges'), field('Microsoft.Network/networkSecurityGroups/securityRules/sourceAddressPrefix'))))]", "equals": false } }, "equals": "[length(parameters('allowedIPRanges'))]" }, { "count": { "field": "Microsoft.Network/networkSecurityGroups/securityRules/sourceAddressPrefixes[]", "where": { "count": { "value": "[parameters('allowedIPRanges')]", "name": "allowedIPRanges", "where": { "value": "[ipRangeContains(current('allowedIPRanges'), first(field('Microsoft.Network/networkSecurityGroups/securityRules/sourceAddressPrefixes[]')))]", "equals": true } }, "greater": 0 } }, "notEquals": "[length(field('Microsoft.Network/networkSecurityGroups/securityRules/sourceAddressPrefixes[]'))]" }, { "field": "Microsoft.Network/networkSecurityGroups/securityRules/sourceAddressPrefix", "equals": "" }, { "field": "Microsoft.Network/networkSecurityGroups/securityRules/sourceAddressPrefix", "equals": "Internet" } ] }, { "count": { "value": "[parameters('destinationPort')]", "name": "destinationPort", "where": { "anyOf": [ { "value": "[if(empty(field('Microsoft.Network/networkSecurityGroups/securityRules/destinationPortRange')), bool('false'), if(contains(field('Microsoft.Network/networkSecurityGroups/securityRules/destinationPortRange'), ''), bool('true'), and(greaterOrEquals(int(current('destinationPort')), int(first(split(field('Microsoft.Network/networkSecurityGroups/securityRules/destinationPortRange'), '-')))), lessOrEquals(int(current('destinationPort')), int(last(split(field('Microsoft.Network/networkSecurityGroups/securityRules/destinationPortRange'), '-')))))))]", "equals": true }, { "count": { "field": "Microsoft.Network/networkSecurityGroups/securityRules/destinationPortRanges[]", "where": { "value": "[if(empty(field('Microsoft.Network/networkSecurityGroups/securityRules/destinationPortRanges[]')), bool('false'), if(contains(string(field('Microsoft.Network/networkSecurityGroups/securityRules/destinationPortRanges[]')), ''), bool('true'), and(greaterOrEquals(int(current('destinationPort')), int(first(split(substring(string(field('Microsoft.Network/networkSecurityGroups/securityRules/destinationPortRanges[]')), 2, sub(length(string(field('Microsoft.Network/networkSecurityGroups/securityRules/destinationPortRanges[]'))), 4)), '-')))), lessOrEquals(int(current('destinationPort')), int(last(split(substring(string(field('Microsoft.Network/networkSecurityGroups/securityRules/destinationPortRanges[]')), 2, sub(length(string(field('Microsoft.Network/networkSecurityGroups/securityRules/destinationPortRanges[*]'))), 4)), '-')))))))]", "equals": true } }, "greater": 0 } ] } }, "greater": 0 } ] }, "then": { "effect": "[parameters('effect')]" } } } }

techlake commented 1 year ago

Did EPAC deploy the custom Policy?

Yes, did you use "policyDefinitionName " in the Policy set


{
    "policyDefinitionReferenceId": "require-nsg-on-subnet",
     "policyDefinitionName": "require-nsg-on-subnet",
     "parameters": {
            "effect": {
                 "value": "[parameters('effect- require-nsg-on-subnet')]"
            }
      }
 },

If no, same problem
glsutter commented 1 year ago

I was using policyDefinitionId, but I changed it to policyDefinitionName. But the problem is still there. Doing some debugging to see if it's actually being found and an entry created in the PowerShell.

glsutter commented 1 year ago

I may have found the problem, but I'm not sure why it's occurring. In Build-PolicySetPlan.ps1, policyDefinitionScopes looks a little strange:

Screenshot 2023-09-07 at 3 41 24 PM

techlake commented 1 year ago

YOU MUST USE "policyDefinitionName" for custom Policies when assigning them or including them in a Policy SET (Initiative). The below is correct:

From: glsutter @.> Sent: Thursday, September 7, 2023 2:44 PM To: Azure/enterprise-azure-policy-as-code @.> Cc: Comment @.>; Subscribed @.> Subject: Re: [Azure/enterprise-azure-policy-as-code] Invalid Policy entry referenced in Policy Set (Issue #350)

I may have found the problem, but I'm not sure why it's occurring. In Build-PolicySetPlan.ps1, policyDefinitionScopes looks a little strange:

[Screenshot 2023-09-07 at 3 41 24 PM] - Reply to this email directly, view it on GitHub or unsubscribe. You are receiving this email because you commented on the thread. Triage notifications on the go with GitHub Mobile for iOS or Android.
glsutter commented 1 year ago

Thanks, Heinrich. That was the problem. For the two custom policies, I was using a full policy definition resource id instead of the simple name.