如何比较Azure策略中的多个阵列?

问题描述

我正在尝试为应用程序网关创建策略。该政策如下所述

Http侦听器不应附加到公共IP前端配置

因此,据我了解,我必须检查 frontendConfiguration 是否具有公共IP,然后检查是否在任何 httpListeners中引用了公共IP的名称

由于frontendIPConfigurations和httpListeners都是数组,因此我考虑对此复杂查询使用计数,并尝试了以下方法

"if": {
                "count": {
                    "field": "Microsoft.Network/applicationGateways/frontendIPConfigurations[*]","where": {
                        "allOf": [
                            {
                                "field": "Microsoft.Network/applicationGateways/frontendIPConfigurations[*].publicIPAddress.id","exists": true
                            },{
                                "field": "Microsoft.Network/applicationGateways/httpListeners[*].frontendIPConfiguration.id","like": "[concat('*',field('Microsoft.Network/applicationGateways/frontendIPConfigurations[*].publicIPAddress.name'))]"
                            }
                        ]
                    }
                },"greaterOrEquals": 1
            },

但是我收到以下错误

在'count.where'表达式内使用的别名:'Microsoft.Network/applicationGateways/httpListeners[].frontendIPConfiguration.id'指向计数范围之外的数组:'Microsoft.Network/applicationGateways/ frontendIPConfigurations []'

能不能解决这个问题?

以下是示例ARM模板供参考:

{
    "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#","contentVersion": "1.0.0.0","parameters": {
        "location": {
            "type": "string"
        },"applicationGatewayName": {
            "type": "string"
        },"tier": {
            "type": "string"
        },"skuSize": {
            "type": "string"
        },"capacity": {
            "type": "int","defaultValue": 2
        },"subnetName": {
            "type": "string"
        },"zones": {
            "type": "array"
        },"virtualNetworkName": {
            "type": "string"
        },"virtualNetworkPrefix": {
            "type": "array"
        },"publicIpAddressName": {
            "type": "string"
        },"sku": {
            "type": "string"
        },"allocationMethod": {
            "type": "string"
        },"publicIpZones": {
            "type": "array"
        },"privateIpAddress": {
            "type": "string"
        },"autoScaleMaxCapacity": {
            "type": "int"
        }
    },"variables": {
        "vnetId": "[resourceId('policy-tester','Microsoft.Network/virtualNetworks/',parameters('virtualNetworkName'))]","publicIPRef": "[resourceId('Microsoft.Network/publicIPAddresses/',parameters('publicIpAddressName'))]","subnetRef": "[concat(variables('vnetId'),'/subnets/',parameters('subnetName'))]","applicationGatewayId": "[resourceId('Microsoft.Network/applicationGateways',parameters('applicationGatewayName'))]"
    },"resources": [
        {
            "name": "[parameters('applicationGatewayName')]","type": "Microsoft.Network/applicationGateways","apiVersion": "2019-09-01","location": "[parameters('location')]","zones": "[parameters('zones')]","dependsOn": [
                "[concat('Microsoft.Network/virtualNetworks/',"[concat('Microsoft.Network/publicIPAddresses/',parameters('publicIpAddressName'))]"
            ],"tags": {},"properties": {
                "sku": {
                    "name": "[parameters('skuSize')]","tier": "[parameters('tier')]"
                },"gatewayIPConfigurations": [
                    {
                        "name": "appGatewayIpConfig","properties": {
                            "subnet": {
                                "id": "[variables('subnetRef')]"
                            }
                        }
                    }
                ],"frontendIPConfigurations": [
                    {
                        "name": "appGwPrivateFrontendIp","properties": {
                            "subnet": {
                                "id": "[variables('subnetRef')]"
                            },"privateIPAddress": "[parameters('privateIpAddress')]","privateIPAllocationMethod": "Static"
                        }
                    },{
                        "name": "appGwPublicFrontendIp","properties": {
                            "PublicIPAddress": {
                                "id": "[variables('publicIPRef')]"
                            }
                        }
                    }
                ],"frontendPorts": [
                    {
                        "name": "port_80","properties": {
                            "Port": 80
                        }
                    },{
                        "name": "port_8080","properties": {
                            "Port": 8080
                        }
                    }
                ],"backendAddresspools": [
                    {
                        "name": "samplebend","properties": {
                            "backendAddresses": []
                        }
                    }
                ],"backendHttpSettingsCollection": [
                    {
                        "name": "sample-http","properties": {
                            "Port": 80,"Protocol": "Http","cookieBasedAffinity": "disabled","requestTimeout": 20
                        }
                    }
                ],"httpListeners": [
                    {
                        "name": "sample-list","properties": {
                            "frontendIPConfiguration": {
                                "id": "[concat(variables('applicationGatewayId'),'/frontendIPConfigurations/appGwPublicFrontendIp')]"
                            },"frontendPort": {
                                "id": "[concat(variables('applicationGatewayId'),'/frontendPorts/port_80')]"
                            },"protocol": "Http","sslCertificate": null
                        }
                    },{
                        "name": "sample-priv-http",'/frontendIPConfigurations/appGwPrivateFrontendIp')]"
                            },'/frontendPorts/port_8080')]"
                            },"sslCertificate": null
                        }
                    }
                ],"requestRoutingRules": [
                    {
                        "Name": "sample-rule","properties": {
                            "RuleType": "Basic","httpListener": {
                                "id": "[concat(variables('applicationGatewayId'),'/httpListeners/sample-list')]"
                            },"backendAddresspool": {
                                "id": "[concat(variables('applicationGatewayId'),'/backendAddresspools/samplebend')]"
                            },"backendHttpSettings": {
                                "id": "[concat(variables('applicationGatewayId'),'/backendHttpSettingsCollection/sample-http')]"
                            }
                        }
                    },{
                        "Name": "sample-priv-http-rule",'/httpListeners/sample-priv-http')]"
                            },'/backendHttpSettingsCollection/sample-http')]"
                            }
                        }
                    }
                ],"enableHttp2": false,"sslCertificates": [],"probes": [],"autoscaleConfiguration": {
                    "minCapacity": "[parameters('capacity')]","maxCapacity": "[parameters('autoScaleMaxCapacity')]"
                }
            }
        },{
            "apiVersion": "2019-09-01","type": "Microsoft.Network/virtualNetworks","name": "[parameters('virtualNetworkName')]","properties": {
                "addressspace": {
                    "addressprefixes": "[parameters('virtualNetworkPrefix')]"
                },"subnets": [
                    {
                        "name": "default","properties": {
                            "addressprefix": "10.0.0.0/24"
                        }
                    }
                ]
            }
        },{
            "apiVersion": "2019-02-01","type": "Microsoft.Network/publicIPAddresses","name": "[parameters('publicIpAddressName')]","sku": {
                "name": "[parameters('sku')]"
            },"zones": "[parameters('publicIpZones')]","properties": {
                "publicIPAllocationMethod": "[parameters('allocationMethod')]"
            }
        }
    ]
}

解决方法

免责声明:我为 Microsoft 工作,但这不是官方答案

以下政策应该可以解决问题:

{
  "if": {
    "allOf": [
      {
        "field": "type","equals": "Microsoft.Network/applicationGateways"
      },{
        "count": {
          "field": "Microsoft.Network/applicationGateways/frontendIPConfigurations[*]","where": {
            "allOf": [
              {
                "field": "Microsoft.Network/applicationGateways/frontendIPConfigurations[*].publicIPAddress.id","exists": true
              },{
                "value": "[format('{0}/frontendIPConfigurations/{1}',field('id'),current('Microsoft.Network/applicationGateways/frontendIPConfigurations[*].name'))]","in": "[field('Microsoft.Network/applicationGateways/httpListeners[*].frontendIPConfiguration.id')]"
              }
            ]
          }
        },"greater": 0
      }
    ]
  },"then": {
    "effect": "deny"
  }
}

详情

条件:

{
    "value": "[format('{0}/frontendIPConfigurations/{1}',"in": "[field('Microsoft.Network/applicationGateways/httpListeners[*].frontendIPConfiguration.id')]"
}

检查当前 frontendIPConfiguration(具有公共 IP)的资源 ID 是否被任何 httpListeners 引用。

value 表达式通过组合应用 GW 资源的资源 ID + 当前 frontendIPConfiguration 资源的名称来构建当前正在评估的 frontendIPConfiguration 的资源 ID。我们必须从头开始构建它,因为在创建新的应用程序 gw 资源时,frontendIPConfiguration 的 id 属性不存在于请求内容中。

另请注意,当您想要访问由 count 表达式枚举的当前数组成员的值时,您需要 should use the current() function instead of field()

关于你遇到的错误信息,这是因为表达式:

{
  "field": "Microsoft.Network/applicationGateways/httpListeners[*].frontendIPConfiguration.id","like": "[concat('*',field('Microsoft.Network/applicationGateways/frontendIPConfigurations[*].publicIPAddress.name'))]"
}

隐式检查Microsoft.Network/applicationGateways/httpListeners[*].frontendIPConfiguration.id所有值是否与条件匹配(请参阅here)。这基本上是计数表达式的一种不同形式,正如错误消息所说,您无法从枚举不同数组的表达式内部枚举一个数组。