Alexander Schmidt
Alexander Schmidt

Reputation: 5733

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

I've created a Bicep template. In it I create a user-assigned identity and reference it in other resources like this

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

Whenever I deploy this I need 2 runs. The first run ends in the error message:

Principal XXX does not exist in the directory YYY

where XXX would be a principal id the user-assigned identity has and YYY is my tenant id. If I now look into the portal the identity is created and XXX is the correct id.

So when I now simply re-run the deployment it works.

I consider it a bug in dependsOn which should relate to ARM templates and not Bicep. I could not find any place where I can report ARM template issues to Microsoft.

I'm asking to assure that I do not miss something else here.

Edit: Added complete working sample which shows the bug. To use it, copy the script content into a test.bicep locally. Then create a resource group (lets call it "rg-test"), ensure that your local POSH context is set correctly and execute the following line in the folder where you stored the bicep in:

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

Upvotes: 1

Views: 6899

Answers (3)

Thomas
Thomas

Reputation: 29736

In the role assignment, you need to specify the principalType to ServicePrincipal and also use an api version greater or equal than: 2018-09-01-preview.

When you create a service principal, it is created in Azure AD. It takes some time for the service principal to be replicated globally. By setting the principalType to ServicePrincipal, it tells the ARM API to wait for the replication.

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

Upvotes: 6

Artem
Artem

Reputation: 2314

You need to reference a newly created identity inside identity property of the target resource. dependsOn is redundant because bicep creates resources in the correct order based on actual usage:

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 documentation doesn't recommend to use dependsOn without as strong reason:

In most cases, you can use a symbolic name to imply the dependency between resources. If you find yourself setting explicit dependencies, you should consider if there's a way to remove it.

Upvotes: 1

DreadedFrost
DreadedFrost

Reputation: 2978

So bicep does not require the dependsOn segment if referencing the property correctly.

Need to reference the properties.principalId of the userId in the resource block.

So would look like:

userId.properties.principalId

Here's a quickstart that calls out in a working example how this would work.

Upvotes: 0

Related Questions