You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Azure Key Vault私有端点强制策略设为Deny时分开部署遭拦截的技术问询

解决Azure Key Vault与私有端点分开部署时的Deny策略拦截问题

我完全懂你现在的头疼事——当你把内置的「Azure Key Vaults should use private link」策略改成Deny效果后,分开部署KV和私有端点的操作直接被拦了。这事儿我之前帮不少用户排查过,核心问题就出在Azure Policy的评估时机上:Deny效果是在资源提交给Azure之前就做检查,这时候你要部署的KV还没和任何私有端点建立连接,自然触发了策略规则。

问题到底出在哪?

咱们先拆解内置策略的逻辑:它会检查KV资源的privateEndpointConnections数组里,已经批准的连接数是不是小于1。分开部署时,你先部署KV,这时候这个数组是空的,完全符合“小于1”的判定条件,Deny直接触发,根本等不到你后面部署私有端点。

给你几个可行的解决方案,按需选择:

方案1:改用DeployIfNotExists效果(首推!)

别死磕Deny了,换成DeployIfNotExists效果香得多。这个效果会自动给没有私有端点的KV补上PE,既满足合规要求,又不会拦你的部署。你可以基于内置策略改个自定义版本,把自动部署PE的逻辑加上:

{
  "properties": {
    "displayName": "强制为Key Vault部署私有端点",
    "policyType": "Custom",
    "mode": "Indexed",
    "parameters": {
      "effect": {
        "type": "String",
        "allowedValues": ["DeployIfNotExists", "Disabled"],
        "defaultValue": "DeployIfNotExists"
      },
      "目标子网ID": {
        "type": "String",
        "metadata": {
          "displayName": "私有端点部署的子网ID",
          "description": "指定要部署私有端点的子网资源ID"
        }
      }
    },
    "policyRule": {
      "if": {
        "allOf": [
          {
            "field": "type",
            "equals": "Microsoft.KeyVault/vaults"
          },
          {
            "count": {
              "field": "Microsoft.KeyVault/vaults/privateEndpointConnections[*]",
              "where": {
                "field": "Microsoft.KeyVault/vaults/privateEndpointConnections[*].privateLinkServiceConnectionState.status",
                "equals": "Approved"
              }
            },
            "less": 1
          }
        ]
      },
      "then": {
        "effect": "[parameters('effect')]",
        "details": {
          "type": "Microsoft.Network/privateEndpoints",
          "name": "[concat('pe-', field('name'))]",
          "existenceCondition": {
            "count": {
              "field": "Microsoft.Network/privateEndpoints/privateLinkServiceConnections[*]",
              "where": {
                "allOf": [
                  {
                    "field": "Microsoft.Network/privateEndpoints/privateLinkServiceConnections[*].privateLinkServiceId",
                    "equals": "[field('id')]"
                  },
                  {
                    "field": "Microsoft.Network/privateEndpoints/privateLinkServiceConnections[*].groupIds[*]",
                    "equals": "vault"
                  }
                ]
              }
            },
            "greaterOrEquals": 1
          },
          "roleDefinitionIds": ["/providers/Microsoft.Authorization/roleDefinitions/4d97b98b-1d4f-4787-a291-c67834d212e7"], // 网络参与者角色ID
          "deployment": {
            "properties": {
              "mode": "Incremental",
              "template": {
                "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
                "contentVersion": "1.0.0.0",
                "parameters": {
                  "kvName": { "type": "String" },
                  "kvId": { "type": "String" },
                  "location": { "type": "String" },
                  "subnetId": { "type": "String" }
                },
                "resources": [
                  {
                    "type": "Microsoft.Network/privateEndpoints",
                    "apiVersion": "2020-03-01",
                    "name": "[concat('pe-', parameters('kvName'))]",
                    "location": "[parameters('location')]",
                    "properties": {
                      "subnet": { "id": "[parameters('subnetId')]" },
                      "privateLinkServiceConnections": [
                        {
                          "name": "[concat('pe-', parameters('kvName'))]",
                          "properties": {
                            "privateLinkServiceId": "[parameters('kvId')]",
                            "groupIds": ["vault"],
                            "privateLinkServiceConnectionState": {
                              "status": "Approved",
                              "description": "由策略自动批准部署"
                            }
                          }
                        }
                      ]
                    }
                  }
                ]
              },
              "parameters": {
                "kvName": { "value": "[field('name')]" },
                "kvId": { "value": "[field('id')]" },
                "location": { "value": "[field('location')]" },
                "subnetId": { "value": "[parameters('目标子网ID')]" }
              }
            }
          }
        }
      }
    }
  }
}

方案2:临时策略豁免(适合自动化部署场景)

如果你非要用Deny效果,那可以在部署KV之前给它加个临时的策略豁免,等PE部署完再删掉。用Azure CLI就能搞定:

# 创建1小时有效的临时豁免(替换成你的资源信息)
az policy assignment exemption create \
  --name "kv-pe-deployment-exemption" \
  --policy-assignment "/subscriptions/{你的订阅ID}/providers/Microsoft.Authorization/policyAssignments/{你的策略分配ID}" \
  --resource "/subscriptions/{你的订阅ID}/resourceGroups/{资源组名}/providers/Microsoft.KeyVault/vaults/{KV名称}" \
  --expires-in "PT1H" \
  --reason "为部署私有端点临时豁免"

# 部署你的KV和PE模板
az deployment group create --resource-group {资源组名} --template-file 你的部署模板.json

# 可选:手动删除豁免(因为设置了1小时过期,也可以等自动失效)
az policy assignment exemption delete --name "kv-pe-deployment-exemption"

方案3:自定义Deny策略加宽限期(需配合监控)

这种方法是给KV留个24小时的宽限期,在宽限期内即使没有PE也不会被Deny,但过了时间还没配置就会触发。适合需要严格Deny但又要给部署留时间的场景:

{
  "properties": {
    "displayName": "宽限期后拒绝未配置私有端点的Key Vault",
    "policyType": "Custom",
    "mode": "Indexed",
    "policyRule": {
      "if": {
        "allOf": [
          {
            "field": "type",
            "equals": "Microsoft.KeyVault/vaults"
          },
          {
            "count": {
              "field": "Microsoft.KeyVault/vaults/privateEndpointConnections[*]",
              "where": {
                "field": "Microsoft.KeyVault/vaults/privateEndpointConnections[*].privateLinkServiceConnectionState.status",
                "equals": "Approved"
              }
            },
            "less": 1
          },
          {
            "field": "tags['pe-deployment-in-progress']",
            "notEquals": "yes"
          },
          {
            "field": "creationTimestamp",
            "greater": "[addHours(utcNow(), -24)]"
          }
        ]
      },
      "then": {
        "effect": "Deny"
      }
    }
  }
}

部署KV的时候加上pe-deployment-in-progress: yes标签,等PE部署完成后去掉标签,这样24小时内不会被Deny。

最后总结一下

  • 首推方案1,自动部署PE既省心又合规,完全不用手动协调部署顺序;
  • 方案2适合必须用Deny的自动化场景,临时豁免简单直接;
  • 方案3适合需要严格管控但又要给部署留缓冲的场景,但需要额外监控标签和时间。

内容的提问来源于stack exchange,提问作者skinex

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 15:47:34