【问题标题】:Azure Function Managed Identities and Key Vault Access Poilcy (Chicken Egg Situation)Azure Function Managed Identities 和 Key Vault 访问策略(鸡蛋情况)
【发布时间】:2021-03-24 10:53:07
【问题描述】:

只是想知道是否有一种方法可以将存储帐户连接字符串存储在函数使用的密钥保管库中。该功能依赖于WEBSITE_CONTENTAZUREFILECONNECTIONSTRINGAzureWebJobsStorage。我正在尝试将这些添加到密钥库中,但我遇到的问题是..

  1. 配置存储帐户
  2. 配置密钥库
  3. 供应功能应用程序
  4. 将函数的访问策略添加到 Key Vault

这里的问题是,在创建函数应用时(第 3 步)它会失败,因为它无法访问密钥保管库(缺少访问策略)。由于功能需要存在,我无法创建策略。

其他人是如何解决这个问题的?我正在考虑预先创建 AD 应用程序(第 0 步)而不使用托管身份(这并不理想)。

【问题讨论】:

    标签: azure-functions azure-keyvault arm-template azure-managed-identity


    【解决方案1】:

    如果您使用 azure 门户部署资源,您可以部署没有 keyvault 引用的函数应用,然后手动配置 keyvault 引用。

    如果您使用 ARM 模板部署资源,doc 已提及您的问题。

    值得注意的是,您需要将应用程序设置定义为它们自己的资源,而不是在站点定义中使用siteConfig 属性。这是因为需要先定义站点,以便使用它创建系统分配的身份,并且可以在访问策略中使用。

    示例:

    {
        //...
        "resources": [
            {
                "type": "Microsoft.Storage/storageAccounts",
                "name": "[variables('storageAccountName')]",
                //...
            },
            {
                "type": "Microsoft.Insights/components",
                "name": "[variables('appInsightsName')]",
                //...
            },
            {
                "type": "Microsoft.Web/sites",
                "name": "[variables('functionAppName')]",
                "identity": {
                    "type": "SystemAssigned"
                },
                //...
                "resources": [
                    {
                        "type": "config",
                        "name": "appsettings",
                        //...
                        "dependsOn": [
                            "[resourceId('Microsoft.Web/sites', variables('functionAppName'))]",
                            "[resourceId('Microsoft.KeyVault/vaults/', variables('keyVaultName'))]",
                            "[resourceId('Microsoft.KeyVault/vaults/secrets', variables('keyVaultName'), variables('storageConnectionStringName'))]",
                            "[resourceId('Microsoft.KeyVault/vaults/secrets', variables('keyVaultName'), variables('appInsightsKeyName'))]"
                        ],
                        "properties": {
                            "AzureWebJobsStorage": "[concat('@Microsoft.KeyVault(SecretUri=', reference(variables('storageConnectionStringResourceId')).secretUriWithVersion, ')')]",
                            "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING": "[concat('@Microsoft.KeyVault(SecretUri=', reference(variables('storageConnectionStringResourceId')).secretUriWithVersion, ')')]",
                            "APPINSIGHTS_INSTRUMENTATIONKEY": "[concat('@Microsoft.KeyVault(SecretUri=', reference(variables('appInsightsKeyResourceId')).secretUriWithVersion, ')')]",
                            "WEBSITE_ENABLE_SYNC_UPDATE_SITE": "true"
                            //...
                        }
                    },
                    {
                        "type": "sourcecontrols",
                        "name": "web",
                        //...
                        "dependsOn": [
                            "[resourceId('Microsoft.Web/sites', variables('functionAppName'))]",
                            "[resourceId('Microsoft.Web/sites/config', variables('functionAppName'), 'appsettings')]"
                        ],
                    }
                ]
            },
            {
                "type": "Microsoft.KeyVault/vaults",
                "name": "[variables('keyVaultName')]",
                //...
                "dependsOn": [
                    "[resourceId('Microsoft.Web/sites', variables('functionAppName'))]"
                ],
                "properties": {
                    //...
                    "accessPolicies": [
                        {
                            "tenantId": "[reference(concat('Microsoft.Web/sites/',  variables('functionAppName'), '/providers/Microsoft.ManagedIdentity/Identities/default'), '2015-08-31-PREVIEW').tenantId]",
                            "objectId": "[reference(concat('Microsoft.Web/sites/',  variables('functionAppName'), '/providers/Microsoft.ManagedIdentity/Identities/default'), '2015-08-31-PREVIEW').principalId]",
                            "permissions": {
                                "secrets": [ "get" ]
                            }
                        }
                    ]
                },
                "resources": [
                    {
                        "type": "secrets",
                        "name": "[variables('storageConnectionStringName')]",
                        //...
                        "dependsOn": [
                            "[resourceId('Microsoft.KeyVault/vaults/', variables('keyVaultName'))]",
                            "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]"
                        ],
                        "properties": {
                            "value": "[concat('DefaultEndpointsProtocol=https;AccountName=', variables('storageAccountName'), ';AccountKey=', listKeys(variables('storageAccountResourceId'),'2015-05-01-preview').key1)]"
                        }
                    },
                    {
                        "type": "secrets",
                        "name": "[variables('appInsightsKeyName')]",
                        //...
                        "dependsOn": [
                            "[resourceId('Microsoft.KeyVault/vaults/', variables('keyVaultName'))]",
                            "[resourceId('Microsoft.Insights/components', variables('appInsightsName'))]"
                        ],
                        "properties": {
                            "value": "[reference(resourceId('microsoft.insights/components/', variables('appInsightsName')), '2015-05-01').InstrumentationKey]"
                        }
                    }
                ]
            }
        ]
    }
    

    【讨论】:

    • 我不清楚 "type": "sourcecontrols" 位是做什么的,但我删除了它并且工作得很好。
    【解决方案2】:

    许多其他需要访问 Key Vault 的资源(包括服务总线、事件中心、API 管理)也存在同样的问题。

    我们如何创建具有这些循环依赖关系的可重新部署的 ARM 模板?

    使用客户管理的密钥加密的服务总线部署示例

    • 首先在没有加密的情况下创建服务总线,因为全新的资源无法访问密钥库密钥。它获取托管身份/服务主体。
    • 更新 KeyVault 以授予对服务总线托管标识的访问权限。
    • 使用 Key Vault 访问加密更新服务总线。
    • 如果由于需要基础架构更新而重新部署 ARM 模板,则服务总线重新部署将失败,因为无法删除加密
    • 不支持检查资源是否已存在于 ARM 模板中以避免在后续部署中重复步骤 1

    用户分配的托管标识似乎可以解决问题,但 ARM 模板不支持它们!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-07-11
      • 2020-02-11
      • 1970-01-01
      • 1970-01-01
      • 2019-06-09
      • 2020-04-21
      • 2021-12-23
      相关资源
      最近更新 更多