Azure Policy 进阶:拒绝新建资源但允许修改已有资源的最佳实践

在管理 Azure 云资源时,我们经常遇到这样的需求:禁止创建新的资源,但允许对已经存在的资源进行修改或删除。这种精细化的控制策略在企业级合规管理和成本优化中尤为重要。本文将通过 Azure Policy 的巧妙组合,为您提供一套经过验证的解决方案。

问题背景与挑战

假设您正在管理一个大型云环境,其中包含数百个虚拟机、数据库和缓存实例。某天,安全团队要求:禁止在中国东部二区(China East 2)创建任何新的 Redis 缓存或 SQL 数据库,但已有的资源必须能够正常修改配置、打补丁或扩容。

为了避免资源的随意创建或是从成本考虑,只能对已有资源进行修改,不允许创建新的资源。

直接使用 Azure Policy 的 Deny 效果会如何?它会一视同仁地阻止所有操作——无论新建、修改还是删除。这显然不符合要求。 我们需要一种更聪明的策略:先审计(Audit),再豁免(Exemption),最后拒绝(Deny)

思路解析:Audit → Exemption → Deny

在探索过程中,我首先咨询了大语言模型(如 GPT-4、Claude),得到了类似的建议:

Azure Policy本身是一个治理工具,它通过定义策略来控制资源的创建和配置,但它的能力有一些限制:

能否区分“新建”和“修改”?

  • Azure Policy主要在资源创建或更新时触发,但它无法直接判断操作是“新建”还是“修改”,因为在技术上,两者都是 PUT 请求。
  • Policy的effect(如 deny,audit )会在资源属性不符合策略时生效,而不是基于操作类型。

是否可以实现“拒绝新建,允许修改”?

直接实现:不行,因为Policy无法区分首次创建和后续更新。

基于此,我们设计了三步走策略:

  1. 创建 Audit 策略:仅扫描和标记不合规的资源,不阻止任何操作。
  2. 添加豁免(Exemption):对已存在的合规资源赋予豁免权,允许后续修改。
  3. 转换为 Deny 策略:将 Audit 改为 Deny,阻止新建资源。

已存在的资源就会被豁免不进行策略评估,而新建资源因为不在豁免列表中,所以会被Deny策略拒绝

这种思路类似于编程中的 白名单模式:先允许所有操作,记录违规行为,然后对已有资源打上“免检”标签,最后关闭大门。在 Java、JavaScript、Go、Python 或 C++ 中,我们经常用类似的设计模式(如策略模式或装饰器模式)来实现动态规则变更。

⚙️ 第一步:创建并分配 Audit 策略

首先,我们需要定义一个 Audit 策略,其作用域锁定为中国东部二区数据中心。策略 JSON 内容如下:

{
  "mode": "All",
  "policyRule": {
    "if": {
      "field": "location",
      "In": "[parameters('disAllowedLocations')]"
    },
    "then": {
      "effect": "Audit"
    }
  },
  "parameters": {
    "disAllowedLocations": {
      "type": "Array",
      "metadata": {
        "displayName": "Disallowed locations",
        "description": "The list of allowed locations for resources.",
        "strongType": "location"
      }
    }
  }
}

创建完成后,将其分配给目标订阅或资源组。接着触发策略评估(可以通过 Azure CLI、PowerShell 或 Portal 手动触发)。查看合规性结果:

PS: 为避免等待,可以使用 az policy state trigger-scan --resource-group "your resource group name" 来触发策略评估

在合规性面板中,您会看到所有位于 China East 2 的 Redis 和 SQL 资源被标记为 Non-compliant。此时,这些资源仍然可以正常修改——因为 Audit 策略只记录,不阻止。

️ 第二步:为合规资源添加豁免

关键步骤来了:我们需要为每一个已存在的资源添加豁免(Exemption),这样当策略变为 Deny 时,这些资源依然可以修改。您可以通过 Azure Portal 逐个添加,或者使用资源选择器批量操作:

image

在添加豁免时,需要选择 Exemption category

  • Waiver:完全豁免,资源不再受策略影响。
  • Mitigated:资源本身合规,但策略仍会评估。

Waiver 的含义 表示该资源或范围完全豁免策略评估,即策略不再对它进行合规性检查。

  效果:策略不会再标记该资源为“不合规”,不会触发  或 。

Mitigated的含义 表示该资源仍然不符合策略要求,但由于有补偿措施(Mitigation),所以不再视为风险。

  效果:策略仍会评估,但在合规报告中标记为“已缓解”(Mitigated),不会影响整体合规评分。

⚠️ 重要提示:如果遗漏了某个资源,后续转换为 Deny 后,该资源将无法进行任何修改。因此,建议使用脚本或 az policy exemption create 命令批量添加,确保覆盖所有需要保留的资源。

第三步:将 Audit 策略转换为 Deny 策略

当所有需要保留的资源都已获得豁免后,我们就可以修改策略定义。回到第一步创建的 Policy Definition,点击 Edit Definition,将:

 { "effect": "Audit" }

修改为:

 { "effect": "Deny" }

保存后,策略立即生效。现在,任何尝试在 China East 2 创建新 Redis 或 SQL 资源的操作都会被阻止。

✅ 第四步与第五步:验证效果

测试新建资源:在 Portal 或通过 CLI 尝试创建 Redis 缓存,您会看到类似这样的错误:

Deployment validation failed.

Additional details from the underlying API that might be helpful: The template deployment failed because of policy violation.

Please see details for more information.

image

测试修改已有资源:对第二步中已豁免的 Redis 资源进行配置修改(例如缩放容量、更改 SKU),操作成功!

image

至此,我们成功实现了拒绝新建但允许修改的精细控制。这种方案在 Python、JavaScript、Go 等语言的云开发实践中也非常实用,例如在 CI/CD 流水线中动态调整策略。

❓ 常见问题与注意事项

Q:是否可以在转换为 Deny 后再添加豁免?

❌ 不可以。因为添加豁免本身也是对资源的修改操作,如果策略已经是 Deny 状态,该操作会被阻止,得到如下错误:

image

因此,务必在转换之前完成所有豁免操作。这类似于编程中的 事务提交:先准备数据(豁免),再锁定(Deny)。

参考资料与延伸阅读

Azure Policy 豁免结构官方文档:https://docs.azure.cn/zh-cn/governance/policy/concepts/exemption-structure

[AFFILIATE_SLOT_1]

在复杂的环境中,我们需要像调试 Java 代码一样,逐步排查并调整策略。记住:浊而静之徐清,安以动之徐生——先审计,再豁免,最后拒绝,每一步都不可颠倒。

总结

本文通过三步法(Audit → Exemption → Deny)解决了 Azure Policy 无法区分新建与修改操作的痛点。关键要点:

  • 使用 Audit 策略先标记不合规资源。
  • ️ 为已有资源添加豁免,确保它们不受后续 Deny 影响。
  • 最后转换为 Deny,阻止新建。

这种方法不仅适用于 Redis 和 SQL,也可推广到任何 Azure 资源类型。如果您在 Go、C++ 或 Python 项目中集成 Azure SDK,同样可以自动化这一流程。

[AFFILIATE_SLOT_2]

denyaudit
posted @ 2026-05-08 09:34  ycfenxi  阅读(6)  评论(0)    收藏  举报