Coder Perfect

Role assignment in Azure Bicep – Principal does not exist in the directory

Problem

A Biceps template has been generated. In it, I generate a user-assigned identity that I refer to in other resources, such as this one.

var identityName = 'mid-dd-test'
var roleName = 'TestRole'
var roleDescription = 'Some test'
var roleScopes = [
    resourceGroup().id
]
var resolvedActions = [
    'Microsoft.Resources/subscriptions/resourcegroups/*'
  'Microsoft.Compute/sshPublicKeys/*'
]
var permittedDataActions = []

resource userId 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = {
  name: identityName
  location: resourceGroup().location  
}

resource roleDef 'Microsoft.Authorization/roleDefinitions@2018-01-01-preview' = {
  name: guid(subscription().id, 'bicep', 'dsadsd')  
  properties: {
    roleName: roleName
    description: roleDescription
    type: 'customRole'    
    assignableScopes: roleScopes
    permissions: [
      {        
        actions: resolvedActions
        dataActions: permittedDataActions
      }
    ]
  }
}

resource roles 'Microsoft.Authorization/roleAssignments@2018-09-01-preview' = {
  name: guid(subscription().id, 'bicep-roleassignments', 'dsddsd')  
  properties: {
    principalId: userId.properties.principalId
    roleDefinitionId: roleDef.id
  }
}

I need two runs every time I deploy this. The first run ends with the following error:

Principal XXX does not exist in the directory YYY

where XXX is the user-assigned identity’s principle id and YYY is my tenant id. When I go into the portal now, the identity is generated, and the right ID is XXX.

So now I just re-run the deployment and it works.

I believe it is a bug in dependsOn, as it should be related to ARM templates rather than Bicep. I couldn’t discover a way to contact Microsoft about ARM template difficulties.

I’m asking to make sure I’m not missing anything else.

Edit: Added a complete functional sample that demonstrates the issue. To use it, save the script’s contents to a test.bicep file on your computer. Then, in the folder where you saved the bicep, create a resource group (let’s call it “rg-test”), make sure your local POSH context is set correctly, and run the following line:

New-AzResourceGroupDeployment -Name deploy -Mode Incremental -TemplateFile .\test.bicep -ResourceGroupName rg-test

Asked by Alexander Schmidt

Solution #1

You must set the principalType to ServicePrincipal in the role assignment, as well as use an API version greater than or equal to: 2018-09-01-preview.

A service principle is generated in an Azure AD when you build it. The service principal must be duplicated globally, which takes time. The ARM API is told to wait for replication by setting the principalType to ServicePrincipal.

resource roles 'Microsoft.Authorization/roleAssignments@2018-09-01-preview' = {
  name: guid(subscription().id, 'bicep-roleassignments', 'dsddsd')  
  properties: {
    principalId: userId.properties.principalId
    roleDefinitionId: roleDef.id
    principalType: 'ServicePrincipal'
  }
}

Answered by Thomas

Solution #2

You must reference a freshly formed identity in the target resource’s identity attribute. Because bicep produces resources in the correct sequence depending on actual usage, dependsOn is superfluous.

resource userId 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = {
  name: 'myidentity'
  location: resourceGroup().location
}

resource appService 'Microsoft.Web/sites@2021-02-01' = {
  name: 'appserviceName'
  location: resourceGroup().location
  properties: {
    //...
  }
  identity: {
    type: 'UserAssigned'
    userAssignedIdentities: {
      '/subscriptions/{your_subscription_id}/resourceGroups/${resourceGroup().name}/providers/Microsoft.ManagedIdentity/userAssignedIdentities/${userId.name}': {}
    }
  }  
}

The manual advises against using dependsOn unless there is a compelling reason to do so:

Answered by Artem

Solution #3

If the property is correctly referenced, bicep does not require the dependsOn segment.

The properties must be referenced. principalId of the resource block’s userId.

As an example, consider the following:

userId.properties.principalId

Here’s a quickstart that demonstrates how this would operate in practice.

Answered by DreadedFrost

Post is based on https://stackoverflow.com/questions/70581387/azure-bicep-role-assignment-principal-does-not-exist-in-the-directory