Use Case – Automate assigning Microsoft Graphs’s User.Read.All permission to App Registration/Service Principal using DevOps pipeline. So that applications can read user profiles.
Challenge
To grant Microsoft Graphs’s User.Read.All permission, service principal under which pipeline will run, requires Global Administrator or Privileged Role Administrator. https://learn.microsoft.com/en-us/azure/active-directory/manage-apps/grant-admin-consent?pivots=portal . The problem is if grant any of these roles, service principal can be used to assign more than Microsoft Graphs’s User.Read.All permission. I am looking for a way where I can restrict service principal with Global Administrator or Privileged Role Administrator or Custom Role to allow assigning only User.Read.All permission, so that service principal cannot be misused.
2
Answers
The permission
AppRoleAssignment.ReadWrite.All
will allow your service principal to grant the permission and admin consent to other principals, without needing to assign Global Administrator or Privileged Role Administrator. Note this permission only allows grantingapplication
type permissions, and notdelegated
type permissions.Reference
Example with Graph API
Before
My example application below has the
AppRoleAssignment.ReadWrite.All
granted with admin consent. I’m going to use this application to grant theUser.Read.All
permission to itself.Send a request to the Graph API
PrincipalId
is the object Id of the Enterprise Application for my example app. This Id is used for the endpoint and in the request body.ResourceId
is the object Id of the Enterprise Application for Microsoft Graph (this Id is different for each tenant)AppRoleId
is the Id for your permission, which can be found in the Microsoft Graph permissions referenceappRoleAssignment API Reference
After
The example app now has
User.Read.All
permission assigned with admin consent granted.Yes, this is possible.
As you’ve noted, the directory roles Global Administrator and Privileged Role Administrator allow granting any Microsoft Graph permissions. Likewise, the Microsoft Graph app roles (application permissions) DelegatedPermissionGrant.ReadWrite.All and AppRoleAssignment.ReadWrite.All also allow granting any delegated permission, or app role, respectively. So, neither of those options are what you’re looking for.
Instead, what you want to do is the following:
The following sections show how to do this in more detail.
0. Setup
Here I’m using the Microsoft Graph PowerShell module, though you could do this with Microsoft Graph directly, of course. You’ll need the Microsoft.Graph.Applications, Microsoft.Graph.Identity.SignIns, and Microsoft.Graph.Identity.Governance modules. If you don’t have them yet, you can install them with:
Now, connect to Microsoft Graph PowerShell with the required permissions. We’re doing something very high privilege (creating and assigning directory roles), so the permissions here are all very privileged, and the user running these cmdlets will also need to be very privileged (Global Admin or Privileged Role Admin):
1. Create a permission grant policy
We’ll start by creating a custom permisison grant policy with two "includes" condition sets: the Microsoft Graph app role (application permission) User.Read.All, and the Microsoft Graph delegated permission User.Read.All. (If you only wanted one or the other, then just skip the one you don’t want.)
With the steps above, we have a permission grant policy that says: "Include the Microsoft Graph delegated permission User.Read.All, and the Microsoft Graph application permission (app role) User.Read.All, for any client application."
You could further limit the conditions if you wanted to. For example, if you only expect the automation to be granting permissions for apps registered in your tenant, you could use
clientApplicationTenantIds
to include that constraint. See the different options available in permissionGrantConditionSet.2. Create a custom directory role
The permission grant policy by itself does not do anything. It only comes into effect when it is included as part of the permission to grant permissions to apps, for example, as part of a permission in a custom directory role.
Here’s we’ll create a custom directory role, and include in that custom role definition two resource actions:
microsoft.directory/servicePrincipals/allProperties/read
: The permission to list service principals. Your automation service will probably need to be able to do this, so you can go ahead and include it here. (Alternatively, you could grant your automation service Application.Read.All, but it might be simpler to do everything with a directory role.) To learn more, see Enterprise app permissionsmicrosoft.directory/servicePrincipals/managePermissionGrantsForAll.{id}
: The permission to grant permissions, tenant-wide and on behalf of all, subject to the constraints that you defined in a permission grant policy. In the previous step we created a permission grant policy with ID "only-user-read-all", so here you’ll be usingmicrosoft.directory/servicePrincipals/managePermissionGrantsForAll.only-user-read-all
. To learn more, see App consent permissions3. Assign the custom directory role to the automation service
We now have a custom role that only allows granting User.Read.All. The remaining step is to assign that role to whoever or whatever needs that privilege. You could assign this to a user (and they’d be able to grant admin consent for User.Read.All), but in this scenario you want to assign it to your automation service’s service principal.
4. Test it out
In my examples below, I’m still using Microsoft Graph PowerShell, connecting as a service principal to which I assigned the custom role as in the previous steps. In your scenario, you might be using the Microsoft Graph SDK to call Microsoft Graph directly.