Posts A look at Azure RBAC Constrained Delegation
Post
Cancel

A look at Azure RBAC Constrained Delegation

If you’ve added role assignments in the Azure Portal, you may have seen an extra page in the portal allowing you to specify Conditions for the assignment. It’s been there for a while, but it’s not something I had looked into until recently and it turns out it can be really useful!

Image of the conditions tab when make role assignments in the Azure Portal

If you select “Not constrained” when setting role assignments, then you will get the same behaviour as you will have been used to. The user will be able to exercise the priviledges of their new assignment, however they like, within the scope you’ve set (for example, an Azure Subscription or Resource Group).

If you select Constrained and then click on +Add Condition you will be able to specify the conditions under which the role assignment is valid, which gives some interesting options.

Image of the conditions tab when make role assignments in the Azure Portal

Constrain Roles

This is a fairly straight forward use case. You want to allow someone to manage role assignments in an Azure Subscription, but you want to limit the level of access they can grant. For example, you might want to allow them to assign the “Reader” role only.

Image of the conditions tab when make role assignments in the Azure Portal

Constrain Roles and Principal Types

This is probably the most useful option with some interesting use cases.

Use Case 1: Allowing role assignment to groups only (interesting)

It’s considered good practice to use Azure AD Groups (sorry, Entra ID Groups!) in role assignments, rather than assigning roles directly to users. This makes it possible to grant the User Access Administrator role to a user (or a group!), but only allow them to assign roles to Groups. You could combine this with the “Constrain Roles” option to allow assignment of only the Reader role and only to groups.

constrain roles and principal types - groups

Use Case 2: Allowing role assignments to Managed Identities (more interesting!)

Say you created an Azure Subscription for a team developing a container based application and have given them the Contributer role on the Azure Subscription. They can get on with deploying the Azure resources they need to support development of their application.

As part of the deployment, an Azure Container App needs to connect to a Container Registry to pull down a container image. It’s best practice to use Managed Identities for these types of interaction between services, so that’s what the developers choose to do.

But, although their Contributor rights allow them to deploy a Container Registry and a Container App with a Managed Identity, they don’t have rights to give the Managed Identity rights to the Container Registry.

This is where the “Constrain Roles and Principal Types” option comes in. You can create a Role Assigment that allows the team to assign the “AcrPull” role to Service Principals, but not to any other Principal Types.

constrain roles and principal types - Service Principals

Constrain Roles and Principals

This option takes it a step further and allows you to specify the exact role assignments that can be made.

For example, perhaps the development team are regularly destroying and recreating Container Registry instances in their development environment. If there is a single User Managed Identity that is used by all the Web Apps in the environment, then the team will need to be able to assign the “AcrPull” role to the Managed Identity of the Web App, but not to any other Managed Identities.

This would let you delegate this right to the development team, without allowing them to assign permissions to other identities.

constrain roles and principals

Advanced Configuration

You can configure much more complex scenarios by specifying the actions and then build expressions that define the allowed roles, principal types and principal IDs.

constrain roles and principals

And you can define it as code if you feel that way inclined - or do it in the Azure Portal and then have it generate the code for you, just like the Export Template option for Azure Resources.

constrain roles and principals

Terraforming it…

Creating contrained delegations in Terraform is pretty straight forward. The role_assignment resource in the azurerm Terraform provider has a condition property. So you can assign “User Access Administrator” and then add your conditions.

The conditions are specified as code but it’s exactly the same as the code that the Azure Portal generates, so it you can always use that to figure out the code you need then copy/paste it.

The Terraform to assign the “User Access Administrator” role to a group with ID 362e3949-ccf4-4b02-a931-0449f5e89203 and then constrain it so it can only assign the “AcrPull” role to Service Principals is below.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
resource "azurerm_role_assignment" "acr_pull_delegation" {

  scope                = "/subscriptions/62e121c7-40f6-3dab-7bfb-eeb8e02e802c"
  role_definition_name = "User Access Administrator"
  principal_id         = "362e3949-ccf4-4b02-a931-0449f5e89203"

  condition_version = "2.0"
  condition = <<EOT
        (
            (
                !(ActionMatches{'Microsoft.Authorization/roleAssignments/write'})
            )
            OR 
            (
                @Request[Microsoft.Authorization/roleAssignments:RoleDefinitionId] ForAnyOfAnyValues:GuidEquals {7f951dda-4ed3-4680-a7ca-43fe172d538d}
                AND
                @Request[Microsoft.Authorization/roleAssignments:PrincipalType] ForAnyOfAnyValues:StringEqualsIgnoreCase {'ServicePrincipal'}
            )
        )
        AND
        (
            (
                !(ActionMatches{'Microsoft.Authorization/roleAssignments/delete'})
            )
        OR 
            (
                @Resource[Microsoft.Authorization/roleAssignments:RoleDefinitionId] ForAnyOfAnyValues:GuidEquals {7f951dda-4ed3-4680-a7ca-43fe172d538d}
                AND
                @Resource[Microsoft.Authorization/roleAssignments:PrincipalType] ForAnyOfAnyValues:StringEqualsIgnoreCase {'ServicePrincipal'}
            )
        )
        EOT
}

That’s it! Just a run through my notes on Constrained Delegation in Azure RBAC, hopefully it was useful!

References:

This post is licensed under CC BY 4.0 by the author.