如何使用应用服务和 Azure Functions 的托管标识
本文内容
注意
从 2024 年 6 月 1 日开始,所有新创建的应用服务应用都可以选择生成唯一的默认主机名,命名约定为 <app-name>-<random-hash>.<region>.chinacloudsites.cn
。 现有应用名称将保持不变。
示例: myapp-ds27dh7271aah175.westus-01.chinacloudsites.cn
本文介绍如何为应用服务和 Azure Functions 应用程序创建托管标识,以及如何使用它来访问其他资源。
借助 Azure Active Directory (Azure AD) 的托管标识,应用可以轻松访问其他受 Azure AD 保护的资源(如 Azure Key Vault)。 标识由 Azure 平台托管,无需设置或转交任何机密。 有关 Azure AD 中的托管标识的详细信息,请参阅 Azure 资源的托管标识 。
你的应用程序可以被授予两种类型的标识:
系统分配的标识与你的应用程序相绑定,如果删除应用,标识也会被删除 。 一个应用只能具有一个系统分配的标识。
用户分配的标识 是可以分配给应用的独立 Azure 资源。 一个应用可以具有多个用户分配的标识。
托管标识配置特定于槽。 若要在门户中为部署槽配置托管标识,请先导航到槽。 若要在 Azure 门户中查找 Microsoft Entra 租户中 Web 应用或部署槽位的托管标识,请直接从租户的概述 页面中进行搜索。 通常,槽名称与 <app-name>/slots/<slot-name>
类似。
添加系统分配的标识
在 Azure 门户 左侧导航窗格中的“设置” 组下访问应用的设置。
选择“标识”。
在“系统分配的”选项卡中,将“状态”切换为“启用” 。 单击“ 保存 ”。
运行 az webapp identity assign
命令以创建系统分配标识:
az webapp identity assign --name myApp --resource-group myResourceGroup
对于应用服务
运行 Set-AzWebApp -AssignIdentity
命令以创建用于应用服务的系统分配标识:
Set-AzWebApp -AssignIdentity $true -Name <app-name> -ResourceGroupName <group-name>
对于 Functions
运行 Update-AzFunctionApp -IdentityType
命令以创建用于函数应用的系统分配标识:
Update-AzFunctionApp -Name $functionAppName -ResourceGroupName $resourceGroupName -IdentityType SystemAssigned
Azure 资源管理器模板可以用于自动化 Azure 资源部署。 若要详细了解如何部署到应用服务和 Functions,请参阅在应用服务中自动执行资源部署 和在 Azure Functions 中自动执行资源部署 。
在资源定义包括以下属性,可以创建 Microsoft.Web/sites
类型的任何有标识资源:
"identity": {
"type": "SystemAssigned"
}
添加系统分配的标识将告知 Azure 为应用程序创建和管理标识。
例如,Web 应用的模板可能如下 JSON 所示:
{
"apiVersion": "2022-03-01",
"type": "Microsoft.Web/sites",
"name": "[variables('appName')]",
"location": "[resourceGroup().location]",
"identity": {
"type": "SystemAssigned"
},
"properties": {
"name": "[variables('appName')]",
"serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('hostingPlanName'))]",
"hostingEnvironment": "",
"clientAffinityEnabled": false,
"alwaysOn": true
},
"dependsOn": [
"[resourceId('Microsoft.Web/serverfarms', variables('hostingPlanName'))]"
]
}
网站创建后,它具有以下附加属性:
"identity": {
"type": "SystemAssigned",
"tenantId": "<tenant-id>",
"principalId": "<principal-id>"
}
tenantId 属性标识该标识所属的 Microsoft Entra 租户。 principalId 是应用程序新标识的唯一标识符。 在 Microsoft Entra ID 中,服务主体的名称与你为应用服务或 Azure Functions 实例提供的名称相同。
如果需要稍后在模板中引用这些属性,则可通过带有 'Full'
标志的 reference()
模板函数 进行引用,如以下示例所示:
{
"tenantId": "[reference(resourceId('Microsoft.Web/sites', variables('appName')), '2018-02-01', 'Full').identity.tenantId]",
"objectId": "[reference(resourceId('Microsoft.Web/sites', variables('appName')), '2018-02-01', 'Full').identity.principalId]",
}
添加用户分配的标识
创建带有用户分配符的标识的应用需要创建标识,然后将其资源标识符添加到应用配置中。
首先,需要创建用户分配的标识资源。
创建用户分配的托管标识资源。
在应用页面的左侧导航中,向下滚动到“设置”组。
选择“标识”。
选择“用户分配的 >添加 ”。
搜索之前创建的标识,选中它,然后选择“添加 ”。
选择“添加 ”后,应用将重启。
创建用户分配的标识。
az identity create --resource-group <group-name> --name <identity-name>
运行 az webapp identity assign
命令以将标识分配给应用。
az webapp identity assign --resource-group <group-name> --name <app-name> --identities <identity-id>
对于应用服务
目前不支持在应用服务中添加用户分配标识。
对于 Functions
创建用户分配的标识。
Install-Module -Name Az.ManagedServiceIdentity -AllowPrerelease
$userAssignedIdentity = New-AzUserAssignedIdentity -Name $userAssignedIdentityName -ResourceGroupName <group-name>
运行 Update-AzFunctionApp -IdentityType UserAssigned -IdentityId
命令以在 Functions 中分配标识:
Update-AzFunctionApp -Name <app-name> -ResourceGroupName <group-name> -IdentityType UserAssigned -IdentityId $userAssignedIdentity.Id
Azure 资源管理器模板可以用于自动化 Azure 资源部署。 若要详细了解如何部署到应用服务和 Functions,请参阅在应用服务中自动执行资源部署 和在 Azure Functions 中自动执行资源部署 。
通过在资源定义中包含以下块,然后将 <resource-id>
替换为所需标识的资源 ID,就可以创建带有标识的任何 Microsoft.Web/sites
类型的资源:
"identity": {
"type": "UserAssigned",
"userAssignedIdentities": {
"<resource-id>": {}
}
}
注意
一个应用程序可以同时具有系统分配的标识和用户分配的标识。 在这种情况下,type
属性将为 SystemAssigned,UserAssigned
添加用户分配的类型即告知 Azure 使用为应用程序指定的用户分配的标识。
例如,Web 应用的模板可能如下 JSON 所示:
{
"apiVersion": "2022-03-01",
"type": "Microsoft.Web/sites",
"name": "[variables('appName')]",
"location": "[resourceGroup().location]",
"identity": {
"type": "UserAssigned",
"userAssignedIdentities": {
"[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', variables('identityName'))]": {}
}
},
"properties": {
"name": "[variables('appName')]",
"serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('hostingPlanName'))]",
"hostingEnvironment": "",
"clientAffinityEnabled": false,
"alwaysOn": true
},
"dependsOn": [
"[resourceId('Microsoft.Web/serverfarms', variables('hostingPlanName'))]",
"[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', variables('identityName'))]"
]
}
网站创建后,它具有以下附加属性:
"identity": {
"type": "UserAssigned",
"userAssignedIdentities": {
"<resource-id>": {
"principalId": "<principal-id>",
"clientId": "<client-id>"
}
}
}
principalId 是用于 Microsoft Entra 管理的标识的唯一标识符。 clientId 是应用程序新标识的唯一标识符,用于指定在运行时调用期间要使用哪一标识。
可能需要配置目标资源,允许从应用或 Functions 进行访问。 例如,如果你请求令牌 以访问 Key Vault,则还必须添加一个访问策略,其中包括你的应用或 Functions 的托管身份。 否则,对 Key Vault 的调用将被拒绝,即使你使用了有效令牌。 Azure SQL 数据库也是如此。 若详细了解支持 Microsoft Entra 令牌的资源,请参阅支持 Microsoft Entra 身份验证的 Azure 服务 。
重要
用于托管标识的后端服务将为每个资源 URI 维护缓存约 24 小时。 这意味着对托管标识的组或角色成员身份的更改可能需要几个小时才能生效。 目前,无法在托管标识的令牌到期前对其强制执行刷新。 如果更改某个托管标识的组或角色成员身份以添加或删除权限,则可能需要等待几个小时才能让使用该标识的 Azure 资源获得正确的访问权限。 有关组或角色成员身份的替代方法,请参阅使用托管标识进行授权的限制 。
在应用代码中连接到 Azure 服务
借助其托管标识,应用可以获取受 Microsoft Entra ID 保护的 Azure 资源的令牌,例如 Azure SQL 数据库、Azure Key Vault 和 Azure 存储。 这些令牌代表访问资源的应用程序,而不是应用程序的任何特定用户。
应用服务和 Azure Functions 提供了内部可访问的 REST 终结点 以用于检索令牌。 可以使用标准 HTTP GET 从应用中访问 REST 终结点,该标准可以使用每种语言的通用 HTTP 客户端来实现。 对于 .NET、JavaScript、Java 和 Python,Azure 标识客户端库提供了基于此 REST 终结点的抽象,并简化了开发体验。 连接到其他 Azure 服务非常简单,只需要将凭据对象添加到特定于服务的客户端。
原始 HTTP GET 请求使用提供的两个环境变量 ,如以下示例所示:
GET /MSI/token?resource=https://vault.azure.cn&api-version=2019-08-01 HTTP/1.1
Host: <ip-address-:-port-in-IDENTITY_ENDPOINT>
X-IDENTITY-HEADER: <value-of-IDENTITY_HEADER>
示例响应可能如下例所示:
HTTP/1.1 200 OK
Content-Type: application/json
{
"access_token": "eyJ0eXAi…",
"expires_on": "1586984735",
"resource": "https://vault.azure.cn",
"token_type": "Bearer",
"client_id": "00001111-aaaa-2222-bbbb-3333cccc4444"
}
此响应与Microsoft Entra 服务到服务访问令牌请求的响应 相同。 要访问 Key Vault,你需要将 access_token
的值添加到与 Vault 的客户端连接。
使用以下脚本通过指定 Azure 服务的资源 URI 从本地终结点检索令牌:
$resourceURI = "https://<AAD-resource-URI-for-resource-to-obtain-token>"
$tokenAuthURI = $env:IDENTITY_ENDPOINT + "?resource=$resourceURI&api-version=2019-08-01"
$tokenResponse = Invoke-RestMethod -Method Get -Headers @{"X-IDENTITY-HEADER"="$env:IDENTITY_HEADER"} -Uri $tokenAuthURI
$accessToken = $tokenResponse.access_token
有关 REST 终结点的更多信息,请参阅 REST 终结点参考 。
删除标识
删除系统分配的标识时,会从 Microsoft Entra ID 中删除标识。 删除应用资源本身时,也会自动从 Microsoft Entra ID 中删除系统分配的标识。
在应用页面的左侧导航中,向下滚动到“设置”组。
选择“标识”。 然后,根据标识类型执行以下步骤:
系统分配的标识:在“系统分配”选项卡中,将“状态”切换为“关闭”。 单击“保存” 。
用户分配的标识:选择“用户分配”选项卡,选中该标识的复选框,然后选择“删除”。 请选择“是”以确认。
若要删除系统分配的标识,请执行以下操作:
az webapp identity remove --name <app-name> --resource-group <group-name>
要删除一个或多个用户分配的标识:
az webapp identity remove --name <app-name> --resource-group <group-name> --identities <identity-id1> <identity-id2> ...
你还可以通过在 --identities
中指定 [system]
来删除系统分配的标识。
对于应用服务
运行 Set-AzWebApp -AssignIdentity
命令以删除用于应用服务的系统分配标识:
Set-AzWebApp -AssignIdentity $false -Name <app-name> -ResourceGroupName <group-name>
对于 Functions
删除 Azure PowerShell 中的所有标识(仅限 Azure Functions):
# Update an existing function app to have IdentityType "None".
Update-AzFunctionApp -Name $functionAppName -ResourceGroupName $resourceGroupName -IdentityType None
删除 ARM 模板中的所有标识:
"identity": {
"type": "None"
}
注意
还可以设置一个应用程序设置 (WEBSITE_DISABLE_MSI),它只禁用本地令牌服务。 但是,它会保留标识,而工具仍会将托管标识显示为“打开”或“已启用”。因此,不建议使用此设置。
REST 终结点参考
具有托管标识的应用通过定义两个环境变量使此终结点可用:
IDENTITY_ENDPOINT - 本地令牌服务的 URL。
IDENTITY_HEADER - 用于帮助缓解服务器端请求伪造 (SSRF) 攻击的标头。 该值由平台轮换。
IDENTITY_ENDPOINT 是一个本地 URL,应用可从其请求令牌。 若要获取资源的令牌,请对此终结点发起 HTTP GET 请求,并包括以下参数:
参数名称
In
说明
resource
查询
应获取其令牌的资源的 Microsoft Entra 资源 URI。 这可以是支持 Microsoft Entra 身份验证的 Azure 服务 或任何其他资源 URI 之一。
api-version
查询
要使用的令牌 API 版本。 请使用 2019-08-01
。
X-IDENTITY-HEADER
标头
IDENTITY_HEADER 环境变量的值。 此标头用于帮助缓解服务器端请求伪造 (SSRF) 攻击。
client_id
查询
(可选)要使用的用户分配的标识的客户端 ID。 不能在包含 principal_id
、mi_res_id
或 object_id
的请求中使用。 如果省略所有 ID 参数(client_id
、principal_id
、object_id
和 mi_res_id
),则使用系统分配的标识。
principal_id
查询
(可选)要使用的用户分配的标识的主体 ID。 object_id
是可以改用的别名。 不能在包含 client_id、mi_res_id 或 object_id 的请求中使用。 如果省略所有 ID 参数(client_id
、principal_id
、object_id
和 mi_res_id
),则使用系统分配的标识。
mi_res_id
查询
(可选)要使用的用户分配的标识的 Azure 资源 ID。 不能在包含 principal_id
、client_id
或 object_id
的请求中使用。 如果省略所有 ID 参数(client_id
、principal_id
、object_id
和 mi_res_id
),则使用系统分配的标识。
重要
如果你要尝试获取用户分配的标识的令牌,必须包含一个可选属性。 否则,令牌服务将尝试为系统分配的标识获取令牌,而该令牌不一定存在。
后续步骤