使用ARM模板关联Azure Key Vault与专用终结点连接失败求助
Azure Key Vault ARM模板专用终结点部署错误修复方案
问题根源
- 导出模板中专用终结点连接的Key Vault资源ID为硬编码的原实例ID,未参数化关联新创建的Key Vault
- 部署顺序错误:连接状态更新操作未依赖Key Vault和专用终结点的创建完成,导致执行时目标资源尚未存在
- 专用终结点的
groupIds未正确设置为Key Vault的标准服务标识vault
修复步骤
- 全参数化资源引用:使用
resourceId函数动态生成新Key Vault的资源ID,替换所有硬编码的原实例ID - 强制部署依赖:给专用终结点连接状态更新操作添加明确的依赖项,确保仅在Key Vault和专用终结点完全创建后执行
- 验证专用终结点配置:确认
privateLinkServiceId指向新Key Vault,groupIds设为vault - 清理静态引用:移除所有与原Key Vault实例相关的硬编码值
修复后的模板示例
参数定义
{ "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "keyVaultName": { "type": "string", "metadata": { "description": "名称:新Key Vault实例" } }, "location": { "type": "string", "defaultValue": "[resourceGroup().location]", "metadata": { "description": "位置:资源部署区域" } }, "privateEndpointName1": { "type": "string", "metadata": { "description": "名称:第一个专用终结点" } }, "privateEndpointName2": { "type": "string", "metadata": { "description": "名称:第二个专用终结点" } }, "virtualNetworkId": { "type": "string", "metadata": { "description": "资源ID:专用终结点所属虚拟网络" } }, "subnetName": { "type": "string", "metadata": { "description": "名称:专用终结点所属子网" } }, "tenantId": { "type": "string", "defaultValue": "[subscription().tenantId]", "metadata": { "description": "租户ID:Key Vault所属Azure AD租户" } } }, "resources": [
Key Vault资源
{ "type": "Microsoft.KeyVault/vaults", "apiVersion": "2023-02-01", "name": "[parameters('keyVaultName')]", "location": "[parameters('location')]", "properties": { "sku": { "family": "A", "name": "Standard" }, "tenantId": "[parameters('tenantId')]", "accessPolicies": [], "enableSoftDelete": true, "enablePurgeProtection": true, "networkAcls": { "defaultAction": "Deny", "bypass": "AzureServices" } } },
第一个专用终结点
{ "type": "Microsoft.Network/privateEndpoints", "apiVersion": "2023-05-01", "name": "[parameters('privateEndpointName1')]", "location": "[parameters('location')]", "dependsOn": [ "[resourceId('Microsoft.KeyVault/vaults', parameters('keyVaultName'))]" ], "properties": { "subnet": { "id": "[concat(parameters('virtualNetworkId'), '/subnets/', parameters('subnetName'))]" }, "privateLinkServiceConnections": [ { "name": "[concat(parameters('privateEndpointName1'), '-connection')]", "properties": { "privateLinkServiceId": "[resourceId('Microsoft.KeyVault/vaults', parameters('keyVaultName'))]", "groupIds": ["vault"], "requestMessage": "通过ARM模板申请连接" } } ] } },
第一个专用终结点连接状态审批
{ "type": "Microsoft.KeyVault/vaults/privateEndpointConnections", "apiVersion": "2023-02-01", "name": "[concat(parameters('keyVaultName'), '/', split(reference(resourceId('Microsoft.Network/privateEndpoints', parameters('privateEndpointName1'))).privateLinkServiceConnections[0].id, '/')[8])]", "location": "[parameters('location')]", "dependsOn": [ "[resourceId('Microsoft.KeyVault/vaults', parameters('keyVaultName'))]", "[resourceId('Microsoft.Network/privateEndpoints', parameters('privateEndpointName1'))]" ], "properties": { "privateEndpoint": { "id": "[resourceId('Microsoft.Network/privateEndpoints', parameters('privateEndpointName1'))]" }, "privateLinkServiceConnectionState": { "status": "Approved", "description": "通过ARM模板自动审批", "actionRequired": "None" } } },
第二个专用终结点及连接审批
{ "type": "Microsoft.Network/privateEndpoints", "apiVersion": "2023-05-01", "name": "[parameters('privateEndpointName2')]", "location": "[parameters('location')]", "dependsOn": [ "[resourceId('Microsoft.KeyVault/vaults', parameters('keyVaultName'))]" ], "properties": { "subnet": { "id": "[concat(parameters('virtualNetworkId'), '/subnets/', parameters('subnetName'))]" }, "privateLinkServiceConnections": [ { "name": "[concat(parameters('privateEndpointName2'), '-connection')]", "properties": { "privateLinkServiceId": "[resourceId('Microsoft.KeyVault/vaults', parameters('keyVaultName'))]", "groupIds": ["vault"], "requestMessage": "通过ARM模板申请连接" } } ] } }, { "type": "Microsoft.KeyVault/vaults/privateEndpointConnections", "apiVersion": "2023-02-01", "name": "[concat(parameters('keyVaultName'), '/', split(reference(resourceId('Microsoft.Network/privateEndpoints', parameters('privateEndpointName2'))).privateLinkServiceConnections[0].id, '/')[8])]", "location": "[parameters('location')]", "dependsOn": [ "[resourceId('Microsoft.KeyVault/vaults', parameters('keyVaultName'))]", "[resourceId('Microsoft.Network/privateEndpoints', parameters('privateEndpointName2'))]" ], "properties": { "privateEndpoint": { "id": "[resourceId('Microsoft.Network/privateEndpoints', parameters('privateEndpointName2'))]" }, "privateLinkServiceConnectionState": { "status": "Approved", "description": "通过ARM模板自动审批", "actionRequired": "None" } } } ] }
部署命令示例
az deployment group create ` --resource-group <你的资源组名称> ` --template-file keyvault-pe-template.json ` --parameters keyVaultName=new-kv-demo ` privateEndpointName1=pe-kv-demo-01 ` privateEndpointName2=pe-kv-demo-02 ` virtualNetworkId=/subscriptions/<订阅ID>/resourceGroups/<资源组>/providers/Microsoft.Network/virtualNetworks/<虚拟网络名称> ` subnetName=<子网名称>
注意事项
- 确保专用终结点所属子网已禁用专用终结点网络策略
- 执行部署的账号需拥有Key Vault管理员权限及虚拟网络资源写入权限
- 如需添加密钥、机密、证书,可在Key Vault资源的
properties下添加keys、secrets、certificates数组进行定义
内容的提问来源于stack exchange,提问作者Abhijeet
相关产品推荐
相关产品推荐

