The Intersection of Graph and Entra ID: Application Permissions and Roles

When you work someplace that develops software that interacts with Entra ID, the question of Graph permissions eventually comes up. With the recent Midnight Blizzard attack against Microsoft, where a threat actor appears to have used service principals and Graph permissions to access resources in Microsoft’s own Entra tenant, the scrutiny on permissions grows even more intense. You can read more about this with a great write-up from Andy Robbins here, Microsoft Breach — What Happened? What Should Azure Admins Do? | by Andy Robbins | Feb, 2024 | Posts By SpecterOps Team Members.

Primer on the Microsoft Graph API

Before jumping into the permission weeds, let’s review a few things to set the stage. If you already understand the Graph API basics, feel free to scroll past.

What is Graph API

The Microsoft Graph API is the unified API endpoint into most Microsoft 365 services, which includes Entra ID. For purposes of this article, the terms Graph and Graph API refer to the Microsoft Graph API.

Microsoft Graph API Diagram / Courtesy Microsoft Learn

You can read more of an overview about the Graph API here, Microsoft Graph overview – Microsoft Graph | Microsoft Learn.

What are Application Permissions

In Graph, there are two permission types, Delegated, and Application. The focus of this article is on application permissions, which allow an application to interact with Microsoft Graph, and the associated Microsoft services, without needing the context of a user.

A common example might be scripts an organization developed that manage user objects in Entra ID – while there are robust third-party solutions that can also manage this stuff, many orgs still run scripts to maintain directory data. If the script is running as a scheduled task in something, somewhere, it’s likely using application permissions (or hopefully is).

Most third-party software applications that interact with Microsoft 365 without a user context use application permissions – this way their software can do its software “things” behind the scenes, not centered around a user, for whatever purpose the software exists. If the software is a conference room integration it might require the ability to read all calendars in Exchange Online.

We won’t cover delegated permissions here, but for reference, these are permissions that allow an application to access resources on behalf of a user. A good example would be an application that wants to save files to OneDrive or read a calendar in Exchange Online. In this instance, the application is acting in the context of the user.

How Graph Interacts with Entra ID

As mentioned, Graph is the one stop shop for all Microsoft 365 resources, including Entra ID. When you query Graph, the service you are reaching out to is derived from the path in the URL.

If we breakdown this example, we see two primary components:

  • The version or endpoint. These terms are both used in Microsoft documentation and can be thought of interchangeably – this is what determines whether you are hitting the v1.0 or beta endpoint.
  • The resource. The resource is a component of the service, but we don’t need to make a specific reference to the service within the Graph API call, we can just let Graph determine what service to call on the backend based on the resource we are looking to interact with.

One time that it does become important to know what service relates to the resources you are accessing is when you are heavily interacting with Graph, and potentially hitting the dreaded 429 response, which is the error you’ll receive back from Graph if your requests are being throttled.

Throttled or not, if you are curious to get an idea of how resources are aggregated into different services, check out the throttling limits here, Microsoft Graph service-specific throttling limits – Microsoft Graph | Microsoft Learn.

Talking to Graph

As Microsoft Graph is a REST API, you use HTTP methods to interact with it. Those with a stronger sysadmin background, and less of a developer background, can be challenged to learn Graph times, but using Graph Explorer helps accelerate that process.

It also helps to understand how the basic CRUD operations of a directory service translate into HTTP methods:

CRUD OperationHTTP Method

The translation is mostly 1:1. You’ll notice that both PUT and PATCH are options for updating; searching the Graph API reference there are only five operations against Entra that use PUT. Point being, most update operations with Entra ID are going to use PATCH.

Exploring application permissions

If you are familiar with Access Control Lists and Access Control Entries in Active Directory, understanding permissions in Entra ID is not as difficult to grasp upfront as it might seem. For simplicity we’ll stick to using the term permissions, and not delve into all the nuances of DACLS and ACE and the such that compose security in Active Directory, but if you want to read more, Microsoft has a nice article on them from an identity security perspective here, Active Directory Access Control List – Attacks and Defense – Microsoft Community Hub.

Where permissions exist

In Active Directory permissions are attached to the target objects, things like users and groups. If I want to grant Sarah permission to change a user’s password, I will apply those permissions onto the user objects, granting Sarah Reset password.

In many instances the permissions are applied onto an Organizational Unit (OU) and inherited down onto the objects, so I could also grant Sarah Reset password on an OU, and she would have the ability to reset the password of all users inheriting that entry in the OU.

Permission relationship in Active Directory

The above diagram is high-level, not intended to describe the actual password reset process and the mechanisms that perform an access check in Active Directory, but to just help visualize the relationship.

Similarly, if I wanted to allow Todd to create new groups, I would grant Create Group objects onto an OU; since the group doesn’t exist, you have many scenarios where you are applying the permissions onto the structure above.

In Active Directory, whether a real service account that’s a gMSA, or a user acting as as service account, the same model applies.

Permission relationship in Active Directory for a service account

In Entra ID, Graph API permissions are applied on the requesting service principal, not on the target object. While an app registration is used to describe the desired permissions, the service principal is the object that holds the relationship to the delegated and application permission grants. If you are still uncertain of the difference between app registrations and enterprise applications, take a look at my deep dive here, Entra App Registrations and Enterprise Applications: The Definitive Guide – Eric on Identity.

Application permissions are held as an appRoleAssignment resource type and are associated with a service principal.

If we look at the example of creating a group, the permissions will look like the following.

Application permissions to create a group

In this example, the application, a daemon, or backend type service, has the credentials necessary to authenticate to Entra ID as the service principal Cloud Application. Cloud Application has been given Graph API permissions of Group.Create, and subsequently can create a group in Entra ID.

While the focus for service principals heavily targets developers, we should also think of service principals as modern service accounts. Just as we want to replace user-based service accounts with gMSA in Active Directory, wherever we can replace user objects with service principals in Entra ID, we want to do the same. For all those one-off scripts that we run as sysadmins, start looking service principals as a replacement.

Consenting to Graph Permissions

When you create an app registration, you can go through and specify the permissions you want. In the Entra admin center portal, we must specify the permissions we want on the app registration.

But how do we put those permissions into action? Through admin consent. Admin consent is the process of approving the requested permissions in your Entra tenant. While it may feel confusing, because app registrations and service principals serve multiple purposes for single and multi-tenant applications, even in a single-tenant app, you need to approve the permissions you are requesting.

Admin consent has two additional and slightly confusing parts to it:

  • Both the app registration and enterprise application blade in the Entra admin center have a Grant admin consent button. They both do the same exact thing. The button is added for convenience to the app registration blade. That’s it. If you are creating an application that is going to be used by something like a script, it saves you the time of having to move between two different sections of the portal.
  • Only a Global Administrator can grant consent to the Microsoft Graph API. Microsoft documentation will highlight that Application Administrator and Cloud Application Administrator role owners can grant consent, however, they cannot for Microsoft Graph.

Putting Permissions into Action

Let’s walk through what it looks like to use application permissions in Entra ID.

We’ve created a new application, Cloud Application, and we’ve specified and consented to the Group.Create permission.

For purposes of this article we’ll be walking through connecting to Graph using the Microsoft Graph PowerShell SDK.

We’ve already configured our credentials, so we just specify the creds and the tenant ID to connect to Graph. We then can also verify the context we are authenticated with by using Get-MGContext.

Looking at the output, we can see that we are connected as the application, and under scopes, we see the application permission assigned.

Let’s create a group.

We can check our audit logs and indeed see that the group was created by the Cloud Application

As we only have the Group.Create permission, while we can go on a spree creating hundreds of groups, we can’t update or delete them.

When application permissions can become tricky

We want our application to have the ability to delete groups.

When we go into the permissions for Graph, what we’ll find is that some of the precision we desire, and perhaps expect coming from the world of Active Directory, does not exist. We had a specific Group.Create permissions, so one might expect Group.Update, Group.Delete, and so on… unfortunately expections will not be met here.

We can see that of the available application permissions for group, the only other options are Group.Read.All, and Group.ReadWrite.All. Group.ReadWrite.All provides us the ability to delete groups, but this ability extends across all groups in the Entra tenant.

Application permissions to create, manage, and delete groups

We add our new permission, disconnect, and then reconnect to Graph. We can see our new permission is available under scopes.

With a simple one-liner, we can delete the group we had previously created, this time with no error.

We can now also add users to the group.

What if we want to allow the same permissions but only on certain groups? That’s where application permissions start to fall short, and roles might become part of the solution.

Roles can fill the application permission granularity gap – somewhat

The problem we are facing is we want a scenario that looks like the following: the ability to only manage certain groups.

Our desired scenario

With Active Directory, we could just move the groups into a sub-OU and set the permissions, or if necessary, directly on the groups we wanted to allow the granular permissions for.

With Entra ID, we can use Administrative Units in a similar fashion, but we’ll find out that there are lots of caveats.

Let’s explore managing groups in an administrative unit. First, we remove all of our Graph API permissions.

Then we grant the Group Administrator role to Cloud Application, but we scope it to a target administrative unit.

We connect to Graph and run get-mgcontext to verify that we have no scopes (permissions). We can’t see from Get-MGContext that we have the role assignment, but it’s there.

Note the lack of scopes (permissions)

We can verify that we don’t have permissions across the directory by attempting to add a user to a group that exists outside of the scope of our administrative unit.

Now let’s try adding a user to a group that we have scoped to an administrative unit

Great! So now we have the granular ability to update this group, and our combination of permissions and roles looks like this.

Role and permissions necessary to update a group in an administrative unit

But the model we are operating with is inherently quite restrictive. In the example we know the Object ID of the group we want to modify. But what if we don’t know what groups we have permissions to manage? We could enumerate the groups in the administrative unit.

Except, we can’t, at least not with the permissions and roles in scope.

Getting into the thick of permissions and roles

We are starting to see that to perform actions as an application, it must either have associated permissions or roles assigned that grant the necessary actions.

We add permissions for AdministrativeUnit.Read.All to our application.

And now we can enumerate the objects in our administrative unit.

But what if we want to enumerate users to determine who to place in the group? Again, it’s another permission.

And if we want a way to determine if a group already exists before creating it? Yup, another permission.

For the handful of operations here, we now have the following permission and role model.

Whether it’s a homegrown set of internal processes managing user or group lifecycles in Entra ID, or a software solution from an ISV, either deployed on-prem or consumed as a SaaS application, the permissions necessary can rapidly expand depending on the type of service being offered, especially if the software is providing broad management or tooling for Entra ID, or likely any M365 service.

Take the time to understand, and test, permissions and roles

While the landscape of permissions and roles might be something less ventured, building an understanding of how they work, their strengths, their weaknesses, and the reality of how they work within Graph and Entra ID is critical to protecting our resources and enterprises. While it may be a little work upfront, refining your applications, scripts, and processes to only use the necessary permissions can go a long way in ensuring that it’s not the next point of lateral movement or privilege escalation.

About This Posts Featured Image

The chosen photo is the work of Danielle Rice, used under the Unsplash license.

Picture of Eric Woodruff
Eric Woodruff

Leave a Reply

Your email address will not be published. Required fields are marked *

Author picture

Writing about all things identity and identity adjacent in the Microsoft ecosystem of Azure AD and Active Directory.

Read More
Mailing List

Subscribe to posts here