Rob Bowman
Rob Bowman

Reputation: 8751

azure bicep to create a container app with an image from secure registry

I would like to create an azure container app that pulls its image from an existing azure container app registry that sits in a different subscription.

My main bicep:

My problem is, it's giving the following error:

  "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.';."

This is my main.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

And this is the module it calls to apply the role assignment:


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
    }
}

After the failed deployment ends, I've used the Azure portal to check the role assignment at the container registry scope and it looks good - the managed identity has the AcrPull role. So, I'm confused as to why the error is being raised?

Upvotes: 2

Views: 1361

Answers (1)

Rob Bowman
Rob Bowman

Reputation: 8751

Thanks again for Thomas for pointing me in the right direction. I also found this great post that gives examples, such as the following:

resource customimagecontainerapp 'Microsoft.App/containerApps@2022-03-01' = {
  name: 'customimagecontainerapp'
  location: location
  properties: {
    managedEnvironmentId: environment.id
    configuration: {
      secrets: [
        {
          name: 'containerregistrypasswordref'
          value: azureContainerRegistryPassword
        }
      ]
      ingress: {
        external: true
        targetPort: 8080
      }
      registries: [
        {
          // server is in the format of myregistry.azurecr.io
          server: azureContainerRegistry
          username: azureContainerRegistryUsername
          passwordSecretRef: 'containerregistrypasswordref'
        }
      ]
    }
    template: {
      containers: [
        {
          // This is in the format of myregistry.azurecr.io
          image: '${azureContainerRegistry}/customimagecontainerapp:latest'
          name: 'customimagecontainerapp'
          resources: {
            cpu: '0.5'
            memory: '1.0Gi'
          }
        }
      ]
      scale: {
        minReplicas: 1
        maxReplicas: 1
      }
    }
  }
}

Upvotes: 0

Related Questions