Bicep中如何获取Azure App Service的应用(客户端)ID
问题场景
在Bicep中配置Azure API Management策略,为后端App Service启用托管服务身份认证时,需要在策略中传入对应标识的客户端ID,常规策略XML片段如下:
<policies> <inbound> <authentication-managed-identity resource="4d192d04-XXXX-461f-a6ab-XXXXXXXXXXXX" /> <base /> </inbound> </policies>
最初尝试直接读取App Service资源的identity.principalId属性取值,对应Bicep片段如下:
// App Service声明 @description('API Website') resource backendapi 'Microsoft.Web/sites@2021-03-01' = { name: 'backend-${environment}' kind: 'app,linux,container' location: location // 省略其余属性配置 // 尝试读取Web App的客户端ID,部署时报错 var managed_identity_id = backendapi.identity.principalId
部署时抛出如下异常:
语言表达式中不存在'identity'属性,可用属性包括:apiVersion、location、tags、kind、properties、condition、deploymentResourceLineInfo、existing、isConditionTrue、subscriptionId、resourceGroupName、scope、resourceId、referenceApiVersion、isTemplateResource、isAction、provisioningOperation
错误原因
报错核心原因有两个:
- 没有在App Service资源定义中显式配置
identity块开启托管标识。未声明托管标识配置的资源,Azure Resource Manager部署时不会返回identity相关属性,直接访问就会触发属性不存在的错误。VS Code的智能提示是基于资源类型的通用Schema给出的全量属性提示,不会校验你是否实际配置了对应功能块,因此会出现提示有属性但部署报错的情况。 - 属性取值选错:
principalId是托管标识对应的Azure AD目录对象ID,而APIM策略authentication-managed-identity的resource参数需要的是应用客户端ID(clientId),两个值完全不同,取错会导致后续令牌获取失败。
正确实现方式
根据你使用的托管标识类型,分别按如下方式配置:
1. 使用系统分配托管标识
首先在App Service资源中显式开启系统分配托管标识,再读取对应客户端ID:
@description('API Website') resource backendapi 'Microsoft.Web/sites@2021-03-01' = { name: 'backend-${environment}' kind: 'app,linux,container' location: location // 必须显式声明identity块开启系统分配托管标识 identity: { type: 'SystemAssigned' } // 其余业务属性按实际需求配置 } // 获取系统分配托管标识的客户端ID var managed_identity_client_id = backendapi.identity.clientId
如果你的App Service开启了AAD默认认证,也可以直接用App Service的默认受众URI作为resource参数值,不需要额外查询客户端ID:https://${backendapi.name}.azurewebsites.net。
2. 使用用户分配托管标识
用户分配托管标识是独立的Azure资源,先创建标识再绑定到App Service,直接从标识资源读取客户端ID即可:
// 定义用户分配托管标识 resource backendMi 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = { name: 'mi-backend-${environment}' location: location } @description('API Website') resource backendapi 'Microsoft.Web/sites@2021-03-01' = { name: 'backend-${environment}' kind: 'app,linux,container' location: location // 绑定用户分配托管标识 identity: { type: 'UserAssigned' userAssignedIdentities: { '${backendMi.id}': {} } } // 其余业务属性按实际需求配置 } // 直接读取用户分配标识的客户端ID,即为APIM策略需要的值 var managed_identity_client_id = backendMi.properties.clientId
获取到正确的客户端ID后,直接替换APIM策略XML中的resource属性值即可完成配置。
注意事项
- 不要使用
principalId填充策略参数,该值是AAD目录对象ID,和客户端ID用途完全不同。 - 即使你已经在Azure门户中手动开启了App Service的托管标识,也必须在Bicep模板的资源定义中显式声明
identity块,否则部署时会覆盖现有配置,同时也无法通过资源属性读取标识相关值。
内容的提问来源于stack exchange,提问作者Sam Vanhoutte

