跨订阅ACR拉取镜像的Azure Container App授权失败排查
问题:跨订阅ACR拉取镜像时Azure Container App授权失败
我需要创建Azure Container App,从另一个订阅的现有Azure Container Registry(ACR)拉取镜像。我的Bicep脚本执行以下操作:
- 创建用户分配托管标识
- 为该标识授予ACR的AcrPull RBAC角色
- 创建Container App并关联该标识(已配置
dependsOn依赖角色分配)
但部署时出现以下错误:
{ "code": "InvalidParameterValueInContainerTemplate", "message": "The following field(s) are either invalid or missing. Field 'template.containers.capp-devops-shared-001.image' is invalid with details: 'Invalid value: \"crbicepregistryprod001.azurecr.io/devops-agent:latest\": GET https:?scope=repository%3Adevops-agent%3Apull&service=crbicepregistryprod001.azurecr.io: UNAUTHORIZED: authentication required, visit https://aka.ms/acr/authorization for more information.';." }
部署后通过Azure门户确认托管标识已拥有ACR的AcrPull角色,但仍出现授权错误。
主Bicep脚本
@description('Specifies the location for all resources.') param location string = resourceGroup().location param tags object = contains(resourceGroup(), 'tags') ? resourceGroup().tags : {} @description('Specifies the docker container image to deploy.') param containerImage string = 'crbicepregistryprod001.azurecr.io/devops-agent:latest' @description('Specifies the container port.') param targetPort int = 80 @description('Number of CPU cores the container can use. Can be with a maximum of two decimals.') @allowed([ '0.25' '0.5' '0.75' '1' '1.25' '1.5' '1.75' '2' ]) param cpuCore string = '0.25' @description('Amount of memory (in gibibytes, GiB) allocated to the container up to 4GiB. Can be with a maximum of two decimals. Ratio with CPU cores must be equal to 2.') @allowed([ '0.5' '1' '1.5' '2' '3' '3.5' '4' ]) param memorySize string = '0.5' @description('Minimum number of replicas that will be deployed') @minValue(0) @maxValue(25) param minReplicas int = 1 @description('Maximum number of replicas that will be deployed') @minValue(0) @maxValue(25) param maxReplicas int = 3 var baseResourceName = replace(resourceGroup().name, 'rg-', '') var logAnalyticsName = 'log-${baseResourceName}' var containerAppName = 'capp-${baseResourceName}' var containerAppEnvName = 'cappenv-${baseResourceName}' resource containerAppEnv 'Microsoft.App/managedEnvironments@2022-06-01-preview' = { name: containerAppEnvName location: location sku: { name: 'Consumption' } properties: { appLogsConfiguration: { destination: 'log-analytics' logAnalyticsConfiguration: { customerId: logAnalytics.properties.customerId sharedKey: logAnalytics.listKeys().primarySharedKey } } } } resource containerIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { name: 'managedId' location: location } resource containerApp 'Microsoft.App/containerApps@2022-06-01-preview' = { name: containerAppName location: location identity: { type: 'UserAssigned' userAssignedIdentities: { '${containerIdentity.id}': {} } } properties: { managedEnvironmentId: containerAppEnv.id configuration: { ingress: { external: true targetPort: targetPort allowInsecure: false traffic: [ { latestRevision: true weight: 100 } ] } } template: { revisionSuffix: 'firstrevision' containers: [ { name: containerAppName image: containerImage resources: { cpu: json(cpuCore) memory: '${memorySize}Gi' } } ] scale: { minReplicas: minReplicas maxReplicas: maxReplicas } } } dependsOn: [ roleAssignment ] } resource logAnalytics 'Microsoft.OperationalInsights/workspaces@2022-10-01' = { name: logAnalyticsName location: location tags: tags properties: { retentionInDays: 30 } } var registrySubscriptionId = 'e90a0a8a-f5a7-4450-9745-07a5246740eb' var registryResourceGroupName = 'rg-bicepregistry-prod-001' module roleAssignment 'rg-acr-role-assignment.bicep' = { name: 'roleAssignment' scope: resourceGroup(registrySubscriptionId, registryResourceGroupName) params: { containerAppPrincipalId: containerIdentity.properties.principalId } } output containerAppFQDN string = containerApp.properties.configuration.ingress.fqdn
角色分配模块脚本
param containerAppPrincipalId string var registryName = 'crbicepregistryprod001' // Get a reference to the existing ACR resource existingACR 'Microsoft.ContainerRegistry/registries@2023-01-01-preview' existing = { name: registryName } //assign role for container app onto container registry var acrPullRole = '7f951dda-4ed3-4680-a7ca-43fe172d538d' resource roleAssignment 'Microsoft.Authorization/roleAssignments@2020-04-01-preview' = { name: guid(containerAppPrincipalId, 'AcrPull') scope: existingACR properties: { roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', acrPullRole) principalId: containerAppPrincipalId } }
问题原因及解决方法
原因
即使托管标识已拥有ACR的AcrPull权限,Container App不会自动使用关联的用户分配标识来拉取私有ACR镜像,必须显式配置镜像拉取的身份验证规则,将指定ACR与托管标识绑定。
解决方法
在主Bicep脚本的containerApp资源中,添加configuration.registries节点,将ACR服务器地址与用户分配标识关联:
修改后的containerApp资源片段
resource containerApp 'Microsoft.App/containerApps@2022-06-01-preview' = { name: containerAppName location: location identity: { type: 'UserAssigned' userAssignedIdentities: { '${containerIdentity.id}': {} } } properties: { managedEnvironmentId: containerAppEnv.id configuration: { ingress: { external: true targetPort: targetPort allowInsecure: false traffic: [ { latestRevision: true weight: 100 } ] } // 添加ACR身份验证配置 registries: [ { server: 'crbicepregistryprod001.azurecr.io' identity: containerIdentity.id } ] } template: { revisionSuffix: 'firstrevision' containers: [ { name: containerAppName image: containerImage resources: { cpu: json(cpuCore) memory: '${memorySize}Gi' } } ] scale: { minReplicas: minReplicas maxReplicas: maxReplicas } } } dependsOn: [ roleAssignment ] }
优化建议
为了避免硬编码,建议将ACR服务器地址提取为参数:
@description('ACR server address') param acrServer string = 'crbicepregistryprod001.azurecr.io' @description('Specifies the docker container image to deploy.') param containerImage string = '${acrServer}/devops-agent:latest'
然后将registries中的server值改为acrServer参数,提升脚本的可维护性。
内容的提问来源于stack exchange,提问作者Rob Bowman
相关产品推荐
相关产品推荐

