☰
Azure Resource Graph查询Azure Policy策略分配与符合性状态实战
2026/10/2 9:35:50 网站建设 项目流程

先说个现象。很多团队的云治理一开始都是靠人盯,订阅少的时候还能应付,等规模上来之后,光靠 Azure Portal 一个个点开资源组看策略是否合规,效率就完全跟不上了。这时候 Azure Policy 已经把"能不能创建这个资源、资源必须带哪些标签"这种治理规则铺到了订阅里,真正缺的是一个统一的、跨订阅的、能快速回答"哪些资源不合规、哪个策略被分到了哪个作用域、内置策略和自定义策略各有多少"的查询通道。Azure Resource Graph(简称 ARG)就是干这个用的。

这篇内容围绕"用 Azure Resource Graph 查询策略分配、符合性状态以及策略定义"展开,适合正在做云治理、安全审计、成本管控或迁移评估的运维工程师、DevOps 和架构师。不夸张地说,看完之后你基本能够丢掉到处点鼠标的习惯,直接用一条 KQL 把治理台账拉出来,再也不用靠 Excel 手工汇总。

1. 场景破题:为什么查 Azure Policy 资料要用 ARG 而不是控制台点鼠标

1.1 云治理的"信息迷雾"困境

说一个实际场景:某团队管理 8 个订阅,里面既有生产环境又有测试环境,创建了 30 多个策略分配,既有内置策略(比如"不允许创建公网 IP 的虚拟机"),又有自定义策略(比如"所有资源必须带 cost-center 标签")。某天审计要求提供一次全量的合规性报告,工程师的做法是什么?大概率是打开 Policy 页面,选中某个订阅,再选中某个策略分配,看下面列出多少不合法资源,截图、复制,再切换下一个。光是收集这些数据,一个上午就没了。

这是一个典型的信息孤岛问题:数据存在,但分散在多个视图中,缺少一个能全局检索的入口。更麻烦的是,策略定义、策略分配、符合性状态这三类数据本身是相互关联的,但在 Portal 上你通常需要跳转多个页面才能把它们对应起来。策略分配到某个管理组,定义在另一个页面,符合性评估结果又是另一个接口返回的东西。要手动把这些数据对齐,几乎等于在几千条 JSON 里做 vlookup。

这时候就到了 ARG 该出场的时机。Azure Resource Graph 本质上是 Azure 控制平面之上的一个索引服务,它预先把资源属性、策略信息、变更历史等构建成可查询的数据表,通过 Kusto Query Language(KQL)提供跨订阅的快速检索能力。最关键的一点,它同一时刻可以扫过你拥有读取权限的所有订阅,而不是让你一个个订阅去切换查。这条特性能直接解决"信息迷雾"里的第一个问题:看不到全貌。

1.2 ARG 相比其他查询路径的差异化优势

先别急着直接写 KQL,我们需要把这条技术路线和其他几种可行路线对比一下,你才知道什么时候用哪个。

用 Azure CLI 的az policy assignment list之类命令去查,当然也可以,但它的输出是一次性快照,拿到的是某个资源某时刻的状态。如果你想做的是"所有策略分配的完整清单 + 每个分配对应的符合性统计 + 策略定义的类别和参数",CLI 得写好几条命令,再用脚本把结果串起来,过程中还要处理 JSON 嵌套和分页问题。而且 CLI 命令通常面向"管理操作",不是面向"复杂条件检索",它的输出格式和查询能力都有限。

用 ARM API 去查属于另一条路径,灵活度更高,能拿到原始 JSON,但代价是要处理 API 版本、分页 token、不同资源类型的不同接口,写出的脚本维护成本很高。ARG 相当于把"繁杂的 API 拼接"这一步给你省掉了,让你直接对着已经整理好的逻辑视图写查询。

这里要补充一个容易忽略的关键点:ARG 的数据是有索引延迟的。它不是实时数据源,而是一个异步构建的索引。资源属性变化之后,通常要等几分钟才会在 ARG 中反映。这点我会在后面的排查部分详细展开。所以如果你要做的操作是对实时性要求极高的合规强校验(比如刚创建完策略就立刻查),那 ARG 未必是第一选择;但如果你是要生成日报、周报、审计报表,或者做一个全局治理大盘,ARG 就是最优解。它的查询响应通常在秒级,能在几秒内扫完成千上万的资源并给出聚合结果,这个能力是 Portal 点鼠标完全给不了的。

我做一个简单对比表,方便你按场景快速决策:

查询方式跨订阅能力复杂条件检索实时性脚本友好度典型场景
Azure Portal Policy 页面弱,需逐订阅切换弱,视图像素级检索较高差单资源排查、临时查看
Azure CLI/Az PowerShell中,需要循环订阅中,命令受参数限制较高(直接调控制平面)中运维脚本、自动化修复
ARM API中,需要写循环和 token 处理高,但需要拼接大量接口较高中深度集成、平台开发
Azure Resource Graph强,一次查询覆盖全部授权订阅强,KQL 支持聚合、过滤、join中等,索引延迟分钟级高治理盘点、报表统计、监控大盘、审计查询

2. 先补基础:策略分配、符合性状态与策略定义在 ARG 里到底长什么样

2.1 三个核心概念的分工

在写查询之前,必须把这三个术语的关系理顺,否则你在 KQL 里面很容易混淆字段来源。

策略定义(Policy Definition)是最上层的规则描述,它回答"规则是什么"。内置定义由微软提供,比如"Allowed locations"定义了一个区域白名单;自定义定义则由团队根据自身需求编写 JSON,比如"所有资源必须包含某个标签"。一个定义本身不产生任何实际效果,它就是一份规则说明书。定义还分 Policy 和 Initiative(即 PolicySetDefinition,策略计划),后者是一组策略定义的集合。在 ARG 的 policyresources 表中,这两种定义都在,类型有microsoft.authorization/policydefinitions和microsoft.authorization/policysetdefinitions。

策略分配(Policy Assignment)是把规则落到实际作用域的动作,它回答"规则在哪生效"。同一个定义可以分配给管理组、订阅或资源组,而且在分配时可以传入参数值,比如定义是"允许的区域列表",分配时具体填入中国东部、中国北部这些值。所以一个定义可能对应多个分配,每个分配在自己的作用域内产生评估结果。

符合性状态(Compliance State)是策略评估之后产出的结果,回答"资源当前是否符合规则"。这个状态来自 Policy Insights 的持续评估和按需评估结果。常见状态包括 Compliant(合规)、NonCompliant(不合规)、NotStarted(未开始评估)、Exempt(豁免)和 Conflict(多个策略分配规则冲突导致无法判定)等。

这三个概念是三层结构:定义是模板,分配是实例,符合性状态是实例作用于真实资源后的反馈。在 ARG 里,定义和分配存在policyresources表,符合性状态则主要在policyinsights表(确切说,ARG 暴露为policyinsights的扩展资源类型)中体现。如果你已经把资源管理和治理数据混在一起,那在查询时就要特别注意这两类数据表的使用区别。

2.2 ARG 中 policyresources 和 policyinsights 两张表的数据结构

打开 ARG Explorer 的 schema 侧边栏,你就能看到policyresources这个资源表。它有点特殊,因为它存储的不是单一资源类型的属性,而是多个授权相关资源类型的聚合。在type字段里,你可以看到microsoft.authorization/policydefinitions、microsoft.authorization/policyassignments、microsoft.authorization/policysetdefinitions等类型值。换句话说,你只需要查policyresources这张表,再按 type 过滤,就能把定义和分配统一捞出来。

policyresources中比较关键的字段包括:

  • name:资源名称。对定义而言是定义名,对分配而言是分配名。
  • type:资源类型,用于区分定义、计划、分配。
  • subscriptionId:作用域所在的订阅。注意管理组层面的定义或分配,subscriptionId 可能为空。
  • properties.displayName:显示名称,通常比 name 字段更可读。
  • properties.policyDefinitionId:分配关联的策略定义 ID,格式类似/subscriptions/{subId}/providers/Microsoft.Authorization/policyDefinitions/{name}。
  • properties.policyDefinitionReferenceId:普通分配没有,只有计划分配(Initiative Assignment)中引用特定策略时才出现。
  • properties.scope:分配的作用域,这是核心字段。
  • properties.parameters:分配的参数化配置,JSON 格式。

policyinsights表承载的是策略评估后的符合性状态数据。它相比policyresources更"动态",因为它是评估引擎不断写入的结果。在这个表里,你会看到:

  • resourceId:被评估的资源的完整 Azure 资源 ID。
  • properties.complianceState:合规状态值,如 Compliant、NonCompliant。
  • properties.policyAssignmentName:对应策略分配的名称。
  • properties.policyDefinitionName:对应策略定义名称。
  • properties.policyAssignmentScope:策略分配的作用域。
  • properties.timestamp:评估结果的时间戳。

把这两张表搞清楚了,接下来写查询就是在做两张逻辑表的关联和过滤。打个比方,policyresources相当于项目的配置清单,policyinsights相当于项目的质检工单。前者告诉你"我们定了哪些标准,在哪些区域执行",后者告诉你"哪些工件通过了、哪些违反了标准"。

2.3 理解查询延迟和索引窗口

使用 ARG 一定要在心里放一根弦:这不是实时数据库。ARG 的后端会持续从 Azure Resource Manager 拉取资源状态、策略评估结果,然后构建索引进可查询的表。但这个过程有天然延迟,通常官方建议你接受"分钟级"延迟。我自己实测下来,资源的新增和策略分配的变更在几分钟内基本能查到,但有些极端情况(比如评估任务还没跑完)可能需要更久。

这样设计是有原因的。ARG 追求的是"大规模的快速查询",它用预建索引换取了搜索性能。如果你能做到实时,那意味着每次查询都要直接打到控制平面做全量扫描,速度和跨订阅能力就会大打折扣。所以 ARG 的定位从来不是替代 ARM API,而是提供一个面向治理、检索、聚合场景的分析型数据源。理解了这一点,你就知道什么时候该用 ARG,什么时候该用az policy state list这些命令直接找 Policy Insights 接口。

3. 实操实录:核心 KQL 查询与真实返回解读

3.1 查询所有策略分配:先给治理台账拍一张快照

既然是要借助 ARG 查询,那第一个实操就是从策略分配这个"治理动作"入口展开。在 ARG Explorer 里输入下面这条查询:

policyresources | where type =~ "microsoft.authorization/policyassignments" | project subscriptionId, name, properties.displayName, properties.scope, properties.policyDefinitionId, properties.parameters | sort by subscriptionId asc, properties.scope asc

这条查询会返回当前你拥有读取权限的所有订阅中的所有策略分配。这里的关键过滤条件是type =~ "microsoft.authorization/policyassignments",大小写不敏感匹配,这样就把表内混杂的 policydefinitions 和 policysetdefinitions 过滤掉了。project则用来裁剪字段,让输出结果更聚焦。

一个很实用的进阶版本是顺带统计每个策略分配在哪个作用域、挂在哪个订阅下,同时把策略定义类型(Policy 还是 Initiative)也标记出来:

policyresources | where type =~ "microsoft.authorization/policyassignments" | extend definitionId = tolower(properties.policyDefinitionId) | join kind = leftouter ( policyresources | where type =~ "microsoft.authorization/policydefinitions" or type =~ "microsoft.authorization/policysetdefinitions" | project definitionId = tolower(id), definitionType = type, definitionDisplayName = properties.displayName ) on definitionId | project subscriptionId, assignmentName = name, assignmentDisplayName = properties.displayName, scope = properties.scope, definitionId, definitionType, definitionDisplayName | order by scope asc

这里用join把策略分配和策略定义关联起来了,通过policyDefinitionId字段匹配到定义表里的id字段。注意我把两边都做了tolower,原因是不同来源的 ID 可能大小写不一致,直接 join 很容易漏数据。这是我在实战中踩过的坑,后来养成了 join 之前先规范字段的习惯。

输出结果后,你应该就能看到一份完整的策略分配台账。如果你管理多个订阅,并且启用了管理组,分配可能出现在管理组层级,这时候properties.scope就会显示为/providers/Microsoft.Management/managementGroups/{mgName},订阅字段为空。遇到这种情况不要慌,说明该分配管的是这个管理组下的所有子订阅。

3.2 查询策略定义:把内置策略和自定义策略拉成一张清单

策略定义的数据也是放在policyresources里的,区别在于 type 不同。要查询所有策略定义(不含计划),可以这样写:

policyresources | where type =~ "microsoft.authorization/policydefinitions" | project id, name, displayName = properties.displayName, policyType = properties.policyType, description = properties.description | sort by policyType asc, displayName asc

注意properties.policyType这个字段,它会区分BuiltIn(内置)和Custom(自定义)。这个字段在做治理盘点时价值极高。内置策略大多是微软预设的通用基线,自定义策略才是你团队真正投入精力设计的东西。所以你可以用下面这条快速统计自定义策略的占比:

policyresources | where type =~ "microsoft.authorization/policydefinitions" | summarize count() by policyType = properties.policyType

这条查询返回两行结果:BuiltIn 多少个,Custom 多少个。如果你发现 Custom 数量特别少,说明团队治理能力还比较初级,大量规则依赖微软默认基线;反过来如果一个订阅下 Custom 比 BuiltIn 还多,治理成本会显著上升,需要关注策略之间的覆盖和冲突。

如果你要查的是 Initiative(策略计划),即一组策略定义的集合,那 type 改为microsoft.authorization/policysetdefinitions即可。在我们的治理实践中,计划的使用非常推荐,因为将多个定义打包成一个"合规框架"之后,可以一次性分配给订阅或管理组,后续查询也更好对应。在 ARG 中查询计划分配的关联定义时,稍微麻烦一点,因为计划分配引用的是计划中的各个定义引用 ID,你需要解析properties.policyDefinitionReferenceId字段来关联。

一个实际可用的扩展查询:把分配给某个管理组或订阅的所有策略定义、计划以及它们的类型一并列出来:

policyresources | where type =~ "microsoft.authorization/policyassignments" | where properties.scope startswith "/providers/Microsoft.Management/managementGroups/contoso-mg" | project assignmentName = name, definitionId = tolower(properties.policyDefinitionId) | join kind = innerunique ( policyresources | where type =~ "microsoft.authorization/policydefinitions" or type =~ "microsoft.authorization/policysetdefinitions" | project definitionId = tolower(id), definitionType = type, displayName = properties.displayName, policyType = properties.policyType ) on definitionId | project-away definitionId

这条我会在生成治理报告时反复使用。它比在 Portal 上逐个展开管理组里的分配快得多,而且可以直接灌进 Power BI 或 Excel 做后续分析。

3.3 查询符合性状态:找到不合规资源才是治理的第一动力

列出定义和分配只是第一步,真正让治理产生价值的是找出不合规资源。这部分数据在policyinsights表里。下方这条查询是日常巡检的高频入口:

policyinsights | where properties.complianceState == "NonCompliant" | project resourceId, policyAssignmentName = properties.policyAssignmentName, policyDefinitionName = properties.policyDefinitionName, complianceState = properties.complianceState, assignmentScope = properties.policyAssignmentScope | take 1000

如果需要按订阅聚合统计不合规资源数量,可以使用:

policyinsights | where properties.complianceState == "NonCompliant" | extend subscriptionId = tostring(split(resourceId, "/")[2]) | summarize nonCompliantResourceCount = count() by subscriptionId | order by nonCompliantResourceCount desc

这条查询在处理跨订阅巡检时价值明显。它直接按订阅分组统计了不合规资源数,让你一眼就能看出哪个订阅是重灾区。我通常在月报里跑这条,在订阅数量几十个的情况下,这条查询仍然能在几秒内返回结果,这在以前很难做到。

如果你要更进一步,希望看到"哪个策略分配导致的不合规数量最多",就再按分配名称聚合:

policyinsights | where properties.complianceState == "NonCompliant" | summarize nonCompliantCount = count() by policyAssignmentName = properties.policyAssignmentName, policyDefinitionName = properties.policyDefinitionName | order by nonCompliantCount desc

返回结果的第一行往往就是"当前治理缺口最大的策略",值得优先处理。我见过很多团队的策略评估结果一塌糊涂,但根本不知道问题出在哪条策略上,就是因为没有做这种聚合分析。用 ARG 跑一次这个查询,答案就摆在眼前了。

3.4 进阶组合:跨订阅汇总、按资源分组、关联分配与定义

前面几个查询是单个逻辑表的操作,但 ARG 真正的威力在跨表关联。除了join之外,你还可以把策略数据和资源数据联合使用。比如想查看"所有不合规虚拟机及其所在资源组":

policyinsights | where properties.complianceState == "NonCompliant" | where resourceId startswith "/subscriptions/" | project resourceId, policyAssignmentName = properties.policyAssignmentName, policyDefinitionName = properties.policyDefinitionName | join kind = innerunique ( resources | where type =~ "microsoft.compute/virtualmachines" | project resourceId = id, vmName = name, resourceGroup, location ) on resourceId | project resourceId, vmName, resourceGroup, location, policyAssignmentName, policyDefinitionName

这条查询把策略评估结果和资源表连接起来了,定位到"哪台虚拟机因为哪条策略不合规"。相比去 Portal 一条条翻,这个方式可以直接输出表格给负责整改的同事,让他们分区域、分资源组去修复。这也是 ARG 跨数据源关联的典型用法。

还可以做时间维度上的洞察。policyinsights表带时间戳,你可以查询某个时间点之后的合规状态变化,用于运维报告和整改效果跟踪:

policyinsights | where properties.complianceState == "NonCompliant" | where properties.timestamp >= datetime("2025-01-01T00:00:00Z") | summarize nonCompliantCount = count() by bin(properties.timestamp, 1d) | order by properties.timestamp asc

这条按天聚合的查询,可以生成一张趋势图,观察不合规数量随时间的变化。在整改推动过程中,这种趋势数据很有说服力:到底是策略太严格、还是资源老化、还是评估规则触发有问题,趋势一目了然。当然,用得多了你会发展出自己的查询库,但上面这些是入门的金三角。

4. 常见问题与排查技巧实录

4.1 为什么我查不到刚创建的策略

最常被问到的问题就是:"我刚刚创建了一个自定义策略分配,为什么 ARG 里查不到?"原因几乎都是索引延迟。ARG 建立索引需要时间,官方不保证实时性。策略分配这种控制平面资源,变更后通常要等几分钟才能被索引。

我的建议是:不要刚操作完立刻去 ARG 验证结果,稍微等一下再查。如果等了几分钟依然没有,再去检查权限、作用域和类型过滤条件。日常自动化脚本里,如果对实时性要求高,可以在创建策略后用 ARM API 或 CLI 做即时验证;如果只是做治理报表,那 ARG 的延迟完全可以接受。

另外值得注意,policyinsights表里的符合性状态不是立刻生成的。Azure Policy 的评估是异步执行的,你在创建完策略分配后,需要等待首次评估完成才会产出状态结果。如果你发现 ARG 里policyinsights是空的,先确认策略分配是否已生效、评估是否已经触发,必要时手动触发评估(在 Azure Policy 页面点"评估"按钮)。

4.2 查询结果超过 1000 条怎么办

ARG 查询默认单次返回最多 1000 条结果。这个限制经常让新手措手不及。如果你的资源数量很多,只看到 1000 条却不提示,就很容易产生"数据是完整"的错觉。

解决办法有几种。第一种是用summarize做聚合,让返回行数下降,比如统计计数而不是列出所有资源。第二种是使用分页,在 PowerShell 的Search-AzGraph中通过分页参数循环拉取所有结果,或使用 Azure CLI 中的--skip参数配合操作。第三种是优化查询条件,增加过滤,分批查询,比如按订阅拆分,或者按资源类型拆分。

ARG 官方文档里其实有说明,分页查询中如果不显式处理分页 token,工具的 SDK 通常会帮你循环抓取,但是在 ARG Explorer 网页里,你更容易看到截断结果。我的经验是:在写查询时尽量先做聚合和裁剪,不要用project *全量返回,这样既能减少数据量,也更容易发现数据模式上的问题。

4.3 权限不足和 API 报错处理

ARG 查询不是所有身份都能直接跑通的。它要求查询者在目标订阅或管理组上至少拥有Microsoft.ResourceGraph/resources/read权限。如果你用的是订阅的 Reader 角色,那没问题;如果你用的是自定义角色,就要注意是否包含这个权限点。很多时候你发现某条查询在其他订阅能跑通,在某个订阅却返回空结果或报错,原因就是缺少资源图读取权限,而不是数据不存在。

此外,返回 HTTP 403 时常见的原因还包括:跨租户查询时没有 Guest User 权限、管理组没有授权、或者某些订阅状态异常(比如订阅被禁用)。如果你正在做的是跨租户的 Azure Lighthouse 管理,还要注意 ARG 对 delegated 资源的支持情况。排查这类问题,最有效的办法是先限定单订阅、单资源组,逐层缩小范围,定位到底是什么环节报错。

4.4 这几种查询最常用的落地场景

分享两个我实际做过的高价值落地场景。第一个是年度治理审计。我们的合规团队要求提供一份"所有策略分配的全量清单 + 每个分配的符合性统计"表格。以前合规工程师需要从多个页面手工导出,做出来要两天。后来我直接用 ARG 查了三张表:policyresources得到定义和分配,policyinsights做聚合统计,再用summarize把两类数据合并成最终报告。当天下午就交付了,之后每个月自动跑一次,配合Export to CSV就能生成口径一致的合规月报。

第二个场景是迁移评估。我们准备把一批老旧虚拟机从本地数据中心迁移到 Azure,但不确定它们是否符合当前订阅中的策略要求。我先用 ARG 查询了目标订阅的全部策略定义,整理出现有规则清单,然后在资源尚未真正创建时就知道了"哪些策略可能会卡住迁移"。我们甚至用 ARG 模拟了迁移后的状态,将这些规则与新资源的属性做对照。这个方法在计划迁移阶段特别实用,避免了资源和成本投入后才发现策略不匹配的尴尬。

说到底,ARG 的核心价值是让你在治理层面不再"盲人摸象"。你可以用 ARG 做资产盘点,可以用它做合规检查,还可以把它接入自动化流程,定期清理不合规资源。我个人的经验是,凡是涉及"跨订阅的批量检索"和"治理状态报告"的场景,优先想到 ARG 就对了。数据模型不需要背得很细,打开 ARG Explorer 用提示功能边写边探索,再配合本文这些查询骨架,很快就能形成你自己的查询模板库。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询