对 Azure 应用服务和 Azure Functions 使用应用程序配置引用

本文介绍如何在 Azure 应用服务或 Azure Functions 应用程序中使用配置数据,而无需进行任何代码更改。 Azure 应用配置 是一项 Azure 服务,可用于集中管理应用程序配置。 它也是一种在一段时间内或跨版本审核配置值的有效工具。

授予对应用程序配置的应用访问权限

若要开始在应用服务中使用应用程序配置引用,请先创建应用程序配置存储区。 然后,向应用授予访问应用商店中的配置键/值对的权限。

  1. 若要创建应用程序配置存储区,请先完成应用程序配置快速入门

  2. 为应用程序创建一个托管标识

    默认情况下,应用程序配置引用将使用应用系统分配的标识,但你可以指定用户分配的标识

  3. 向标识授予对应用程序配置存储区的正确访问权限集。 更新存储的角色分配。 将应用程序配置数据读取者角色分配给此标识,范围限定为资源。

使用用户分配的标识访问应用程序配置存储区

在某些情况下,应用可能需要在创建时引用配置,但系统分配的标识尚不可用。 在这种情况下,可以提前为应用程序配置存储创建用户分配的标识

向用户分配的标识授予权限后,完成以下步骤:

  1. 为应用程序分配标识

  2. 通过将 keyVaultReferenceIdentity 属性设置为用户分配的标识的资源 ID,配置应用以将此标识用于应用程序配置引用操作。 尽管属性的名称中含有 keyVault,但标识也将应用于应用程序配置引用。 代码如下:

    userAssignedIdentityResourceId=$(az identity show -g MyResourceGroupName -n MyUserAssignedIdentityName --query id -o tsv)
    appResourceId=$(az webapp show -g MyResourceGroupName -n MyAppName --query id -o tsv)
    az rest --method PATCH --uri "${appResourceId}?api-version=2021-01-01" --body "{'properties':{'keyVaultReferenceIdentity':'${userAssignedIdentityResourceId}'}}"
    

此配置适用于应用中的所有引用。

授予应用对引用的密钥保管库的访问权限

除了存储原始配置值之外,应用配置还具有自己的格式来存储 Azure Key Vault 引用。 如果应用配置引用的值是应用配置存储中的 Key Vault 引用,则应用还必须具有访问引用中指定的密钥保管库的权限。

注意

应用配置 Key Vault 引用 不应与 应用服务和 Azure Functions Key Vault 引用混淆。 你的应用可以使用这些引用的任意组合,但有一些重要的区别需要注意。 如果您的保管库需要网络限制,或者您需要应用程序定期更新至最新版本,请考虑使用应用服务和 Azure Functions 方法,而不是使用应用配置引用。

若要授予应用对密钥保管库的访问权限,请执行以下作:

  1. 确定用于应用程序配置引用的标识。 必须向同一标识授予保管库访问权限。

  2. 在密钥保管库中为该标识创建访问策略。 在此策略上启用“获取”机密权限。 请勿配置“授权的应用程序”applicationId 设置,因为这与托管标识不兼容。

引用语法

应用程序配置引用的格式为:@Microsoft.AppConfiguration({referenceString}),其中 {referenceString} 将被替换为下表中所述的具体值:

引用字符串部分 说明
Endpoint = <endpointURL> Endpoint (必需)。 您的应用配置服务的 URL。
Key = <myAppConfigKey> Key (必需)。 要分配给应用设置的密钥的名称。
Label = <myKeyLabel> Label (可选)。 在 Key 中指定的键标签的值。

下面是包含 Label 的完整引用的示例:

@Microsoft.AppConfiguration(Endpoint=https://myAppConfigStore.azconfig.io; Key=myAppConfigKey; Label=myKeyLabel)​

下面是不包含 Label 的示例:

@Microsoft.AppConfiguration(Endpoint=https://myAppConfigStore.azconfig.io; Key=myAppConfigKey)​

任何导致站点重启的应用程序配置更改都会立即从应用程序配置存储区中重新提取所有被引用的键/值对。

注意

目前不支持在应用程序配置中更新键/值对时自动刷新和重新提取这些值。

来自应用程序配置的源应用程序设置

可以使用应用配置引用作为 应用程序设置 的值,以便可以在应用配置中保留配置数据,而不是在站点配置设置中保留配置数据。 应用设置和应用配置密钥/值对都是静态加密的。 如果需要集中的配置管理功能,可以将配置数据添加到应用程序配置中。

若要将应用程序配置引用用于应用设置,请将引用设置为设置的值。 应用可以像往常一样通过其键引用配置值。 不需更改代码。

提示

应将大多数使用应用程序配置引用的应用程序设置标记为槽设置,以便为每个环境设置单独的存储区或标签。

Azure 文件存储装载注意事项

应用可使用 WEBSITE_CONTENTAZUREFILECONNECTIONSTRING 应用程序设置将 Azure 文件存储装载为文件系统。 此设置有额外的验证检查,旨在确保该应用程序可以正常启动。 平台依赖于在 Azure 文件存储中拥有内容共享,而且除非在 WEBSITE_CONTENTSHARE 设置中指定名称,否则它会采用默认名称。 对于修改这些设置的任何请求,平台会尝试验证此内容共享是否存在。 如果共享不存在,平台将尝试创建共享。 如果找不到或无法创建内容共享,系统会阻止请求。

如果为此设置使用应用程序配置引用,默认情况下,此验证检查将失败,因为平台在处理传入请求时无法解析连接本身。 若要避免此问题,可以通过将 WEBSITE_SKIP_CONTENTSHARE_VALIDATION 设置为 1 来跳过验证。 此设置会绕过所有检查,并且不会自动创建内容共享。 必须确保提前创建共享。

警告

如果跳过验证,并且连接字符串或内容共享无效,该应用程序将无法正常启动,且服务器只显示 HTTP 500 错误。

创建站点时,如果未传播托管标识权限或未设置虚拟网络集成,装载内容共享可能会失败。 可推迟到稍后在部署模板中设置 Azure 文件存储,以适应所需设置。 有关详细信息,请参阅下一部分的 Azure 资源管理器部署。 在 Azure 文件存储设置完成之前,Azure 应用服务仅使用默认文件系统,且文件不会被复制过去。 确保在装载 Azure 文件存储之前的过渡期间不进行任何部署尝试操作。

Azure 资源管理器部署

如果使用 Azure 资源管理器 (ARM) 模板自动执行资源部署,则可能需要按特定顺序对依赖项进行排序,以使应用配置引用正常工作。 在这种情况下,必须将应用程序设置定义为其自己的资源,而不是使用站点定义中的 siteConfig 属性。 必须先定义站点,以便使用站点创建系统分配的标识。 然后,在访问策略中使用托管标识。

下面是具有应用配置引用的函数应用的示例模板:

{
    "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {
        "roleNameGuid": {
            "type": "string",
            "defaultValue": "[newGuid()]",
            "metadata": {
                "description": "A new GUID used to identify the role assignment"
            }
        }
    },
    "variables": {
        "functionAppName": "DemoMBFunc",
        "appConfigStoreName": "DemoMBAppConfig",
        "resourcesRegion": "China North 2",
        "appConfigSku": "standard",
        "FontNameKey": "FontName",
        "FontColorKey": "FontColor",
        "myLabel": "Test",
        "App Configuration Data Reader": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/', '516239f1-63e1-4d78-a4de-a74fb236a071')]"
    },
    "resources": [
        {
            "type": "Microsoft.Web/sites",
            "name": "[variables('functionAppName')]",
            "apiVersion": "2021-03-01",
            "location": "[variables('resourcesRegion')]",
            "identity": {
                "type": "SystemAssigned"
            },
            //...
            "resources": [
                {
                    "type": "config",
                    "name": "appsettings",
                    "apiVersion": "2021-03-01",
                    //...
                    "dependsOn": [
                        "[resourceId('Microsoft.Web/sites', variables('functionAppName'))]",
                        "[resourceId('Microsoft.AppConfiguration/configurationStores', variables('appConfigStoreName'))]"
                    ],
                    "properties": {
                        "WEBSITE_FONTNAME": "[concat('@Microsoft.AppConfiguration(Endpoint=', reference(resourceId('Microsoft.AppConfiguration/configurationStores', variables('appConfigStoreName'))).endpoint,'; Key=',variables('FontNameKey'),'; Label=',variables('myLabel'), ')')]",
                        "WEBSITE_FONTCOLOR": "[concat('@Microsoft.AppConfiguration(Endpoint=', reference(resourceId('Microsoft.AppConfiguration/configurationStores', variables('appConfigStoreName'))).endpoint,'; Key=',variables('FontColorKey'),'; Label=',variables('myLabel'), ')')]",
                        "WEBSITE_ENABLE_SYNC_UPDATE_SITE": "true"
                        //...
                    }
                },
                {
                    "type": "sourcecontrols",
                    "name": "web",
                    "apiVersion": "2021-03-01",
                    //...
                    "dependsOn": [
                        "[resourceId('Microsoft.Web/sites', variables('functionAppName'))]",
                        "[resourceId('Microsoft.Web/sites/config', variables('functionAppName'), 'appsettings')]"
                    ]
                }
            ]
        },
        {
            "type": "Microsoft.AppConfiguration/configurationStores",
            "name": "[variables('appConfigStoreName')]",
            "apiVersion": "2019-10-01",
            "location": "[variables('resourcesRegion')]",
            "sku": {
                "name": "[variables('appConfigSku')]"
            },
            //...
            "dependsOn": [
                "[resourceId('Microsoft.Web/sites', variables('functionAppName'))]"
            ],
            "properties": {
            },
            "resources": [
                {
                    "type": "keyValues",
                    "name": "[variables('FontNameKey')]",
                    "apiVersion": "2021-10-01-preview",
                    //...
                    "dependsOn": [
                        "[resourceId('Microsoft.AppConfiguration/configurationStores', variables('appConfigStoreName'))]"

                    ],
                    "properties": {
                        "value": "Calibri",
                        "contentType": "application/json"
                    }
                },
                {
                    "type": "keyValues",
                    "name": "[variables('FontColorKey')]",
                    "apiVersion": "2021-10-01-preview",
                    //...
                    "dependsOn": [
                        "[resourceId('Microsoft.AppConfiguration/configurationStores', variables('appConfigStoreName'))]"

                    ],
                    "properties": {
                        "value": "Blue",
                        "contentType": "application/json"
                    }
                }
            ]
        },
        {
            "scope": "[resourceId('Microsoft.AppConfiguration/configurationStores', variables('appConfigStoreName'))]",
            "type": "Microsoft.Authorization/roleAssignments",
            "apiVersion": "2020-04-01-preview",
            "name": "[parameters('roleNameGuid')]",
            "properties": {
                "roleDefinitionId": "[variables('App Configuration Data Reader')]",
                "principalId": "[reference(resourceId('Microsoft.Web/sites/', variables('functionAppName')), '2020-12-01', 'Full').identity.principalId]",
                "principalType": "ServicePrincipal"
            }
        }
    ]
}

注意

在此示例中,源代码管理部署取决于应用程序设置。 在大多数情况下,此序列不太安全,因为应用设置以异步方式更新。 但是,由于该示例包含 WEBSITE_ENABLE_SYNC_UPDATE_SITE 应用程序设置,因此更新是同步的。 仅当应用程序设置完全更新后,源代码管理部署才会开始。 有关应用设置的更多信息,请参阅 Azure 应用服务中的环境变量和应用设置

排查应用程序配置引用问题

如果没有正确解析某个引用,将改用引用值。 创建一个使用语法 @Microsoft.AppConfiguration(...) 的环境变量。 引用可能会导致错误,因为应用程序需要配置值。

此错误通常是 应用配置访问策略配置错误的结果。 但是,如果引用中存在语法错误,或者存储中不存在配置键/值对,则也可能发生这种情况。