Azure Policy 定义结构

Azure Policy 可为资源建立多种约定。 策略定义描述资源符合性条件,以及在符合某个条件时要采取的效果。 条件将资源属性字段与所需值进行比较。 资源属性字段是通过别名进行访问的。 如果资源属性字段为数组,则可使用特殊的数组别名从所有数组成员中选择值,并将条件应用于每个值。 如需了解更多,请参见条件

通过定义约定,可以控制成本并更轻松地管理资源。 例如,可指定仅允许特定类型的虚拟机。 也可要求资源使用特定的标记。 策略分配由子资源继承。 如果将策略分配应用到资源组,则会将其应用到该资源组中的所有资源。

策略定义“policyRule”架构可在此处查看:

使用 JSON 创建策略定义。 策略定义包含以下项的元素:

  • 显示名称
  • description
  • mode
  • metadata
  • parameters
  • 策略规则
    • 逻辑评估
    • 效果

例如,以下 JSON 说明限制资源部署位置的策略:

{
    "properties": {
        "displayName": "Allowed locations",
        "description": "This policy enables you to restrict the locations your organization can specify when deploying resources.",
        "mode": "Indexed",
        "metadata": {
            "version": "1.0.0",
            "category": "Locations"
        },
        "parameters": {
            "allowedLocations": {
                "type": "array",
                "metadata": {
                    "description": "The list of locations that can be specified when deploying resources",
                    "strongType": "location",
                    "displayName": "Allowed locations"
                },
                "defaultValue": [ "chinanorth2" ]
            }
        },
        "policyRule": {
            "if": {
                "not": {
                    "field": "location",
                    "in": "[parameters('allowedLocations')]"
                }
            },
            "then": {
                "effect": "deny"
            }
        }
    }
}

Azure Policy 内置和模式位于 Azure Policy 示例

显示名称和说明

请使用 displayNamedescription 来标识策略定义,并提供其使用上下文。 displayName 的最大长度为 128 个字符,description 的最大长度为 512 个字符。

注意

在创建或更新策略定义期间,idtypename 由 JSON 外部属性定义,在 JSON 文件中不是必需的。 通过 SDK 获取策略定义将返回 idtypename 属性作为 JSON 的一部分,但每个属性都是与策略定义相关的只读信息。

策略类型

尽管无法设置 policyType 属性,但 SDK 返回了三个值且在门户中可见:

  • Builtin:这些策略定义由 Microsoft 提供并维护。

  • Custom:客户创建的所有策略定义都具有此值。

模式

“模式”的配置要取决于策略是针对 Azure 资源管理器属性还是资源提供程序属性。

资源管理器模式

“模式”决定要为策略定义评估的资源类型。 支持的模式包括:

  • all:评估资源组、订阅和所有资源类型
  • indexed:仅评估支持标记和位置的资源类型

例如,资源 Microsoft.Network/routeTables 支持标记和位置,并在这两种模式中进行评估。 但是,无法标记资源 Microsoft.Network/routeTables/routes,也不会在 Indexed 模式下对其进行评估。

大多数情况下,建议将“mode”设置为 。 通过门户创建的所有策略定义使用 all 模式。 如果使用 PowerShell 或 Azure CLI,则可以手动指定 mode 参数。 如果策略定义不包含 mode 值,为提供后向兼容性,在 Azure PowerShell 中默认为 all,在 Azure CLI 中默认为 nullnull 模式等同于使用 indexed 来支持后向兼容性。

在创建强制执行标记或位置的策略时,应该使用 indexed。 虽然并不是必需的,但是它会阻止不支持标记和位置的资源,使其不会在符合性结果中显示为不兼容。 有一个例外情况,就是资源组和订阅。 策略定义若在资源组或订阅上强制执行位置或标记,则应将“模式”设为 ,并明确以 Microsoft.Resources/subscriptions/resourceGroupsMicrosoft.Resources/subscriptions 类型为目标。 有关示例,请参阅模式:标记 - 示例 #1。 有关支持标记的资源列表,请参阅有关 Azure 资源的标记支持

资源提供程序模式

完全支持以下资源提供程序模式:

元数据

metadata 可选属性用于存储关于策略定义的信息。 客户可在 metadata 中定义对其组织有用的任何属性和值。 但是,Azure Policy 和内置项使用一些常见属性。每个 属性的限制为 1024 个字符。

常见元数据属性

  • version(字符串):跟踪有关策略定义的内容版本的详细信息。
  • category(字符串):确定在 Azure 门户中的哪个类别下显示策略定义。
  • preview(布尔):如果策略定义为“预览”,则为 True 或 False 标记。
  • deprecated(布尔):如果策略定义被标记为“已弃用”,则为 True 或 False 标记。
  • portalReview(字符串):决定是否应在门户中查看参数,而不考虑必需的输入。

注意

Azure Policy 服务会使用 versionpreviewdeprecated 属性,将变更级别传达给内置策略定义或计划和状态。 version 的格式为:{Major}.{Minor}.{Patch}。 特定状态(例如“弃用”或“预览版”)会附加至 属性,或另一个属性中附加为“布尔值”。 有关 Azure Policy 内置项版本控制方式的详细信息,请参阅内置项版本控制。 若要详细了解策略“已弃用”或“处于预览状态”的含义,请参阅处于预览状态和已弃用的策略

参数

参数可减少策略定义的数量,有助于简化策略管理。 可以将参数想象成窗体上的字段 - nameaddresscitystate。 这些参数始终不变,但其值会基于窗体中的各填写内容变化。 构建策略时,参数同样适用。 如果在策略定义中包括参数,就可以通过使用不同的值重新使用策略以执行不同方案。

添加或删除参数

参数可以添加到现有和已分配的定义。 新参数必须包含 defaultValue 属性。 这可以防止策略或计划的现有分配间接被设为无效。

无法从策略定义中移除参数,因为可能存在设置参数值的赋值,并且该引用将被破坏。 一些内置策略已使用 "deprecated": true 元数据弃用了参数,在 Azure 门户中分配定义时,这会隐藏参数。 虽然自定义策略定义不支持这样做,但另一种选择是复制并新建不带参数自定义策略定义。

参数属性

参数有下述可以在策略定义中使用的属性:

  • name:参数的名称。 由策略规则中的 parameters 部署函数使用。 有关详细信息,请参阅使用参数值
  • type:确定参数是否为“字符串”、“数组”、“对象”、“布尔值”、“整数”、“浮点数”或者“日期/时间”。
  • metadata:定义主要由 Azure 门户用来显示用户友好信息的子属性:
    • description:说明参数的用途。 可以用来提供可接受值的示例。
    • displayName:在门户中显示的用于参数的友好名称。
    • strongType:(可选)通过门户分配策略定义时使用。 提供上下文感知列表。 有关详细信息,请参阅 strongType
    • assignPermissions:(可选)设置为“true”,使 Azure 门户在策略分配过程中创建角色分配。 如果希望在分配范围之外分配权限,此属性会很有用。 策略中的每个角色定义(或计划中所有策略中的每个角色定义)都有一个角色分配。 参数值必须是有效的资源或范围。
    • deprecated:一个布尔标志,指示参数是否已在内置定义中被弃用。
  • defaultValue:(可选)设置分配的参数的值(如果值未给定)。 在更新已分配的现有策略定义时必须使用此项。 对于 oject 类型的参数,值必须与适当的架构匹配。
  • allowedValues:(可选)提供参数在分配过程中所接受值的数组。
    • 区分大小写:分配策略时允许的值比较区分大小写,这意味着赋值中的所选参数值必须与定义中 allowedValues 数组中的值的大小写相符。 但是,为赋值选择值后,根据使用的条件,对字符串比较的计算可能会不区分大小写。 例如,如果参数将 Dev 指定为赋值中的允许的标记值,并且此值使用 equals 条件与输入字符串进行比较,则 Azure Policy 稍后会将标记值 dev 作为匹配项来计算,即使它小写也是如此,因为 notEquals 不区分大小写。
    • 对于对象类型的参数,值必须与适当的架构匹配。
  • schema:(可选)在分配过程中使用自定义 JSON 架构验证参数输入。 此属性仅支持对象类型的参数,并遵循 Json.NET 架构 2019-09 实现。 可以了解更多关于在 https://json-schema.org/ 使用架构和在 https://www.jsonschemavalidator.net/ 测试草稿架构的信息。

示例参数

示例 1

例如,可以定义策略定义来限制资源的部署位置。 allowedLocations 可以是该策略定义的一个参数。 每次分配策略定义来限制接受的值时,会使用此参数。 使用 strongType 可以在通过门户完成分配时提供增强的体验:

"parameters": {
    "allowedLocations": {
        "type": "array",
        "metadata": {
            "description": "The list of allowed locations for resources.",
            "displayName": "Allowed locations",
            "strongType": "location"
        },
        "defaultValue": [ "chinanorth2" ],
        "allowedValues": [
            "chinaeast2",
            "chinanorth2",
            "chinanorth"
        ]
    }
}

在分配时,此数组类型参数(没有 strongType)的示例输入可能是 ["chinaeast2", "chinanorth"]。

示例 2

在更高级的方案中,可以定义要求 Kubernetes 群集 Pod 使用指定标签的策略。 该策略定义的参数可以是 labelSelector,该参数由策略定义的每次分配用于根据标签键和值指定有问题的 Kubernetes 资源:

"parameters": {
    "labelSelector": {
        "type": "Object",
        "metadata": {
            "displayName": "Kubernetes label selector",
            "description": "Label query to select Kubernetes resources for policy evaluation. An empty label selector matches all Kubernetes resources."
        },
        "defaultValue": {},
        "schema": {
            "description": "A label selector is a label query over a set of resources. The result of matchLabels and matchExpressions are ANDed. An empty label selector matches all resources.",
            "type": "object",
            "properties": {
                "matchLabels": {
                    "description": "matchLabels is a map of {key,value} pairs.",
                    "type": "object",
                    "additionalProperties": {
                        "type": "string"
                    },
                    "minProperties": 1
                },
                "matchExpressions": {
                    "description": "matchExpressions is a list of values, a key, and an operator.",
                    "type": "array",
                    "items": {
                        "type": "object",
                        "properties": {
                            "key": {
                                "description": "key is the label key that the selector applies to.",
                                "type": "string"
                            },
                            "operator": {
                                "description": "operator represents a key's relationship to a set of values.",
                                "type": "string",
                                "enum": [
                                    "In",
                                    "NotIn",
                                    "Exists",
                                    "DoesNotExist"
                                ]
                            },
                            "values": {
                                "description": "values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty.",
                                "type": "array",
                                "items": {
                                    "type": "string"
                                }
                            }
                        },
                        "required": [
                            "key",
                            "operator"
                        ],
                        "additionalProperties": false
                    },
                    "minItems": 1
                }
            },
            "additionalProperties": false
        }
    },
}

分配时此对象类型参数的示例输入采用 JSON 格式,由指定的架构验证,可能是:

{
    "matchLabels": {
        "poolID": "abc123",
        "nodeGroup": "Group1",
        "region": "chinaeast2"
    },
    "matchExpressions": [
        {
            "key": "name",
            "operator": "In",
            "values": ["payroll", "web"]
        },
        {
            "key": "environment",
            "operator": "NotIn",
            "values": ["dev"]
        }
    ]
}

使用参数值

在策略规则中,你可以使用下列 parameters 函数语法引用参数:

{
    "field": "location",
    "in": "[parameters('allowedLocations')]"
}

此示例引用 allowedLocations 参数,该参数已在参数属性中演示过。

strongType

metadata 属性中,可以使用 strongType 来提供 Azure 门户中的一个包含选项的多选列表。 strongType 可以是受支持的资源类型,也可以是允许值。 若要确定某个资源类型是否对 strongType 有效,请使用 Get-AzResourceProvider。 资源类型“strongType”的格式为 。 例如 Microsoft.Network/virtualNetworks/subnets

支持部分不是由 Get-AzResourceProvider 返回的资源类型。 这些类型包括:

  • Microsoft.RecoveryServices/vaults/backupPolicies

strongType 的非资源类型允许值包括:

  • location
  • resourceTypes
  • storageSkus
  • vmSKUs
  • existingResourceGroups

定义位置

创建计划或策略时,需要指定定义位置。 定义位置必须是管理组或订阅。 此位置决定了计划或策略的分配范围。 资源必须是用于分配的目标定义位置的层次结构中的直系成员或子代。

如果定义位置是:

  • 订阅 - 策略定义只能分配到该订阅内的资源。
  • 管理组 - 策略定义只能分配到子管理组和子订阅内的资源。 如果你计划将此策略定义应用于多个订阅,该位置必须是包含每个订阅的管理组。

有关详细信息,请参阅了解 Azure Policy 中的范围

策略规则

策略规则包括 IfThen 块。 在 If 块中,定义强制执行策略时指定的一个或多个条件。 可以对这些条件应用逻辑运算符,以精确定义策略的方案。

Then 块中,定义满足 If 条件时产生的效果。

{
    "if": {
        <condition> | <logical operator>
    },
    "then": {
        "effect": "deny | audit | modify | denyAction | append | auditIfNotExists | deployIfNotExists | disabled"
    }
}

逻辑运算符

支持的逻辑运算符为:

  • "not": {condition or operator}
  • "allOf": [{condition or operator},{condition or operator}]
  • "anyOf": [{condition or operator},{condition or operator}]

not 语法反转条件的结果。 allOf 语法(与逻辑 And 操作相似)要求所有条件为 true。 anyOf 语法(与逻辑 Or 操作相似)要求一个或多个条件为 true。

可以嵌套逻辑运算符。 以下示例显示了嵌套在 allOf 操作中的 not 操作。

"if": {
    "allOf": [{
            "not": {
                "field": "tags",
                "containsKey": "application"
            }
        },
        {
            "field": "type",
            "equals": "Microsoft.Storage/storageAccounts"
        }
    ]
},

条件

条件用于评估某个值是否符合特定的标准。 支持的条件有:

  • "equals": "stringValue"
  • "notEquals": "stringValue"
  • "like": "stringValue"
  • "notLike": "stringValue"
  • "match": "stringValue"
  • "matchInsensitively": "stringValue"
  • "notMatch": "stringValue"
  • "notMatchInsensitively": "stringValue"
  • "contains": "stringValue"
  • "notContains": "stringValue"
  • "in": ["stringValue1","stringValue2"]
  • "notIn": ["stringValue1","stringValue2"]
  • "containsKey": "keyName"
  • "notContainsKey": "keyName"
  • "less": "dateValue" | "less": "stringValue" | "less": intValue
  • "lessOrEquals": "dateValue" | "lessOrEquals": "stringValue" | "lessOrEquals": intValue
  • "greater": "dateValue" | "greater": "stringValue" | "greater": intValue
  • "greaterOrEquals": "dateValue" | "greaterOrEquals": "stringValue" | "greaterOrEquals": intValue
  • "exists": "bool"

对于“less”、“lessOrEquals”、“greater”和“greaterOrEquals”,如果属性类型与条件类型不匹配,则会引发错误。 字符串比较是使用 InvariantCultureIgnoreCase 进行。

使用 like 和 notLike 条件时,请在值中指定通配符 。 值不应包含多个通配符 *

当使用 match 和 notMatch 条件时,请提供 来匹配数字、 来匹配字母、. 来匹配所有字符,以及提供任何其他字符来匹配该实际字符。 尽管 match 和 notMatch 区分大小写,但用于评估 stringValue 的所有其他条件都不区分大小写 。 “matchInsensitively”和“notMatchInsensitively”中提供了不区分大小写的替代方案 。

字段

可以使用“field”表达式来构建条件,用于评估资源请求有效负载中的属性值是否符合特定的标准。 支持以下字段:

  • name

  • fullName

    • 返回资源全名。 资源全名是最前面为任意父资源名称的资源名称(例如“myServer/myDatabase”)。
  • kind

  • type

  • location

    • 位置字段已规范化,支持各种格式。 例如,China East 2 被视为等于 chinaeast2
    • 对于不限位置的资源,请使用 global
  • id

    • 返回所评估的资源的资源 ID。
    • 示例:/subscriptions/06be863d-0996-4d56-be22-384767287aa2/resourceGroups/myRG/providers/Microsoft.KeyVault/vaults/myVault
  • identity.type

  • tags

  • tags['<tagName>']

    • 此括号语法支持具有标点符号的标记名称,例如连字符、句点或空格。
    • 其中 <tagName> 是要验证其条件的标记的名称。
    • 示例:tags['Acct.CostCenter'],其中 Acct.CostCenter 是标记的名称。
  • tags['''<tagName>''']

    • 此括号语法通过双撇号进行转义,可支持在其中包含撇号的标记名称。
    • 其中“tagName>”是要验证其条件的标记的名称。
    • 示例:tags['''My.Apostrophe.Tag'''],其中“My.Apostrophe.Tag”是标记的名称。

    注意

    tags.<tagName>tags[tagName]tags[tag.with.dots] 仍然是可接受的用于声明标记字段的方式。 但是,首选表达式是上面列出的那些。

  • 属性别名 - 有关列表,请参阅别名

    注意

    在引用 [*] 别名的“field”表达式中,将在元素之间使用逻辑“与”对数组中的每个元素分别进行评估。 有关详细信息,请参阅引用数组资源属性

使用 field 表达式的条件可以替换用于写入操作的旧策略定义语法 "source": "action"。 例如,此项不再受支持:

{
    "source": "action",
    "like": "Microsoft.Network/publicIPAddresses/*"
}

但可以使用 field 逻辑实现所需的行为:

{
    "field": "type",
    "equals": "Microsoft.Network/publicIPAddresses"
}

使用带参数的标记

参数值可以传递给标记字段。 将参数传递给标记字段可在策略分配期间提高策略定义的灵活性。

在以下示例中,concat 用于为名为 tagName 参数值的标记创建标记字段查找。 如果该标记不存在,系统会使用“修改”效果,通过 查找函数使用在已审计资源父资源组上具有相同名称的标签值来添加该标记。

{
    "if": {
        "field": "[concat('tags[', parameters('tagName'), ']')]",
        "exists": "false"
    },
    "then": {
        "effect": "modify",
        "details": {
            "operations": [{
                "operation": "add",
                "field": "[concat('tags[', parameters('tagName'), ']')]",
                "value": "[resourcegroup().tags[parameters('tagName')]]"
            }],
            "roleDefinitionIds": [
                "/providers/microsoft.authorization/roleDefinitions/4a9ae827-6dc8-4573-8ac7-8239d42aa03f"
            ]
        }
    }
}

用于评估某个值是否符合特定标准的条件可以使用“value”表达式来构建。 值可以是文本、参数的值,也可以是任何受支持的模板函数的返回值。

警告

如果模板函数的结果是一个错误,则策略评估会失败。 评估失败是一种隐式拒绝。 有关详细信息,请参阅避免模板失败。 使用 DoNotEnforce 的 enforcementMode,以防止在测试和验证新策略定义期间,由于新的或更新的资源评估失败而受到影响。

Value 示例

此策略规则示例使用 valueresourceGroup() 函数和返回的 name 属性的结果与 like 条件 *netrg 进行对比。 此规则拒绝名称以 *netrg 结尾的资源组中 Microsoft.Network/* 不为 Microsoft.Network/* 的资源。

{
    "if": {
        "allOf": [{
                "value": "[resourceGroup().name]",
                "like": "*netrg"
            },
            {
                "field": "type",
                "notLike": "Microsoft.Network/*"
            }
        ]
    },
    "then": {
        "effect": "deny"
    }
}

此策略规则示例使用 value 来检查多个嵌套函数的结果是否 equalstrue。 此规则拒绝并没有至少三个标记的资源。

{
    "mode": "indexed",
    "policyRule": {
        "if": {
            "value": "[less(length(field('tags')), 3)]",
            "equals": "true"
        },
        "then": {
            "effect": "deny"
        }
    }
}

避免模板失败

在 value 中使用模板函数允许使用许多复杂嵌套函数。 如果模板函数的结果是一个错误,则策略评估会失败。 评估失败是一种隐式拒绝。 在某些情况下失败的 value 示例:

{
    "policyRule": {
        "if": {
            "value": "[substring(field('name'), 0, 3)]",
            "equals": "abc"
        },
        "then": {
            "effect": "audit"
        }
    }
}

上面的示例策略规则使用 substring() 将名称的前三个字符与 abc 进行比较。 如果名称少于三个字符, 函数会导致错误。 此错误会导致策略变为“拒绝”效果。

相反地,请改用 if() 函数来检查名称的前三个字符是否等于 abc,不允许名称少于三个字符,这会导致错误:

{
    "policyRule": {
        "if": {
            "value": "[if(greaterOrEquals(length(field('name')), 3), substring(field('name'), 0, 3), 'not starting with abc')]",
            "equals": "abc"
        },
        "then": {
            "effect": "audit"
        }
    }
}

使用修订后的策略规则,if() 会先检查名称的长度,然后尝试在少于三个字符的值上获取 substring()。 如果名称太短,则会改为返回“不是以 abc 开头”的值,并将其与 abc 进行比较。 短名称不是以 abc 开头的资源仍会导致策略规则失败,但在评估过程中不会再造成错误。

计数

用于统计数组中有多少成员符合特定标准的条件可以使用“count”表达式来构建。 常见方案是检查是“至少有一个”数组成员、“正好有一个”数组成员、“所有”数组成员还是“没有”数组成员满足条件。 “count”会根据条件表达式评估每个数组成员,并将 true 结果求和,然后将其与表达式运算符进行比较。

字段计数

统计请求有效负载中的数组有多少成员符合条件表达式。 “字段计数”表达式的结构为:

{
    "count": {
        "field": "<[*] alias>",
        "where": {
            /* condition expression */
        }
    },
    "<condition>": "<compare the count of true condition expression array members to this value>"
}

以下属性与“字段计数”结合使用:

  • count.field(必需):包含数组路径,且必须为数组别名。
  • count.where(可选):用于分别评估 count.field 的每个 [*] 别名数组成员的条件表达式。 如果未提供此属性,具有“字段”路径的所有数组成员将评估为 true。 任何条件都可在此属性内使用。 可在此属性中使用逻辑运算符来创建复杂的评估要求。
  • <条件>(必需):该值与符合 count.where 条件表达式的项数进行比较。 应使用数字条件

有关如何在 Azure Policy 中使用数组属性的更多详细信息,包括有关“字段计数”表达式计算方式的详细说明,请参阅引用数组资源属性

值计数

统计数组中有多少成员符合条件。 数组可以是文本数组,也可以是对数组参数的引用。 “值计数”表达式的结构为:

{
    "count": {
        "value": "<literal array | array parameter reference>",
        "name": "<index name>",
        "where": {
            /* condition expression */
        }
    },
    "<condition>": "<compare the count of true condition expression array members to this value>"
}

以下属性与“值计数”结合使用:

  • count.value(必需):要评估的数组。
  • count.name(必需):索引名称,由英文字母和数字构成。 定义在当前迭代中评估的数组成员的值的名称。 该名称用于引用 count.where 条件内的当前值。 当 count 表达式不在另一个 count 表达式的子级中时,此项为可选 。 如果未提供此项,则索引名称将隐式设置为 "default"
  • count.where(可选):用于分别评估 count.value 的每个数组成员的条件表达式。 如果未提供此属性,则所有数组成员都将评估为 true。 任何条件都可在此属性内使用。 可在此属性中使用逻辑运算符来创建复杂的评估要求。 可以通过调用 current 函数来访问当前枚举的数组成员的值。
  • <条件>(必需):该值与符合 count.where 条件表达式的项数进行比较。 应使用数字条件

current 函数

current() 函数仅在 count.where 条件内可用。 它返回当前通过 count 表达式评估枚举的数组成员的值。

值计数用法

  • current(<index name defined in count.name>)。 例如:current('arrayMember')
  • current()。 只有当 value count 表达式不是另一个 count 表达式的子级时,才允许使用此函数 。 返回与上面的值相同的值。

如果调用返回的值是一个对象,则支持属性访问器。 例如:current('objectArrayMember').property

字段计数用法

  • current(<the array alias defined in count.field>)。 例如,current('Microsoft.Test/resource/enumeratedArray[*]')
  • current()。 只有当 field count 表达式不是另一个 count 表达式的子级时,才允许使用此函数 。 返回与上面的值相同的值。
  • current(<alias of a property of the array member>)。 例如,current('Microsoft.Test/resource/enumeratedArray[*].property')

字段计数示例

示例 1:检查数组是否为空

{
    "count": {
        "field": "Microsoft.Network/networkSecurityGroups/securityRules[*]"
    },
    "equals": 0
}

示例 2:检查是否只有一个数组成员符合条件表达式

{
    "count": {
        "field": "Microsoft.Network/networkSecurityGroups/securityRules[*]",
        "where": {
            "field": "Microsoft.Network/networkSecurityGroups/securityRules[*].description",
            "equals": "My unique description"
        }
    },
    "equals": 1
}

示例 3:检查是否至少有一个数组成员符合条件表达式

{
    "count": {
        "field": "Microsoft.Network/networkSecurityGroups/securityRules[*]",
        "where": {
            "field": "Microsoft.Network/networkSecurityGroups/securityRules[*].description",
            "equals": "My common description"
        }
    },
    "greaterOrEquals": 1
}

示例 4:检查是否所有对象数组成员都符合条件表达式

{
    "count": {
        "field": "Microsoft.Network/networkSecurityGroups/securityRules[*]",
        "where": {
            "field": "Microsoft.Network/networkSecurityGroups/securityRules[*].description",
            "equals": "description"
        }
    },
    "equals": "[length(field('Microsoft.Network/networkSecurityGroups/securityRules[*]'))]"
}

示例 5:检查是否至少有一个数组成员与条件表达式中的多个属性匹配

{
    "count": {
        "field": "Microsoft.Network/networkSecurityGroups/securityRules[*]",
        "where": {
            "allOf": [
                {
                    "field": "Microsoft.Network/networkSecurityGroups/securityRules[*].direction",
                    "equals": "Inbound"
                },
                {
                    "field": "Microsoft.Network/networkSecurityGroups/securityRules[*].access",
                    "equals": "Allow"
                },
                {
                    "field": "Microsoft.Network/networkSecurityGroups/securityRules[*].destinationPortRange",
                    "equals": "3389"
                }
            ]
        }
    },
    "greater": 0
}

示例 6:在 where 条件中使用 current() 函数来访问模板函数中当前枚举的数组成员的值。 此条件检查虚拟网络是否包含不在 10.0.0.0/24 CIDR 范围内的某个地址前缀。

{
    "count": {
        "field": "Microsoft.Network/virtualNetworks/addressSpace.addressPrefixes[*]",
        "where": {
          "value": "[ipRangeContains('10.0.0.0/24', current('Microsoft.Network/virtualNetworks/addressSpace.addressPrefixes[*]'))]",
          "equals": false
        }
    },
    "greater": 0
}

示例 7:在 where 条件中使用 field() 函数来访问当前枚举的数组成员的值。 此条件检查虚拟网络是否包含不在 10.0.0.0/24 CIDR 范围内的某个地址前缀。

{
    "count": {
        "field": "Microsoft.Network/virtualNetworks/addressSpace.addressPrefixes[*]",
        "where": {
          "value": "[ipRangeContains('10.0.0.0/24', first(field(('Microsoft.Network/virtualNetworks/addressSpace.addressPrefixes[*]')))]",
          "equals": false
        }
    },
    "greater": 0
}

值计数示例

示例 1:检查资源名称是否与任何给定的名称模式匹配。

{
    "count": {
        "value": [ "prefix1_*", "prefix2_*" ],
        "name": "pattern",
        "where": {
            "field": "name",
            "like": "[current('pattern')]"
        }
    },
    "greater": 0
}

示例 2:检查资源名称是否与任何给定的名称模式匹配。 current() 函数未指定索引名称。 结果与前面的示例相同。

{
    "count": {
        "value": [ "prefix1_*", "prefix2_*" ],
        "where": {
            "field": "name",
            "like": "[current()]"
        }
    },
    "greater": 0
}

示例 3:检查资源名称是否与数组参数提供的任何给定的名称模式匹配。

{
    "count": {
        "value": "[parameters('namePatterns')]",
        "name": "pattern",
        "where": {
            "field": "name",
            "like": "[current('pattern')]"
        }
    },
    "greater": 0
}

示例 4:检查是否有任何虚拟网络地址前缀不在批准的前缀的列表下。

{
    "count": {
        "field": "Microsoft.Network/virtualNetworks/addressSpace.addressPrefixes[*]",
        "where": {
            "count": {
                "value": "[parameters('approvedPrefixes')]",
                "name": "approvedPrefix",
                "where": {
                    "value": "[ipRangeContains(current('approvedPrefix'), current('Microsoft.Network/virtualNetworks/addressSpace.addressPrefixes[*]'))]",
                    "equals": true
                },
            },
            "equals": 0
        }
    },
    "greater": 0
}

示例 5:检查是否在 NSG 中定义了所有保留的 NSG 规则。 保留的 NSG 规则的属性是在一个包含对象的数组参数中定义的。

参数值:

[
    {
        "priority": 101,
        "access": "deny",
        "direction": "inbound",
        "destinationPortRange": 22
    },
    {
        "priority": 102,
        "access": "deny",
        "direction": "inbound",
        "destinationPortRange": 3389
    }
]

策略:

{
    "count": {
        "value": "[parameters('reservedNsgRules')]",
        "name": "reservedNsgRule",
        "where": {
            "count": {
                "field": "Microsoft.Network/networkSecurityGroups/securityRules[*]",
                "where": {
                    "allOf": [
                        {
                            "field": "Microsoft.Network/networkSecurityGroups/securityRules[*].priority",
                            "equals": "[current('reservedNsgRule').priority]"
                        },
                        {
                            "field": "Microsoft.Network/networkSecurityGroups/securityRules[*].access",
                            "equals": "[current('reservedNsgRule').access]"
                        },
                        {
                            "field": "Microsoft.Network/networkSecurityGroups/securityRules[*].direction",
                            "equals": "[current('reservedNsgRule').direction]"
                        },
                        {
                            "field": "Microsoft.Network/networkSecurityGroups/securityRules[*].destinationPortRange",
                            "equals": "[current('reservedNsgRule').destinationPortRange]"
                        }
                    ]
                }
            },
            "equals": 1
        }
    },
    "equals": "[length(parameters('reservedNsgRules'))]"
}

策略函数

函数可用于将其他逻辑引入策略规则。 在策略定义的策略规则内以及分配给计划中的策略定义的参数值内解析它们。

除了以下函数和用户定义的函数外,所有资源管理器模板函数均可在策略规则中使用:

  • copyIndex()
  • dateTimeAdd()
  • dateTimeFromEpoch
  • dateTimeToEpoch
  • deployment()
  • environment()
  • extensionResourceId()
  • lambda()
  • listAccountSas()
  • listKeys()
  • listSecrets()
  • list*
  • managementGroup()
  • newGuid()
  • pickZones()
  • providers()
  • reference()
  • resourceId()
  • subscriptionResourceId()
  • tenantResourceId()
  • tenant()
  • variables()

注意

在 deployIfNotExists 策略定义中,仍可在其模板部署的 details.deployment.properties.template 部分中使用这些函数。

以下函数可在策略规则中使用,但与在 Azure 资源管理器模板(ARM 模板)中使用不同:

  • utcNow() - 与 ARM 模板不同,该属性可以在 defaultValue 之外使用。
    • 以通用 ISO 8601 日期/时间格式“yyyy-MM-ddTHH:mm:ss.fffffffZ”返回设置为当前日期和时间的字符串。

以下函数仅适用于策略规则:

  • addDays(dateTime, numberOfDaysToAdd)

    • dateTime:[必需] 字符串 - 采用通用 ISO 8601 日期/时间格式“yyyy-MM-ddTHH:mm:ss.FFFFFFFZ”的字符串
    • numberOfDaysToAdd:[必需] 整数 - 要增加的天数
  • field(fieldName)

    • fieldName:[必需] 字符串 - 要检索的字段名称
    • 从 If 条件正在评估的资源返回该字段的值。
    • field 主要用于 fieldDeployIfNotExists,以引用所评估资源上的字段。 可以在 DeployIfNotExists 示例中看到这种用法的示例。
  • requestContext().apiVersion

    • 返回已触发策略评估的请求的 API 版本(示例:2021-09-01)。 该值是 PUT/PATCH 请求中用于对资源创建/更新进行评估的 API 版本。 在对现有资源进行符合性评估时,将会一律使用最新的 API 版本。
  • policy()

    • 返回有关正在评估的策略的下列信息。 可以从返回的对象访问属性,例如:[policy().assignmentId]

      {
        "assignmentId": "/subscriptions/ad404ddd-36a5-4ea8-b3e3-681e77487a63/providers/Microsoft.Authorization/policyAssignments/myAssignment",
        "definitionId": "/providers/Microsoft.Authorization/policyDefinitions/34c877ad-507e-4c82-993e-3452a6e0ad3c",
        "setDefinitionId": "/providers/Microsoft.Authorization/policySetDefinitions/42a694ed-f65e-42b2-aa9e-8052e9740a92",
        "definitionReferenceId": "StorageAccountNetworkACLs"
      }
      
  • ipRangeContains(range, targetRange)

    • range:[必需]字符串 - 指定 IP 地址范围的字符串,用于检查 targetRange 是否在其中。
    • targetRange:[必需]字符串 - 此字符串指定一个 IP 地址范围,需要验证它是否包含在 range 内。
    • 返回一个布尔值,指示 range IP 地址范围是否包含 targetRange IP 地址范围。 空范围或 IP 系列之间的混合是不允许的,这会导致评估失败。

    支持的格式:

    • 单个 IP 地址(示例:10.0.0.02001:0DB8::3:FFFE
    • CIDR 范围(示例:10.0.0.0/242001:0DB8::/110
    • 由起始 IP 地址和结束 IP 地址定义的范围(示例:192.168.0.1-192.168.0.92001:0DB8::-2001:0DB8::3:FFFF
  • current(indexName)

策略函数示例

此策略规则示例使用 resourceGroup 资源函数获取 resourceGroup 属性,并将该属性与 concat 数组和对象函数结合使用以构建 like 条件,该条件强制资源名称以资源组名称开头。

{
    "if": {
        "not": {
            "field": "name",
            "like": "[concat(resourceGroup().name,'*')]"
        }
    },
    "then": {
        "effect": "deny"
    }
}

策略规则限制

创作期间强制实施的限制

在创作或分配策略期间,将强制实施对策略规则结构的限制。 尝试创建或分配超出这些限制的策略定义将会失败。

限制 其他详细信息
if 条件中的条件表达式 4096
then 程序块中的条件表达式 128 适用于 AuditIfNotExists 和 DeployIfNotExists 策略的 existenceCondition
每个策略规则的策略函数 2048
参数的策略函数数目 128 示例: [function('parameter1', 'parameter2', ...)]
嵌套策略函数深度 64 示例: [function(nested1(nested2(...)))]
策略函数表达式字符串长度 81920 示例:"[function(....)]" 的长度
每个数组的字段计数表达式 5
每个策略规则的值计数表达式 10
值计数表达式迭代计数 100 对于嵌套值计数表达式,这还包括父表达式的迭代计数

评估期间强制实施的限制

在策略评估期间由策略函数处理的对象的大小限制。 根据评估内容,这些限制在创作期间不会一直强制执行。 例如:

{
    "field": "name",
    "equals": "[concat(field('stringPropertyA'), field('stringPropertyB'))]"
}

concat() 函数创建的字符串的长度取决于评估资源中属性的值。

限制 示例
函数返回的字符串的长度 131072 [concat(field('longString1'), field('longString2'))]
作为参数提供给函数或由函数返回的复杂对象的深度 128 [union(field('largeObject1'), field('largeObject2'))]
作为参数提供给函数或由函数返回的复杂对象的节点数 32768 [concat(field('largeArray1'), field('largeArray2'))]

警告

在评估期间超过上述限制的策略将实际上成为拒绝策略,并可以阻止传入请求。 使用复杂函数编写策略时,请注意这些限制,并针对可能超过这些限制的资源测试这些策略。

别名

可以使用属性别名来访问资源类型的特定属性。 通过别名,可限制允许用于资源属性的值和条件。 每个别名会映射到给定资源类型不同 API 版本的路径。 在策略评估期间,策略引擎会获取该 API 版本的属性路径。

别名列表始终不断增长。 若要找出 Azure Policy 当前支持哪些别名,请使用以下方法之一:

  • 适用于 Visual Studio Code 的 Azure Policy 扩展(推荐)

    使用适用于 Visual Studio Code 的 Azure Policy 扩展来查看和发现资源属性的别名。

    Visual Studio Code 的 Azure Policy 扩展的屏幕截图,鼠标悬停在属性上以显示别名。

  • Azure PowerShell

    # Login first with Connect-AzAccount
    Connect-AzAccount -Environment AzureChinaCloud
    
    # Use Get-AzPolicyAlias to list available providers
    Get-AzPolicyAlias -ListAvailable
    
    # Use Get-AzPolicyAlias to list aliases for a Namespace (such as Azure Compute -- Microsoft.Compute)
    (Get-AzPolicyAlias -NamespaceMatch 'compute').Aliases
    

    注意

    若要查找可用于修改效果的别名,请在 Azure PowerShell 4.6.0 或更高版本中使用以下命令:

    Get-AzPolicyAlias | Select-Object -ExpandProperty 'Aliases' | Where-Object { $_.DefaultMetadata.Attributes -eq 'Modifiable' }
    
  • Azure CLI

    # Login first with following commands
    az cloud set -n AzureChinaCloud
    az login
    
    # List namespaces
    az provider list --query [*].namespace
    
    # Get Azure Policy aliases for a specific Namespace (such as Azure Compute -- Microsoft.Compute)
    az provider show --namespace Microsoft.Compute --expand "resourceTypes/aliases" --query "resourceTypes[].aliases[].name"
    
  • REST API/ARMClient

    GET https://management.chinacloudapi.cn/providers/?api-version=2019-10-01&$expand=resourceTypes/aliases
    

了解 [*] 别名

很多可用的别名都会有一个显示为“正常”名称的版本,以及一个附加有 [*] 的版本。 例如:

  • Microsoft.Storage/storageAccounts/networkAcls.ipRules
  • Microsoft.Storage/storageAccounts/networkAcls.ipRules[*]

“正常”别名会将该字段表示为单个值。 当整个值集必须与定义完全一致,不能多也不能少时,此字段适用于精确匹配的比较场景。

[*] 别名表示从数组资源属性的元素中所选的值的集合。 例如:

Alias 选定值
Microsoft.Storage/storageAccounts/networkAcls.ipRules[*] ipRules 数组的元素。
Microsoft.Storage/storageAccounts/networkAcls.ipRules[*].action ipRules 数组的每个元素中的 action 属性的值。

字段条件中使用数组别名时,可以将每个单独的数组元素与目标值进行比较。 与 count 表达式结合使用时,可以执行以下操作:

  • 检查数组的大小
  • 检查是否所有或任意数组元素均满足复杂条件,或者是否没有数组元素满足复杂条件
  • 检查是否恰好有 n 个数组元素满足复杂条件

有关详细信息和示例,请参阅引用数组资源属性

效果

Azure Policy 支持以下类型的效果:

  • Append:会将定义的字段集添加到请求
  • Audit:会在活动日志中生成一个警告事件,但不会使请求失败
  • AuditIfNotExists:如果相关资源不存在,则会在活动日志中生成一个警告事件
  • Deny:在活动日志中生成事件,并根据请求的资源配置使请求失败
  • DenyAction:在活动日志中生成事件,并根据请求的操作使请求失败
  • DeployIfNotExists:如果相关资源不存在,则部署该资源
  • Disabled:不评估资源是否符合策略规则
  • 修改:添加、更新或移除请求中定义的字段集
  • EnforceOPAConstraint(已弃用):针对 Azure 上的自托管 Kubernetes 群集,配置 Open Policy Agent 许可控制器与 Gatekeeper v3
  • EnforceRegoPolicy(已弃用):在 Azure Kubernetes 服务中,配置 Open Policy Agent 许可控制器与 Gatekeeper v2

有关每种效果、评估顺序、属性和示例的完整详细信息,请参阅了解 Azure Policy 效果

后续步骤