Azure / aca-dotnet-workshop

A Dotnet Azure Container Apps workshop showcasing how to accelerate developers' ability to develop and ship distributed applications.
https://azure.github.io/aca-dotnet-workshop/
MIT License
103 stars 81 forks source link

Use User-Assigned Managed Identity to access Azure Container Registry #122

Open simonkurtz-MSFT opened 1 year ago

simonkurtz-MSFT commented 1 year ago

Please describe the feature.

We need a user-assigned managed identity to access Azure Container Registry in order to pull images to create Azure Container Apps. Using a system-assigned managed identity does not work because we can't create one until the container app create, but that won't exist until we can securely pull an image from the registry using an identity. Chickens and eggs, rejoice!

jdrepo commented 4 months ago

Hi Simon,

I think it would work if the creation and rbac role assignment for user-assigned managed identity are moved into a separate module and then reference the "containerRegistryUserAssignedIdentityId" in the module output ?

module userassigned-identity.bicep

targetScope = 'resourceGroup'

// ------------------
//    PARAMETERS
// ------------------

@description('The location where the resources will be created.')
param location string = resourceGroup().location

@description('The tags to be assigned to the created resources.')
param tags object = {}

// Container Registry
@description('The name of the container registry.')
param containerRegistryName string

// ------------------
// VARIABLES
// ------------------

var containerRegistryPullRoleGuid='7f951dda-4ed3-4680-a7ca-43fe172d538d'

resource containerRegistry 'Microsoft.ContainerRegistry/registries@2023-01-01-preview' existing = {
  name: containerRegistryName
}

resource containerRegistryUserAssignedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = {
  name: 'aca-user-identity-${uniqueString(resourceGroup().id)}'
  location: location
  tags: tags
}

resource containerRegistryPullRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = if(!empty(containerRegistryName)) {
  name: guid(subscription().id, containerRegistry.id, containerRegistryUserAssignedIdentity.id) 
  scope: containerRegistry
  properties: {
    principalId: containerRegistryUserAssignedIdentity.properties.principalId
    roleDefinitionId: resourceId('Microsoft.Authorization/roleDefinitions', containerRegistryPullRoleGuid)
    principalType: 'ServicePrincipal'
  }
}

output containerRegistryUserAssignedIdentityId string = containerRegistryUserAssignedIdentity.id

and then reference them incontainer-apps.bicep

module containerRegistryUserAssignedIdentity 'userassigned-identity.bicep' = {
  name: 'containerRegistryUserAssignedIdentity-${uniqueString(resourceGroup().id)}'
  params: {
    containerRegistryName: containerRegistryName
  }
}

module frontendWebAppService 'container-apps/webapp-frontend-service.bicep' = {
  name: 'frontendWebAppService-${uniqueString(resourceGroup().id)}'
  params: {
    frontendWebAppServiceName: frontendWebAppServiceName
    location: location
    tags: tags
    containerAppsEnvironmentId: containerAppsEnvironment.id
    containerRegistryName: containerRegistryName
    // containerRegistryUserAssignedIdentityId: containerRegistryUserAssignedIdentity.id
    containerRegistryUserAssignedIdentityId: containerRegistryUserAssignedIdentity.outputs.containerRegistryUserAssignedIdentityId
    frontendWebAppServiceImage: frontendWebAppServiceImage
    appInsightsInstrumentationKey: applicationInsights.properties.InstrumentationKey
    frontendWebAppPortNumber: frontendWebAppPortNumber

  }
}
simonkurtz-MSFT commented 4 months ago

Hi @jdrepo,

Something closely along those lines would do the trick. I won't be able to get to it any time soon due to other priorities, unfortunately.