我创建了一个ARM模板来部署Azure WebApp,该Azure WebApp使用托管服务身份验证和KeyVault进行机密。因此,ARM模板创建WebApp资源并启用MSI,还创建KeyVault资源并将WebApp tenantid和objectid添加到accessPolicies,但是,ARM模板还从我的Keyvault中删除了所有其他现有的访问策略。
是否有一种方法可以增量部署访问策略,从而不必在部署后将用户重新添加到KeyVault访问策略中?
{
"type": "Microsoft.KeyVault/vaults",
"name": "[parameters('ICMODSKeyVaultName')]",
"apiVersion": "2016-10-01",
"location": "[resourceGroup().location]",
"properties": {
"sku": {
"family": "A",
"name": "standard"
},
"tenantId": "[reference(variables('identityResourceId'), '2015-08-31-PREVIEW').tenantId]",
"accessPolicies": [
{
"tenantId": "[reference(variables('identityResourceId'), '2015-08-31-PREVIEW').tenantId]",
"objectId": "[reference(variables('identityResourceId'), '2015-08-31-PREVIEW').principalId]",
"permissions": {
"secrets": [
"get"
]
}
}
],
"enabledForDeployment": true,
"enabledForTemplateDeployment": true
},
"dependsOn": [
"[concat('Microsoft.Web/sites/', parameters('AppName'))]"
]
}
答案 0 :(得分:2)
使用KeyVault的apiVersion 2019-09-01,可以通过仅在新库(使用condition)时才部署库(类型:Microsoft.KeyVault / vaults)来解决此问题。
将访问策略分别定义为子资源。答案 1 :(得分:1)
This is the behavior you should get, as ARM templates are idempotent. you will be able to alter this behavior if you create access policies as a separate resource:
{
"name": "vaultName/policyName",
"location": xxx,
"api-version": "2016-10-01",
"type": "Microsoft.KeyVault/vaults/accessPolicies",
"properties": {
"accessPolicies": [
{
"tenantId": "00000000-0000-0000-0000-000000000000",
"objectId": "00000000-0000-0000-0000-000000000000",
"permissions": {
"keys": [
"encrypt"
],
"secrets": [
"get"
],
"certificates": [
"get"
]
}
}
]
}
}
keep in mind this is a rough sketch, it might not work, but you can get it to work fairly easily. it is to illustrate the idea.
reference: https://docs.microsoft.com/en-us/rest/api/keyvault/vaults/updateaccesspolicy
答案 2 :(得分:1)
accepted answer 的问题在于它从 ARM 模板中完全删除了密钥保管库,这意味着密钥保管库的创建成为新环境中的手动过程。
ARM 不允许在不清除其现有访问策略的情况下重新部署密钥保管库。 accessPolicies
属性为 required(恢复已删除的保管库时除外),因此省略它会导致错误。将其设置为 []
将清除所有现有策略。自 2018 年以来,一直有 Microsoft Feedback request 解决此问题,目前有 152 票。
我发现的解决此问题的最佳方法是仅在 Key Vault 不存在时有条件地部署它,并且通过单独的 add
子资源。这会导致添加或更新指定的策略,同时保留任何其他现有策略。我通过将现有资源名称列表传递给 ARM 模板来检查密钥保管库是否已存在。
在 Azure 管道中:
- task: AzurePowerShell@5
displayName: 'Get existing resource names'
inputs:
azureSubscription: '$(armServiceConnection)'
azurePowerShellVersion: 'LatestVersion'
ScriptType: 'InlineScript'
Inline: |
$resourceNames = (Get-AzResource -ResourceGroupName $(resourceGroupName)).Name | ConvertTo-Json -Compress
Write-Output "##vso[task.setvariable variable=existingResourceNames]$resourceNames"
azurePowerShellVersion: 'LatestVersion'
- task: AzureResourceManagerTemplateDeployment@3
name: DeployResourcesTemplate
displayName: 'Deploy resources through ARM template
inputs:
deploymentScope: 'Resource Group'
action: 'Create Or Update Resource Group'
# ...
overrideParameters: >-
-existingResourceNames $(existingResourceNames)
# ...
deploymentMode: 'Incremental'
在 ARM 模板中:
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"keyVaultName": {
"type": "string"
},
"existingResourceNames": {
"type": "array",
"defaultValue": []
}
},
"resources": [
{
"type": "Microsoft.KeyVault/vaults",
"apiVersion": "2016-10-01",
"name": "[parameters('keyVaultName')]",
"location": "[resourceGroup().location]",
// Only deploy the key vault if it does not already exist.
// Conditional deployment doesn't cascade to child resources, which can be deployed even when their parent isn't.
"condition": "[not(contains(parameters('existingResourceNames'), parameters('keyVaultName')))]",
"properties": {
"sku": {
"family": "A",
"name": "Standard"
},
"tenantId": "[subscription().tenantId]",
"enabledForDeployment": false,
"enabledForDiskEncryption": false,
"enabledForTemplateDeployment": true,
"enableSoftDelete": true,
"accessPolicies": []
},
"resources": [
{
"type": "accessPolicies",
"apiVersion": "2016-10-01",
"name": "add",
"location": "[resourceGroup().location]",
"dependsOn": [
"[parameters('keyVaultName')]"
],
"properties": {
"accessPolicies": [
// Specify your access policies here.
// List does not need to be exhaustive; other existing access policies are preserved.
]
}
}
]
}
]
}
答案 3 :(得分:0)
我们按照以下解决方案进行幂等 Key Vault ARM 部署。
1.部署用作检查点的资源组标签。 在参数块
"resourceTags": {
"type": "object",
"defaultValue": {
"DeploymentLabel": "1"
}
}
在资源块
{
"name": "default",
"type": "Microsoft.Resources/tags",
"apiVersion": "2020-10-01",
"properties": {
"tags": "[parameters('resourceTags')]"
}
}
这意味着仅创建了Resource 组,但尚未创建Keyvault。
{
"apiVersion": "2019-09-01",
"name": "[parameters('keyVaultName')]",
"location": "[resourceGroup().location]",
"condition": "[equals(variables('tagslength'), 1)]",
"type": "Microsoft.KeyVault/vaults",
}
在同一个 keyvault arm 模板中,添加新标签以注册 Keyvault 部署。现在,向 RG 添加了 2 个标签,因此我们可以重新部署而不会丢失访问策略。
答案 4 :(得分:0)
我们通过使用找到了解决方法 Managed identity
二头肌示例:
创建用户分配的身份资源:
resource UserAssignedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = {
name: 'UserAssignedIdentityName'
...
}
然后将对象 ID 添加到 Key Vault 部署并包含访问权限:
resource keyVault 'Microsoft.KeyVault/vaults@2020-04-01-preview' = {
...
properties: {
...
accessPolicies: [
{
...
objectId: UserAssignedIdentity.properties.principalId // Managed Identity
permissions: {
...
}
}
]
}
}
例如,从另一个 arm 模板部署需要访问 Key Vault 的函数应用时。使用现有的用户分配身份:
resource UserAssignedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' existing = {
name: 'Name of an existing UAID resource'
}
resource FunctionApp 'Microsoft.Web/sites@2020-12-01' = {
...
identity:{
type: 'SystemAssigned, UserAssigned'
userAssignedIdentities:{
'${UserAssignedIdentity.id}' :{}
}
...
}