Assign Azure Privileged Identity Management Roles using Bicep

Azure Privileged Identity Management (PIM) is a tool that allows you to provide Just In Time (JIT) access to Azure RBAC roles. Using PIM, you can create a role assignment to make a user or group eligible for a role. This assignment doesn’t mean that the user or group has the role, but instead that they can request the role when they need it. When this occurs, the user can trigger an elevation request to be granted the role for a short period (usually hours, but definable). Rules can then be applied to their request, such as requiring approval, requiring a ticket number and so on, and then the rights are granted. PIM is a great tool for removing many permanent access rights to users, but it does require an Azure AD P2 licence for each user.

PIM is an Azure AD feature, so I assumed it wouldn’t be possible to create PIM assignments using Bicep (or ARM), but it is possible. PIM roles are often application or service-specific, so being able to create them as part of your Infrastructure as Code is quite helpful.

Creating PIM Assignments

To create a PIM assignment, we are going to use the Microsoft.Authorization/roleEligibilityScheduleRequests, the full API sec for this can be found here. This object can be used for more than just creating an assignment, it can, in theory, be used to activate an assignment, remove assignments and more. We’ll focus on creating and updating assignments.

To be able to use this, we are going to need a couple of pieces of information:

  • The object ID of the user or group you want to assign the role to. This can be found by looking at the user or group in AAD. You’re looking for the object ID field

  • The complete ID of the role you want to assign. This is usually in the format:

    subscriptions/<subscription ID>/providers/Microsoft.Authorization/roleDefinitions/<role ID>
    

    Subscription ID is the ID of the subscription holding the role you want to assign. The role ID is the GUID of the role. You can find the GUID’s for all the built-in roles in the MS docs here, or you can also use the handy AzRoleAdvertizer site. If you’re applying the assignment at the management group rather than subscription or resource, you will replace this with the ID of the management group role.

With this information, we can create the Bicep code we need. First, we need to get the start date for the role in the correct format. The format is 2022-04-10T14:40:08.067566 but fortunately, the Bicep utcNow function gets this in the correct format, so we can use that. This function can only be used as a default value for a parameter, so we need to create a parameter in our template that we assign this to and won’t override in the future.

param startTime string = utcNow()

Now we have that we can create the actual resource:

resource pimAssignment 'Microsoft.Authorization/roleEligibilityScheduleRequests@2022-04-01-preview' = {
  name: guid(resourceGroup().id, 'contributor')
  scope: resourceGroup()
  properties: {
    principalId: '<object ID of user or group>'
    requestType: 'AdminUpdate'
    roleDefinitionId: '<ID of role>'
    scheduleInfo: {
      expiration: {
        duration: 'P365D'
        type: 'AfterDuration'
      }
      startDateTime: startTime
    }
  }
}

A few things to note:

  • The name needs to be a GUID, so I am using the guid function to generate one, passing the resource group and a string as a seed to ensure a consistent GUID generation should I run this again
  • The request type is set to AdminUpdate. This will create a role if it doesn’t exist and update it if it does. You can use AdminCreate if you want only to create it.
  • The schedule info section is setting that the user or group should be eligible to elevate for a year (the max allowed) before the role needs to be reviewed
  • I have set the scope to be the resource group. This defines that the PIM role should be for this resource group only. If I wanted to assign rights to elevate over a whole subscription or management group, then I would adjust the scope

The whole template looks like this:

param startTime string = utcNow()

resource pimAssignment 'Microsoft.Authorization/roleEligibilityScheduleRequests@2022-04-01-preview' = {
  name: guid(resourceGroup().id, 'contributor')
  scope: resourceGroup()
  properties: {
    principalId: '<object ID of user or group>'
    requestType: 'AdminUpdate'
    roleDefinitionId: '<ID of role>'
    scheduleInfo: {
      expiration: {
        duration: 'P365D'
        type: 'AfterDuration'
      }
      startDateTime: startTime
    }
  }
}

Once deployed, you should be able to go to the PIM UI in the portal and see that the designated user or group is now eligible to elevate to this role.