Assistance with nsg rule azure policy

Harold Huckaby 0 Reputation points
2024-04-16T20:52:23.46+00:00

Hello, I am having trouble creating an azure policy that adds and modifies default nsg rules if they do not match what is defined in the policy using the deployIfNotExists effect.. I am getting the error that the "deployment definition is invalid" but cannot figure out what the issue is for the life of me. Below is what I have so far for the policy, any help would be greatly appreciated

{
  "mode": "Indexed",
  "policyRule": {
    "if": {
      "equals": "Microsoft.Network/networkSecurityGroups",
      "field": "type"
    },
    "then": {
      "details": {
        "deployment": {
          "properties": {
            "mode": "incremental",
            "parameters": {
              "access": {
                "value": "[parameters('access')]"
              },
              "description": {
                "value": "[parameters('ruledescription')]"
              },
              "destinationAddressPrefix": {
                "value": "[parameters('destinationAddressPrefix')]"
              },
              "destinationPortRange": {
                "value": "[parameters('destinationPortRange')]"
              },
              "direction": {
                "value": "[parameters('direction')]"
              },
              "nsgName": {
                "value": "[field('name')]"
              },
              "priority": {
                "value": "[parameters('priority')]"
              },
              "protocol": {
                "value": "[parameters('protocol')]"
              },
              "rulename": {
                "value": "[parameters('rulename')]"
              },
              "sourceAddressPrefix": {
                "value": "[parameters('sourceAddressPrefix')]"
              },
              "sourcePortRange": {
                "value": "[parameters('sourcePortRange')]"
              }
            },
            "template": {
              "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
              "contentVersion": "1.0.0.0",
              "parameters": {
                "access": {
                  "type": "String"
                },
                "description": {
                  "type": "String"
                },
                "destinationAddressPrefix": {
                  "type": "Array"
                },
                "destinationPortRange": {
                  "type": "Array"
                },
                "direction": {
                  "type": "String"
                },
                "nsgName": {
                  "type": "string"
                },
                "priority": {
                  "type": "Integer"
                },
                "protocol": {
                  "type": "String"
                },
                "rulename": {
                  "type": "String"
                },
                "sourceAddressPrefix": {
                  "type": "Array"
                },
                "sourcePortRange": {
                  "type": "Array"
                }
              },
              "resources": [
                {
                  "apiVersion": "2022-07-01",
                  "properties": {
                    "access": "[parameters('access')]",
                    "description": "[parameters('description')]",
                    "destinationAddressPrefix": "[if(equals(length(parameters('destinationAddressPrefix')),1),parameters('destinationAddressPrefix'),json('null'))]",
                    "destinationAddressPrefixs": "[if(equals(length(parameters('destinationAddressPrefix')),1),json('null'),parameters('destinationAddressPrefix'))]",
                    "destinationPortRange": "[if(equals(length(parameters('destinationPortRange')),1),parameters('destinationPortRange'),json('null'))]",
                    "destinationPortRanges": "[if(equals(length(parameters('destinationPortRange')),1),json('null'),parameters('destinationPortRange'))]",
                    "direction": "[parameters('direction')]",
                    "priority": "[parameters('priority')]",
                    "protocol": "[parameters('protocol')]",
                    "sourceAddressPrefix": "[if(equals(length(parameters('sourceAddressPrefix')),1),parameters('sourceAddressPrefix'),json('null'))]",
                    "sourceAddressPrefixs": "[if(equals(length(parameters('sourceAddressPrefix')),1),json('null'),parameters('sourceAddressPrefix'))]",
                    "sourcePortRange": "[if(equals(length(parameters('sourcePortRange')),1),parameters('sourcePortRange'),json('null'))]",
                    "sourcePortRanges": "[if(equals(length(parameters('sourcePortRange')),1),json('null'),parameters('sourcePortRange'))]"
                  },
                  "rulename": "[concat(parameters('nsgName'),'/',parameters('rulename'))]",
                  "type": "Microsoft.Network/networkSecurityGroups/securityRules"
                }
              ]
            }
          }
        },
        "existenceCondition": {
          "count": {
            "field": "Microsoft.Network/networkSecurityGroups/securityRules[*]",
            "where": {
              "allOf": [
                {
                  "equals": "[parameters('rulename')]",
                  "field": "Microsoft.Network/networkSecurityGroups/securityRules[*].name"
                },
                {
                  "equals": "[parameters('protocol')]",
                  "field": "Microsoft.Network/networkSecurityGroups/securityRules[*].protocol"
                },
                {
                  "anyOf": [
                    {
                      "equals": true,
                      "value": "[equals(field('Microsoft.Network/networkSecurityGroups/securityRules[*].sourcePortRange'), parameters('sourcePortRange'))]"
                    },
                    {
                      "equals": true,
                      "value": "[equals(field('Microsoft.Network/networkSecurityGroups/securityRules[*].sourcePortRanges'), parameters('sourcePortRange'))]"
                    }
                  ]
                },
                {
                  "anyOf": [
                    {
                      "equals": true,
                      "value": "[equals(field('Microsoft.Network/networkSecurityGroups/securityRules[*].destinationPortRange'), parameters('destinationPortRange'))]"
                    },
                    {
                      "equals": true,
                      "value": "[equals(field('Microsoft.Network/networkSecurityGroups/securityRules[*].destinationPortRanges'), parameters('destinationPortRange'))]"
                    }
                  ]
                },
                {
                  "anyOf": [
                    {
                      "equals": true,
                      "value": "[equals(field('Microsoft.Network/networkSecurityGroups/securityRules[*].sourceAddressPrefix'), parameters('sourceAddressPrefix'))]"
                    },
                    {
                      "equals": true,
                      "value": "[equals(field('Microsoft.Network/networkSecurityGroups/securityRules[*].sourceAddressPrefixes'), parameters('sourceAddressPrefix'))]"
                    }
                  ]
                },
                {
                  "anyOf": [
                    {
                      "equals": true,
                      "value": "[equals(field('Microsoft.Network/networkSecurityGroups/securityRules[*].destinationAddressPrefix'), parameters('destinationAddressPrefix'))]"
                    },
                    {
                      "equals": true,
                      "value": "[equals(field('Microsoft.Network/networkSecurityGroups/securityRules[*].destinationAddressPrefixes'), parameters('destinationAddressPrefix'))]"
                    }
                  ]
                },
                {
                  "equals": "[parameters('access')]",
                  "field": "Microsoft.Network/networkSecurityGroups/securityRules[*].access"
                },
                {
                  "equals": "[parameters('priority')]",
                  "field": "Microsoft.Network/networkSecurityGroups/securityRules[*].priority"
                },
                {
                  "equals": "[parameters('direction')]",
                  "field": "Microsoft.Network/networkSecurityGroups/securityRules[*].direction"
                }
              ]
            }
          },
          "notEquals": 0
        },
        "roleDefinitionIds": [
          "/providers/Microsoft.Authorization/roleDefinitions/4d97b98b-1d4f-4787-a291-c67834d212e7"
        ],
        "type": "Microsoft.Network/networkSecurityGroups/securityRules"
      },
      "effect": "[parameters('effect')]"
    }
  },
  "parameters": {
    "access": {
      "type": "String",
      "metadata": {
        "displayName": "access",
        "description": "The network traffic is allowed or denied. - Allow or Deny"
      },
      "defaultValue": "Deny"
    },
    "destinationAddressPrefix": {
      "type": "Array",
      "metadata": {
        "displayName": "destinationAddressPrefix",
        "description": "The destination address prefix. CIDR or destination IP range. Asterisk '*' can also be used to match all source IPs. Default tags such as 'VirtualNetwork', 'AzureLoadBalancer' and 'Internet' can also be used."
      },
      "defaultValue": [
        "*"
      ]
    },
    "destinationPortRange": {
      "type": "Array",
      "metadata": {
        "displayName": "destinationPortRange",
        "description": "The destination port or range. Integer or range between 0 and 65535. Asterisk '*' can also be used to match all ports."
      },
      "defaultValue": [
        "*"
      ]
    },
    "direction": {
      "type": "String",
      "metadata": {
        "displayName": "direction",
        "description": "The direction of the rule. The direction specifies if rule will be evaluated on incoming or outgoing traffic. - Inbound or Outbound"
      },
      "defaultValue": "Outbound"
    },
    "priority": {
      "type": "Integer",
      "metadata": {
        "displayName": "priority",
        "description": "The priority of the rule. The value can be between 100 and 4096. The priority number must be unique for each rule in the collection. The lower the priority number, the higher the priority of the rule."
      },
      "defaultValue": 999
    },
    "protocol": {
      "type": "String",
      "metadata": {
        "displayName": "protocol",
        "description": "Network protocol this rule applies to. - Tcp, Udp, Icmp, Esp, *, Ah"
      },
      "defaultValue": "Tcp"
    },
    "ruledescription": {
      "type": "String",
      "metadata": {
        "displayName": "description",
        "description": "The description of the rule."
      },
      "defaultValue": "Change Me"
    },
    "rulename": {
      "type": "String",
      "metadata": {
        "displayName": "Rule Name",
        "description": "This is the name of the security rule itself."
      },
      "defaultValue": "ChangeMe"
    },
    "sourceAddressPrefix": {
      "type": "Array",
      "metadata": {
        "displayName": "sourceAddressPrefix",
        "description": "The CIDR or source IP range. Asterisk '*' can also be used to match all source IPs. Default tags such as 'VirtualNetwork', 'AzureLoadBalancer' and 'Internet' can also be used. If this is an ingress rule, specifies where network traffic originates from."
      },
      "defaultValue": [
        "*"
      ]
    },
    "sourcePortRange": {
      "type": "Array",
      "metadata": {
        "displayName": "sourcePortRange",
        "description": "The source port or range. Integer or range between 0 and 65535. Asterisk '*' can also be used to match all ports."
      },
      "defaultValue": [
        "*"
      ]
    },
    "effect": {
      "type": "String",
      "metadata": {
        "displayName": "Effect",
        "description": "DeployIfNotExists, AuditIfNotExists or Disabled the execution of the Policy"
      },
      "allowedValues": [
        "DeployIfNotExists",
        "AuditIfNotExists",
        "Disabled"
      ],
      "defaultValue": "DeployIfNotExists"
    }
  }
}
Azure Policy
Azure Policy
An Azure service that is used to implement corporate governance and standards at scale for Azure resources.
795 questions
{count} votes

2 answers

Sort by: Most helpful
  1. Vahid Ghafarpour 17,950 Reputation points
    2024-04-17T04:19:41.96+00:00

    Thanks for posting your question in the Microsoft Q&A forum.

    I think for NSGs, the correct resource type is "Microsoft.Network/networkSecurityGroups/securityRules"

    ** Please don't forget to close up the thread here by upvoting and accept it as an answer if it is helpful **


  2. Prashant Kumar 75 Reputation points Microsoft Employee
    2024-04-17T15:45:45.6866667+00:00

    Hi Harold,

    This error is due to syntax error in the ARM template used in this policy.

    I would suggest extracting the ARM template from the policy json and deploying it standalone. you will get to see the error in detail and fix it quicky as well. Because updating the policy definition for ARM template and re-running remediation tasks to test the ARM template is time-consuming.

    From initial analysis, I could see that wrong data type is being used for priority property. The supported data type needs to mention as int and not Integer.

    Also, the resource block has the name field replaced with rulename. name is mandatory property.

    Quick Reference : https://learn.microsoft.com/en-us/azure/templates/microsoft.network/networksecuritygroups/securityrules?pivots=deployment-language-arm-template

    Could you please try the below updated policy json?

    {

    "mode": "Indexed",

    "policyRule": {

    "if": {
    
      "equals": "Microsoft.Network/networkSecurityGroups",
    
      "field": "type"
    
    },
    
    "then": {
    
      "details": {
    
        "deployment": {
    
          "properties": {
    
            "mode": "incremental",
    
            "parameters": {
    
              "access": {
    
                "value": "[parameters('access')]"
    
              },
    
              "description": {
    
                "value": "[parameters('ruledescription')]"
    
              },
    
              "destinationAddressPrefix": {
    
                "value": "[parameters('destinationAddressPrefix')]"
    
              },
    
              "destinationPortRange": {
    
                "value": "[parameters('destinationPortRange')]"
    
              },
    
              "direction": {
    
                "value": "[parameters('direction')]"
    
              },
    
              "nsgName": {
    
                "value": "[field('name')]"
    
              },
    
              "priority": {
    
                "value": "[parameters('priority')]"
    
              },
    
              "protocol": {
    
                "value": "[parameters('protocol')]"
    
              },
    
              "rulename": {
    
                "value": "[parameters('rulename')]"
    
              },
    
              "sourceAddressPrefix": {
    
                "value": "[parameters('sourceAddressPrefix')]"
    
              },
    
              "sourcePortRange": {
    
                "value": "[parameters('sourcePortRange')]"
    
              }
    
            },
    
            "template": {
    
              "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
    
              "contentVersion": "1.0.0.0",
    
              "parameters": {
    
                "access": {
    
                  "type": "String"
    
                },
    
                "description": {
    
                  "type": "String"
    
                },
    
                "destinationAddressPrefix": {
    
                  "type": "String"
    
                },
    
                "destinationPortRange": {
    
                  "type": "String"
    
                },
    
                "direction": {
    
                  "type": "String"
    
                },
    
                "nsgName": {
    
                  "type": "string"
    
                },
    
                "priority": {
    
                  "type": "int"
    
                },
    
                "protocol": {
    
                  "type": "String"
    
                },
    
                "rulename": {
    
                  "type": "String"
    
                },
    
                "sourceAddressPrefix": {
    
                  "type": "string"
    
                },
    
                "sourcePortRange": {
    
                  "type": "String"
    
                }
    
              },
    
              "resources": [
    
                {
    
                  "apiVersion": "2022-07-01",
    
                  "properties": {
    
                    "access": "[parameters('access')]",
    
                    "description": "[parameters('description')]",
    
    
                   
    
    				 "destinationAddressPrefix": "[if(equals(length(parameters('destinationAddressPrefix')), 1), parameters('destinationAddressPrefix')[0], json('null'))]",
    
    				 "destinationAddressPrefixes": "[if(greater(length(parameters('destinationAddressPrefix')), 1), parameters('destinationAddressPrefix'), json('null'))]",
    
    
                   
    
                   "destinationPortRange": "[if(equals(length(parameters('destinationPortRange')),1),parameters('destinationPortRange'),json('null'))]",
    
                      "destinationPortRanges": "[if(equals(length(parameters('destinationPortRange')),1),json('null'),parameters('destinationPortRange'))]",
    
                    "direction": "[parameters('direction')]",
    
                    "priority": "[parameters('priority')]",
    
                    "protocol": "[parameters('protocol')]",
    
                     "sourceAddressPrefix": "[if(equals(length(parameters('sourceAddressPrefix')),1),parameters('sourceAddressPrefix'),json('null'))]",
    
                      "sourceAddressPrefixes": "[if(equals(length(parameters('sourceAddressPrefix')),1),json('null'),parameters('sourceAddressPrefix'))]",
    
                      "sourcePortRange": "[if(equals(length(parameters('sourcePortRange')),1),parameters('sourcePortRange'),json('null'))]",
    
                      "sourcePortRanges": "[if(equals(length(parameters('sourcePortRange')),1),json('null'),parameters('sourcePortRange'))]"
    
                  },
    
                  "name": "[concat(parameters('nsgName'),'/',parameters('rulename'))]",
    
                  "type": "Microsoft.Network/networkSecurityGroups/securityRules"
    
                }
    
              ]
    
            }
    
          }
    
        },
    
        "existenceCondition": {
    
          "count": {
    
            "field": "Microsoft.Network/networkSecurityGroups/securityRules[*]",
    
            "where": {
    
              "allOf": [
    
                {
    
                  "equals": "[parameters('rulename')]",
    
                  "field": "Microsoft.Network/networkSecurityGroups/securityRules[*].name"
    
                },
    
                {
    
                  "equals": "[parameters('protocol')]",
    
                  "field": "Microsoft.Network/networkSecurityGroups/securityRules[*].protocol"
    
                },
    
                {
    
                  "anyOf": [
    
                    {
    
                      "equals": true,
    
                      "value": "[equals(field('Microsoft.Network/networkSecurityGroups/securityRules[*].sourcePortRange'), parameters('sourcePortRange'))]"
    
                    },
    
                    {
    
                      "equals": true,
    
                      "value": "[equals(field('Microsoft.Network/networkSecurityGroups/securityRules[*].sourcePortRanges'), parameters('sourcePortRange'))]"
    
                    }
    
                  ]
    
                },
    
                {
    
                  "anyOf": [
    
                    {
    
                      "equals": true,
    
                      "value": "[equals(field('Microsoft.Network/networkSecurityGroups/securityRules[*].destinationPortRange'), parameters('destinationPortRange'))]"
    
                    },
    
                    {
    
                      "equals": true,
    
                      "value": "[equals(field('Microsoft.Network/networkSecurityGroups/securityRules[*].destinationPortRanges'), parameters('destinationPortRange'))]"
    
                    }
    
                  ]
    
                },
    
                {
    
                  "anyOf": [
    
                    {
    
                      "equals": true,
    
                      "value": "[equals(field('Microsoft.Network/networkSecurityGroups/securityRules[*].sourceAddressPrefix'), parameters('sourceAddressPrefix'))]"
    
                    },
    
                    {
    
                      "equals": true,
    
                      "value": "[equals(field('Microsoft.Network/networkSecurityGroups/securityRules[*].sourceAddressPrefixes'), parameters('sourceAddressPrefix'))]"
    
                    }
    
                  ]
    
                },
    
                {
    
                  "anyOf": [
    
                    {
    
                      "equals": true,
    
                      "value": "[equals(field('Microsoft.Network/networkSecurityGroups/securityRules[*].destinationAddressPrefix'), parameters('destinationAddressPrefix'))]"
    
                    },
    
                    {
    
                      "equals": true,
    
                      "value": "[equals(field('Microsoft.Network/networkSecurityGroups/securityRules[*].destinationAddressPrefixes'), parameters('destinationAddressPrefix'))]"
    
                    }
    
                  ]
    
                },
    
                {
    
                  "equals": "[parameters('access')]",
    
                  "field": "Microsoft.Network/networkSecurityGroups/securityRules[*].access"
    
                },
    
                {
    
                  "equals": "[parameters('priority')]",
    
                  "field": "Microsoft.Network/networkSecurityGroups/securityRules[*].priority"
    
                },
    
                {
    
                  "equals": "[parameters('direction')]",
    
                  "field": "Microsoft.Network/networkSecurityGroups/securityRules[*].direction"
    
                }
    
              ]
    
            }
    
          },
    
          "notEquals": 0
    
        },
    
        "roleDefinitionIds": [
    
          "/providers/Microsoft.Authorization/roleDefinitions/4d97b98b-1d4f-4787-a291-c67834d212e7"
    
        ],
    
        "type": "Microsoft.Network/networkSecurityGroups/securityRules"
    
      },
    
      "effect": "[parameters('effect')]"
    
    }
    ```  },
    
      "parameters": {
    
    ```scala
    "access": {
    
      "type": "String",
    
      "metadata": {
    
        "displayName": "access",
    
        "description": "The network traffic is allowed or denied. - Allow or Deny"
    
      },
    
      "defaultValue": "Deny"
    
    },
    
    "destinationAddressPrefix": {
    
      "type": "String",
    
      "metadata": {
    
        "displayName": "destinationAddressPrefix",
    
        "description": "The destination address prefix. CIDR or destination IP range. Asterisk '*' can also be used to match all source IPs. Default tags such as 'VirtualNetwork', 'AzureLoadBalancer' and 'Internet' can also be used."
    
      },
    
      "defaultValue": 
    
        "*"
    
    
      
    
    },
    
    "destinationPortRange": {
    
      "type": "String",
    
      "metadata": {
    
        "displayName": "destinationPortRange",
    
        "description": "The destination port or range. Integer or range between 0 and 65535. Asterisk '*' can also be used to match all ports."
    
      },
    
      "defaultValue":  "*"
    
    
      
    
    },
    
    "direction": {
    
      "type": "String",
    
      "metadata": {
    
        "displayName": "direction",
    
        "description": "The direction of the rule. The direction specifies if rule will be evaluated on incoming or outgoing traffic. - Inbound or Outbound"
    
      },
    
      "defaultValue": "Outbound"
    
    },
    
    "priority": {
    
      "type": "Integer",
    
      "metadata": {
    
        "displayName": "priority",
    
        "description": "The priority of the rule. The value can be between 100 and 4096. The priority number must be unique for each rule in the collection. The lower the priority number, the higher the priority of the rule."
    
      },
    
      "defaultValue": 999
    
    },
    
    "protocol": {
    
      "type": "String",
    
      "metadata": {
    
        "displayName": "protocol",
    
        "description": "Network protocol this rule applies to. - Tcp, Udp, Icmp, Esp, *, Ah"
    
      },
    
      "defaultValue": "Tcp"
    
    },
    
    "ruledescription": {
    
      "type": "String",
    
      "metadata": {
    
        "displayName": "description",
    
        "description": "The description of the rule."
    
      },
    
      "defaultValue": "Change Me"
    
    },
    
    "rulename": {
    
      "type": "String",
    
      "metadata": {
    
        "displayName": "Rule Name",
    
        "description": "This is the name of the security rule itself."
    
      },
    
      "defaultValue": "ChangeMe"
    
    },
    
    "sourceAddressPrefix": {
    
      "type": "string",
    
      "metadata": {
    
        "displayName": "sourceAddressPrefix",
    
        "description": "The CIDR or source IP range. Asterisk '*' can also be used to match all source IPs. Default tags such as 'VirtualNetwork', 'AzureLoadBalancer' and 'Internet' can also be used. If this is an ingress rule, specifies where network traffic originates from."
    
      },
    
      "defaultValue": 
    
        "*"
    
    
      
    
    },
    
    "sourcePortRange": {
    
      "type": "String",
    
      "metadata": {
    
        "displayName": "sourcePortRange",
    
        "description": "The source port or range. Integer or range between 0 and 65535. Asterisk '*' can also be used to match all ports."
    
      },
    
      "defaultValue": 
    
        "*"
    
    
      
    
    },
    
    "effect": {
    
      "type": "String",
    
      "metadata": {
    
        "displayName": "Effect",
    
        "description": "DeployIfNotExists, AuditIfNotExists or Disabled the execution of the Policy"
    
      },
    
      "allowedValues": [
    
        "DeployIfNotExists",
    
        "AuditIfNotExists",
    
        "Disabled"
    
      ],
    
      "defaultValue": "DeployIfNotExists"
    
    }
    ```  }
    
    }