Delegating App Registration Admin Consent permissions in Azure AD

Was trying to find out if there’s a way of letting others in our firm create App Registrations and add permissions to them, but limit what permissions they can admin consent to. You know, maybe allow them to admin consent delegated permissions but not application permissions. Or even allow application permissions but not certain type of application permissions. Typically you need to be either a Global Admin or a Privileged Role Admin to be able to do this, and that gives out a lot more permissions than needed.

Looks like the ability to do this was released about a year ago. What you need to do is:

  1. Create app consent policies as detailed in this link (this is what defines what consents someone can do), and
  2. Add these consent policies to custom roles that you create as detailed in this link (this is what applies the app consent policies to users & groups who have that custom role).

All of this needs to be done via PowerShell, and some of these even require the AzureADPreview module (even though it’s been a year since release of this feature).

So let’s get cracking!

First, install/ enable the preview module and connect to AzureAD.

After that, if you want to see the existing app consent policies you can do so with the following cmdlet:

Here’s what the default output looks like:

Creating a new app consent policy

Creating a new app consent policy is via the New-AzureADMSPermissionGrantPolicy cmdlet to create a policy and then the New-AzureADMSPermissionGrantConditionSet to add permissions to that policy.

Let’s make an app consent policy that allows consent to delegated permissions only. This one’s very simple:

Note the Id (mytenant-all-delegated-permissions). We need it later.

Let’s also make an app consent policy that allows consent to any application permissions; but not a few critical ones. For example: I don’t want someone to be able to consent to an application permission that lets them modify roles… that would be silly after all as anyone who can do this consent will be able to escalate themselves to the Global Admin role for instance. :)

The official document has an example like the one below where they exclude certain delegated permissions:

How do you get those permission ids though? The document simply says -Permissions are “The identifier of the resource application to scope consent operation down to. It could be @("All") or a list of permission ids.” Not very helpful.

The app consent document is slightly more helpful.

Hmm, so it’s in the ServicePrincipal object of the API. I am interested in the Graph API so lets dig into that.

First I’ll search for the ServicePrincipal object and filter to any with the words “Graph” in it:

I think Microsoft Graph is what I am looking for? Let’s expand that:

Yup, jackpot! Let’s look at what AppRoles are available as I am interested in application level permissions:

Best to put them into a CSV so I can easily read in Excel:

Here’s a few I want to exclude (highlighted):

I know the -Permissions parameter expects an array of the Ids so let’s create that. I put all the Ids I want to exclude into a text file (called excludedIds.txt in the snippet below). Then I read them into an array:

Then I create the app consent policy. I learnt a bunch of things through trial and error here so I’ll summarize them below:

  • I have to first include/ allow everything and then do an exclusion – i.e. I cannot create a policy having only exclusions as I have to define the set of policies that it is allowed in the first place and then exclude from that.
  • When excluding I have to specify the resource application whose permissions I am excluding. In this case it’s the Graph API. However, I don’t use the ObjectId property of the Service Principal but the AppId.
  • As a best practice let’s also specify the resource application when defining what is allowed/ included. Because if I leave that empty then it means all permissions of all APIs are allowed – and that’s not what we want here. I want to allow all permissions of the Graph API (because I selectively disable a few later), so if I don’t restrict the allowing also to just the Graph API it means any other APIs like (say) Exchange Online and PowerBI etc. are allowed. That means someone could potentially consent to an application level permission for the Exchange Online API to do a full_access_as_app as I am not disallowing anything to do with this API later on. Oops!

Here’s what I did:

That’s it! So now I have two permission policies – one for all delegated permissions (for all APIs – just clarifying that); another for all except a few applications permissions for the Graph API.

Creating the custom role

The next step is to add the above permission policies to a custom role. This can’t be done via the Portal, however. You can create a custom role on the portal and assign it to users, but the specific bit of adding the above permission policies needs to be done via PowerShell.

There’s two permissions one can add to the custom role. Here’s the full list of permission policies related permissions, but the first two are what is of interest:

In my case I want the admins to be able to consent on behalf of themselves and/ or tenant. If you don’t want to do either of these then skip that permission when you do this.

My idea is to also have two custom roles. One for Level 1 Application admins – who can do only delegated permissions for themselves and/ or tenant – and another for Level 2 Application admins who can do delegated and application permissions (subject to exclusions as above) for themselves and/ or tenant.

If you want to create a new custom role and add the permissions you can do it thus:

I’ll delve into the additional permissions above in a bit.

If you already have a custom role and only want to add these new permissions to it you can do it thus:

And that’s it really! Now add users to the appropriate role group and they can do what you have allowed.

Those additional permissions

I added a few extra permissions above so the user in that custom role can also create App Registrations. You can get of the permissions at this link. I wanted users to be able to 1) create app registrations (microsoft.directory/applications/create), 2) create the associated service principal (microsoft.directory/servicePrincipals/create), and 3) read all properties of service principals (microsoft.directory/servicePrincipals/allProperties/read) – I found that without this the user couldn’t view any app registration or service principal, he/ she could only search for them.

I might in future also add microsoft.directory/applications/permissions/update (or rather microsoft.directory/applications.myOrganization/permissions/update) so the admins can create permissions for other apps. With the current permissions above a Level 1 or Level 2 admin can only add permissions to the apps they own/ create.

With the above permissions any Level 2 or Level 1 admin cannot create secrets and that is intentional. Again, I don’t want them to be able to add secret to an app registration that possibly has a lot of permissions and that way do malicious things. If you want to allow that though then microsoft.directory/applications/credentials/update is what you must add. All this and more can be found at the permissions link above.

Examples

A few examples of this in action.

First up, a warning on something I encountered and wasted time on. Initially I was creating the Level 2 custom role above with only the application permissions. This was because I was figuring things out and wanted to keep things minimal; and also because I thought maybe I could add the Level 2 admins to the Level 1 admins role to grant them the delegated permissions consent. So when I logged in with an admin who was in the Level 2 custom role (and it had only the application permissions) and I created an app registration with an application permission that was in the allowed list, the admin consent button was grayed out:

I wasted a fair bit of time trying to understand if I did something wrong or whether my understanding of everything I wrote above was mistaken. Then I realized I was right all along, but because app registrations have a delegated permission added by default (the User.Read above) the admin consent was grayed out because my Level 2 user didn’t have rights to admin cosent delegated permissions. Doh! So I removed the delegated permission and refreshed the page a couple of times and then the button was no longer grayed out and I could do an admin consent:

Keep this in mind and mention to the Level 1 and Level 2 admins. If a Level 1 admin adds both delegated and application permissions for instance, the admin consent button will be grayed out even though they have rights to consent to the delegated permissions. Their workflow shoud be to first add the delegated permissions, do the consent, then add the application permissions so someone else can do the consent for those (or get someone else to both add and consent the application permissions).

Back to examples, if I were to add a restricted API permission:

Then the admin consent is still visible but clicking it throws an error:

Excellent! This is just what we want.

One more thing

I wasn’t aware of this until I stumbled upon it a few weeks ago. You can add any identity to a custom role. That is to say if you have an app registration service principal or an Azure Automation identity or a Function App identity you can add these to the custom role and they too would have the rights associated with that role. This is useful if you want to create some sort of automation to create app registrations and do admin consents, but want this to be restricted – simply add it to one of the custom roles above.