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无法区分首次创建和后续更新。
基于此,我们设计了三步走策略:
- 创建 Audit 策略:仅扫描和标记不合规的资源,不阻止任何操作。
- 添加豁免(Exemption):对已存在的合规资源赋予豁免权,允许后续修改。
- 转换为 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 逐个添加,或者使用资源选择器批量操作:

在添加豁免时,需要选择 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.

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

至此,我们成功实现了拒绝新建但允许修改的精细控制。这种方案在 Python、JavaScript、Go 等语言的云开发实践中也非常实用,例如在 CI/CD 流水线中动态调整策略。
❓ 常见问题与注意事项
Q:是否可以在转换为 Deny 后再添加豁免?
❌ 不可以。因为添加豁免本身也是对资源的修改操作,如果策略已经是 Deny 状态,该操作会被阻止,得到如下错误:

因此,务必在转换之前完成所有豁免操作。这类似于编程中的 事务提交:先准备数据(豁免),再锁定(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
浙公网安备 33010602011771号