Управляемые удостоверения функций Azure и политика доступа к хранилищу ключей (ситуация с куриным яйцом)

Просто интересно, есть ли способ хранить строки подключения учетной записи хранения в хранилище ключей, которое использует функция. Функция зависит от WEBSITE_CONTENTAZUREFILECONNECTIONSTRING и AzureWebJobsStorage. Я пытаюсь добавить их в хранилище ключей, но у меня проблема.

  1. Учетная запись хранения резерва
  2. Предоставление хранилища ключей
  3. Приложение функции обеспечения
  4. Добавить политику доступа для функции в хранилище ключей

Проблема здесь в том, что при создании функционального приложения (шаг 3) происходит сбой, поскольку он не может получить доступ к хранилищу ключей (отсутствует политика доступа). Я не могу создать политику, так как функция должна существовать.

Как это исправили другие? Я думал заранее создать приложение AD (шаг 0) и не использовать управляемые удостоверения (что не идеально).


person Dr Schizo    schedule 24.03.2021    source источник


Ответы (2)


Если вы используете портал Azure для развертывания ресурсов, вы можете развернуть приложение-функцию без ссылки на хранилище ключей, а затем настроить ссылку на хранилище ключей вручную.

Если вы используете шаблон 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]"
                    }
                }
            ]
        }
    ]
}
person Joy Wang    schedule 25.03.2021
comment
Мне неясно, какой тип: бит sourcecontrols делает, но я удалил это и работает с удовольствием. - person Dr Schizo; 26.03.2021

Та же проблема существует для многих других ресурсов, которым требуется доступ к Key Vault (включая служебную шину, концентратор событий, управление API).

Как мы можем создать повторно развертываемый шаблон ARM с этими циклическими зависимостями?

Пример развертывания служебной шины с шифрованием ключей, управляемых клиентом

  • Служебная шина сначала создается без шифрования, поскольку совершенно новый ресурс не может получить доступ к ключам хранилища ключей. Он получает управляемое удостоверение/субъект-службу.
  • KeyVault обновлен для предоставления доступа к управляемому удостоверению служебной шины.
  • Служебная шина обновлена ​​с помощью шифрования с использованием доступа к Key Vault.
  • Если шаблон ARM повторно развертывается из-за того, что требуются обновления инфраструктуры, повторное развертывание служебной шины завершается с ошибкой, так как шифрование невозможно удалить.
  • Не поддерживается проверка наличия ресурса в шаблоне ARM, чтобы избежать повторения шага 1 при последующих развертываниях.

Кажется, что назначенные пользователем управляемые удостоверения могут решить проблему, но они не поддерживаются в шаблонах ARM!

person siegelc    schedule 25.03.2021