如何比较 Azure Policy 中的多个数组?
How do I compare multiple arrays in azure policy?
我正在尝试为 应用程序网关 创建策略。政策说明如下
Http listener should not be attached to a public IP frontend configuration
所以根据我的理解,我必须检查 frontendConfiguration 是否有 public IP,然后检查 public IP 的名称在任何 httpListeners
中被引用
由于 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
},
但是我得到以下错误
The alias: 'Microsoft.Network/applicationGateways/httpListeners[].frontendIPConfiguration.id' used inside the 'count.where' expression is targeting an array outside of the count scope: '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/', parameters('virtualNetworkName'))]",
"[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",
"properties": {
"frontendIPConfiguration": {
"id": "[concat(variables('applicationGatewayId'), '/frontendIPConfigurations/appGwPrivateFrontendIp')]"
},
"frontendPort": {
"id": "[concat(variables('applicationGatewayId'), '/frontendPorts/port_8080')]"
},
"protocol": "Http",
"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",
"properties": {
"RuleType": "Basic",
"httpListener": {
"id": "[concat(variables('applicationGatewayId'), '/httpListeners/sample-priv-http')]"
},
"backendAddressPool": {
"id": "[concat(variables('applicationGatewayId'), '/backendAddressPools/samplebend')]"
},
"backendHttpSettings": {
"id": "[concat(variables('applicationGatewayId'), '/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')]",
"location": "[parameters('location')]",
"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')]",
"location": "[parameters('location')]",
"sku": {
"name": "[parameters('sku')]"
},
"zones": "[parameters('publicIpZones')]",
"properties": {
"publicIPAllocationMethod": "[parameters('allocationMethod')]"
}
}
]
}
免责声明:我在微软工作,但这不是官方回答
以下政策应该可以解决问题:
{
"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}', field('id'), current('Microsoft.Network/applicationGateways/frontendIPConfigurations[*].name'))]",
"in": "[field('Microsoft.Network/applicationGateways/httpListeners[*].frontendIPConfiguration.id')]"
}
检查当前 frontendIPConfiguration(具有 public 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'))]"
}
隐式检查 all Microsoft.Network/applicationGateways/httpListeners[*].frontendIPConfiguration.id
的值是否匹配条件(参见 here)。这基本上是计数表达式的一种不同形式,正如错误消息所说,您不能从枚举不同数组的表达式内部枚举一个数组。
我正在尝试为 应用程序网关 创建策略。政策说明如下
Http listener should not be attached to a public IP frontend configuration
所以根据我的理解,我必须检查 frontendConfiguration 是否有 public IP,然后检查 public IP 的名称在任何 httpListeners
中被引用由于 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
},
但是我得到以下错误
The alias: 'Microsoft.Network/applicationGateways/httpListeners[].frontendIPConfiguration.id' used inside the 'count.where' expression is targeting an array outside of the count scope: '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/', parameters('virtualNetworkName'))]",
"[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",
"properties": {
"frontendIPConfiguration": {
"id": "[concat(variables('applicationGatewayId'), '/frontendIPConfigurations/appGwPrivateFrontendIp')]"
},
"frontendPort": {
"id": "[concat(variables('applicationGatewayId'), '/frontendPorts/port_8080')]"
},
"protocol": "Http",
"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",
"properties": {
"RuleType": "Basic",
"httpListener": {
"id": "[concat(variables('applicationGatewayId'), '/httpListeners/sample-priv-http')]"
},
"backendAddressPool": {
"id": "[concat(variables('applicationGatewayId'), '/backendAddressPools/samplebend')]"
},
"backendHttpSettings": {
"id": "[concat(variables('applicationGatewayId'), '/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')]",
"location": "[parameters('location')]",
"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')]",
"location": "[parameters('location')]",
"sku": {
"name": "[parameters('sku')]"
},
"zones": "[parameters('publicIpZones')]",
"properties": {
"publicIPAllocationMethod": "[parameters('allocationMethod')]"
}
}
]
}
免责声明:我在微软工作,但这不是官方回答
以下政策应该可以解决问题:
{
"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}', field('id'), current('Microsoft.Network/applicationGateways/frontendIPConfigurations[*].name'))]",
"in": "[field('Microsoft.Network/applicationGateways/httpListeners[*].frontendIPConfiguration.id')]"
}
检查当前 frontendIPConfiguration(具有 public 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'))]"
}
隐式检查 all Microsoft.Network/applicationGateways/httpListeners[*].frontendIPConfiguration.id
的值是否匹配条件(参见 here)。这基本上是计数表达式的一种不同形式,正如错误消息所说,您不能从枚举不同数组的表达式内部枚举一个数组。