You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

跨订阅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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 13:50:32