Azure Keyvault 通过 ARM 添加 Function MSI

Posted

技术标签:

【中文标题】Azure Keyvault 通过 ARM 添加 Function MSI【英文标题】:Azure Keyvault add Function MSI via ARM 【发布时间】:2018-05-19 21:46:03 【问题描述】:

我认为托管服务身份是一个很棒的概念,我喜欢 keyvault。然而:

当我通过增量资源组部署使用脚本时:

为简洁起见修改了示例


      "type": "Microsoft.KeyVault/vaults",
      "name": "[parameters('keyvaultName')]",
      "apiVersion": "2015-06-01",
      "properties":             
        "accessPolicies": [
          
            "objectId": "[reference(parameters('functionAppName'), '2016-08-01', 'Full').identity.principalId]",
            "permissions": 
              "keys": [],
              "secrets": [
                "Get"
              ]
            
          
        ]
      ,
      "dependsOn": [
        "[resourceId('Microsoft.Web/sites', parameters('functionAppName'))]"
      ]
    ,
    
      "apiVersion": "2016-08-01",
      "type": "Microsoft.Web/sites",
      "name": "[parameters('functionAppName')]",
      "kind": "functionapp",
      "identity": 
        "type": "SystemAssigned"
      ,
    

它成功部署并将 MSI 添加到 keyvault,但是 --

它吹走了已经分配的访问策略。 arm 是否可以保留 accessPolicies 并仅添加/更新匹配的策略?

如果没有这个,就不可能使用 MSI 完全编写部署脚本并将主体分配给 keyvault..

我错过了什么吗?

【问题讨论】:

你能确认你是在增量模式下运行吗? 是的,它正在运行增量模式。 你检查过这个example吗? "identityResourceId": "[concat(resourceId('Microsoft.Web/sites', parameters('webSiteName')),'/providers/Microsoft.ManagedIdentity/Identities/default')]" 对象 ID 应为 "objectId": "[reference(variables('identityResourceId'), '2015-08-31-PREVIEW').principalId]", @ShengbaoShui-MSFT 这是真的.. 我可以将所有权限添加到模板中,它会起作用.. 但这意味着我需要一个包含所有 MSI 和访问特定保管库的主体的脚本..这不好处理 【参考方案1】:

作为blog post的作者,我会根据模组发布详细信息:

当您部署名称为“add”的 Microsoft.KeyVault/vaults/accessPolicies 类型的资源时,它将合并到您的更改中。创建此特殊子资源类型是为了允许托管服务身份方案,在这些方案中,您在部署 VM 之前不知道 VM 的身份,并且您希望在部署期间授予该身份对保管库的访问权限。

增量部署可以与这个 json 一起使用来实现目标:


    "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
    "contentVersion": "1.0.0.0",
    "parameters": 
        "vaultName": 
            "type": "string"
        
    ,
    "resources": [
        
            "type": "Microsoft.KeyVault/vaults/accessPolicies",
            "name": "[concat(parameters('vaultName'), '/add')]",
            "apiVersion": "2016-10-01",
            "properties": 
                "accessPolicies": [
                    
                        "tenantId": "dfe47ca8-acfc-4539-9519-7d195a9e79e4",
                        "objectId": "5abe9358-10ae-4195-ba23-d34111430329",
                        "permissions": 
                            "keys": ["all"],
                            "secrets": ["all"],
                            "certificates": ["all"],
                            "storage": ["all"]
                        
                    
                ]
            
        
    ],
    "outputs": 
    

【讨论】:

那里的vaultName 应该是什么?它只是一个字符串或 url 吗?此外,如果该 keyvault 存在于另一个资源组中,那么我们应该提供 keyvault 的资源 id(long uri)吗? 这并不能真正解决问题。如果您通过模板创建保管库,它将删除所有现有策略。因此,如果您想要增量策略,则必须将它们隔离到一个完全独立的模板中。由于大多数资源都是以增量方式工作的,因此这实际上只会导致将 Vault 拆分为独立模板。 这并不能解决最初的问题。如果我部署 Vault 的 ARM 模板,它将清除我的策略,这与其他增量部署的工作方式完全相反。【参考方案2】:

highest-voted answer 的问题在于它从 ARM 模板中完全删除了密钥保管库,这意味着密钥保管库的创建在新环境中变成了手动过程。

ARM 不允许在未清除其现有访问策略的情况下重新部署密钥保管库。 accessPolicies 属性为required(恢复已删除保管库时除外),因此省略它会导致错误。将其设置为 [] 将清除所有现有策略。自 2018 年以来,已有 Microsoft Feedback request 解决此问题,目前有 152 票。

我发现解决此问题的最佳方法是仅在密钥库尚不存在时有条件地部署它,并且通过单独的 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.
            ]
          
        
      ]
    
  ]

【讨论】:

以上是关于Azure Keyvault 通过 ARM 添加 Function MSI的主要内容,如果未能解决你的问题,请参考以下文章