Azure Custom Role Definitions and Assignment Scopes

Working with custom Role Definitions in Azure can be a funny thing.

Interestingly, when reviewing the Azure Active Directory user interface in Azure Portal you will not find a way to query all available role definitions. If you query the Roles and Administrators view you will only see administrator roles:

Roles and administrators view

With a PowerShell cmdlet you are able to list all. Get-AzRoleDefinition | select name | sort name | ft results in something like the following:

Name
----
AcrDelete
AcrImageSigner
AcrPull
AcrPush
AcrQuarantineReader
AcrQuarantineWriter
API Management Service Contributor
API Management Service Operator Role
API Management Service Reader Role
App Configuration Data Owner
...

But are these really all the role definitions out there? Obviously not! This list is scoped to the subscription you are currently targeting with your current Azure Context.
In order for you to try out yourself, just create a couple of role definitions with various assignment scopes. Assuming you have owner permissions to the following subscriptions that are being trusted by the same Azure Active directory; Get-AzContext -ListAvailable | select Subscription, Tenant:

Subscription                         Tenant
------------                         ------
e36fadc1-c562-4055-9761-4a24e82d11b2 2a4ad7d9-ca66-40e4-9b03-7d71ef12e75b
29d33106-a89b-476b-9586-fa2ee4076b30 2a4ad7d9-ca66-40e4-9b03-7d71ef12e75b

(guids are just made up)

Create the following custom roles:

# Create a role only assignable to subscription 1:
Set-AzContext Subscription1
$roleDefinition = Get-AzRoleDefinition -Name 'Reader'
$roleDefinition.Id = $null
$roleDefinition.IsCustom = $true
$roleDefinition.Name = 'Role1'
$roleDefinition.AssignableScopes.Clear()  
$roleDefinition.AssignableScopes.Add("/subscriptions/e36fadc1-c562-4055-9761-4a24e82d11b2")
New-AzRoleDefinition -Role $roleDefinition

# Create a role only assignable to subscription 2:
Set-AzContext Subscription2
$roleDefinition.Name = 'Role2'
$roleDefinition.AssignableScopes.Clear()  
$roleDefinition.AssignableScopes.Add("/subscriptions/29d33106-a89b-476b-9586-fa2ee4076b30")
New-AzRoleDefinition -Role $roleDefinition

# Create a role assignable to both subscription 1 and 2, created from subscription1's context:
Set-AzContext Subscription1
$roleDefinition.Name = 'Role3'
$roleDefinition.AssignableScopes.Clear()  
$roleDefinition.AssignableScopes.Add("/subscriptions/e36fadc1-c562-4055-9761-4a24e82d11b2")
$roleDefinition.AssignableScopes.Add("/subscriptions/29d33106-a89b-476b-9586-fa2ee4076b30")
New-AzRoleDefinition -Role $roleDefinition

# Create a role assignable to both subscription 1 and 2, created from subscription2's context:
Set-AzContext Subscription2
$roleDefinition.Name = 'Role4'
New-AzRoleDefinition -Role $roleDefinition

Hint: An easy way to switch between contexts, is to assign the full array to a variable and specify a specific index on the prompt:

$allSubscriptions = Get-AzContext -ListAvailable
Set-AzContext $allSubscriptions[0]
Set-AzContext $allSubscriptions[1]

When you list our just made custom roles per subscription you will see the following:

Az-SetContext Subscription1
Get-AzRoleDefinition | where name -like "Role*" | select Name, AssignableScopes

Name  AssignableScopes
----  ----------------
Role1 {/subscriptions/e36fadc1-c562-4055-9761-4a24e82d11b2}
Role3 {/subscriptions/29d33106-a89b-476b-9586-fa2ee4076b30, /subscriptions/e36fadc1-c562-4055-9761-4a24e82d11b2}
Role4 {/subscriptions/29d33106-a89b-476b-9586-fa2ee4076b30, /subscriptions/e36fadc1-c562-4055-9761-4a24e82d11b2}

Az-SetContext Subscription2
Get-AzRoleDefinition | where name -like "Role*" | select Name, AssignableScopes

Name  AssignableScopes
----  ----------------
Role2 {/subscriptions/29d33106-a89b-476b-9586-fa2ee4076b30}
Role3 {/subscriptions/29d33106-a89b-476b-9586-fa2ee4076b30, /subscriptions/e36fadc1-c562-4055-9761-4a24e82d11b2}
Role4 {/subscriptions/29d33106-a89b-476b-9586-fa2ee4076b30, /subscriptions/e36fadc1-c562-4055-9761-4a24e82d11b2}

So all the roles that are assignable to the particular subscription scope are listed.

Built-in Reader role

Another thing to review is that the Reader role is the same for all subscriptions; Get-AzRoleDefinition -Name 'Reader' in all contexts yields the same:

Name             : Reader
Id               : acdd72a7-3385-48ef-bd42-f606fba81ae7
IsCustom         : False
Description      : Lets you view everything, but not make any changes.
Actions          : {*/read}
NotActions       : {}
DataActions      : {}
NotDataActions   : {}
AssignableScopes : {/}

Specify the scope

Instead of switching the Azure Context, you can also query role definitions for a particular scope. To no surprise the following is shown:

Az-SetContext Subscription1
Get-AzRoleDefinition -Scope "/subscriptions/29d33106-a89b-476b-9586-fa2ee4076b30" | where name -like "Role*" | select Name, AssignableScopes

Name  AssignableScopes
----  ----------------
Role2 {/subscriptions/29d33106-a89b-476b-9586-fa2ee4076b30}
Role3 {/subscriptions/29d33106-a89b-476b-9586-fa2ee4076b30, /subscriptions/e36fadc1-c562-4055-9761-4a24e82d11b2}
Role4 {/subscriptions/29d33106-a89b-476b-9586-fa2ee4076b30, /subscriptions/e36fadc1-c562-4055-9761-4a24e82d11b2}

Insufficient permissions

What is also of interest, what error is thrown when you do not have enough permissions to create a role on the subscription scope, e.g. with subscription id 09d7deb8-ca5f-4741-a905-5b78994a4032:

New-AzRoleDefinition : The client '<your principal name>' with object id a72a5c5a-113a-4adb-a584-a9bab609cb37' does not have authorization to perform action 'Microsoft.Authorization/roleDefinitions/write' over scope '/subscriptions/09d7deb8-ca5f-4741-a905-5b78994a4032' or the scope is invalid. If access was recently granted, please refresh your credentials.

Other Azure Active Directory

When you try to define a role for another directory you will receive the following error:

New-AzRoleDefinition : The access token is from the wrong issuer 'https://sts.windows.net/36eb2eb1-9a41-4126-8e34-9ab6ab4283a1/'. It must match the tenant 'https://sts.windows.net/6d574385-313a-4b25-b397-742101102e54/' associated with this subscription. Please use the authority (URL) 'https://login.windows.net/6d574385-313a-4b25-b397-742101102e54' to get the token. Note, if the subscription is transferred to another tenant there is no impact to the services, but information about new tenant could take time to propagate (up to an hour). If you just transferred your subscription and see this error message, please try back later.

Insufficient permissions 2

You could also bump into the following error:

Multiple error occurred: Forbidden,Forbidden. Please see details.

In our case this was caused by the principal not having access to one of the existing scopes in order to remove it, while adding another. We are able to solve this by removing the scope first with a second principal that does have access to all existing scopes, and then added the new scope with the first principal. We would like to learn where we can find these details as mentioned in the error message though 😉

Reacties

Populaire posts van deze blog

Exploring advanced DOM interop with Blazor WebAssembly

TypeScript async/await example for the browser

Troubleshooting restoring a site collection