ExO RBAC improvements #3: Limiting access in CBA scenarios

Certificate-based authentication (CBA) for Exchange Online PowerShell was introduced two years ago as a method to automate the execution of scripts and tasks in a modern authentication world. In a nutshell, CBA allows you to leverage the OAuth client credentials flow to obtain an access token, which you can then use to connect to Exchange PowerShell. The flow is intended to be used by background applications, so it runs in the context of a service principal, instead of a user, and is non-interactive. The actual authentication happens either via a client secret (very long password string) or preferably, a certificate.

While support for CBA addressed some of the grievances of switching to Modern authentication, the client credentials flow and the application permissions model by extension creates a whole new set of problems. Similar to most of the Graph API endpoints, using application permissions with Exchange Online granted unrestricted access to the entire tenant, effectively bypassing Exchange’s robust RBAC model. Some measure of control could be exercised by the Azure AD admin role assigned to the application (service principal), but it was nowhere near as granular as what Exchange’s built-in controls offered. In particular, there was no way to apply a management scope in order to limit access to just a subset of the objects within your tenant.

Until now. With the recently introduced improvements that extend Exchange’s RBAC model to support service principal objects, it is now possible to assign specific roles to SP objects, add them to Exchange Role Groups or create scoped management assignments. Let’s examine these scenarios!

First and foremost, you will need a service principal object within ExODS. As covered in previous articles, for the time being you will need to manually create the link between an existing service principal object within Azure AD and its representation within ExODS, by means of the New-ServicePrincipal cmdlet. As a refresher, here’s an example on how to do that:

New-ServicePrincipal -AppId xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx -ServiceId xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

where the required AppId (ClientID) and ServiceID (objectID) values can be obtained from either the Azure AD blade > App registrations > Overview page, or via PowerShell (Get-MsolServicePrincipalGet-AzureADServicePrincipal or Get-MgServicePrincipal cmdlet, depending on which module you prefer). Do note that the New-ServicePrincipal cmdlet does NOT validate the values, so make sure you double- and triple-check them.

Once you have a representation of the service principal object, you can use it with the various controls of Exchange’s RBAC model. As first scenario, let’s see how we can add a service principal as a member of a given Role Group. This is a great scenario to address, as Role Groups are far more granular compared to the Azure AD roles we could assign until now. And since you can create your own Role Groups, with even more granular management role assignments therein, you have a lot of flexibility.

Take for example a custom Role Group I’ve created, with the lovely name of “test”. A single Exchange management role is added to the Role Group, allowing any members to execute any of the cmdlets contained within the built-in Mail Recipients role. The service principal corresponding to the application we are using to enable CBA for Exchange Online PowerShell is then added as member of the newly created role group. Here are the details:

Get-RoleGroup Test

Name AssignedRoles RoleAssignments ManagedBy
---- ------------- --------------- ---------
test {Mail Recipients} {Mail Recipients-test} {Organization Management, vasil}

Get-RoleGroup Test | select -ExpandProperty Members
2a63aee1-db17-489d-a8ab-d40971066292

In fact, you can also use the Exchange Admin Center UI to perform most of the tasks described above. Creating a new Role Group and adding management Roles is fully supported even in the new EAC, but adding service principal objects as members is not, at least for now. Once the new improvements mature to GA, we will hopefully get proper UI support. Still, it might be easier for some people to use the UI approach even today.

With the setup described above completed, you can now connect to Exchange Online PowerShell using the service principal and examine the effect of the newly configured RBAC restrictions. Instead of the full set of 800+ cmdlets you get with the Exchange administrator Azure AD role assigned, you should see a lot smaller list now. Do remember to remove any unwanted Azure AD roles beforehand, the Exchange RBAC controls do not overwrite assignments made on the Azure AD layer!

But wait! It gets even better – we can now also leverage management scopes to limit the set of objects against which the service principal will get the assigned permissions! As detailed in the previous article, you can either use the good old RecipientFilter-based management scopes or leverage the newly introduced –RecipientAdministrativeUnitScope parameter to scope access based on membership of an Azure AD administrative unit. Either way, the result is further limiting access even in CBA scenarios!

As an example, let’s create a custom management scope, and for the sake of example only include a handful of mailbox objects. And you guessed it – we call it “test” 🙂

Get-ManagementScope test

Name ScopeRestrictionType Exclusive RecipientRoot RecipientFilter
---- -------------------- --------- ------------- ---------------
test RecipientScope False ((UserPrincipalName -eq 'vasil@michev.info') -or (UserPrincipalName -eq 'shared@michev.info'))

Nothing out of the ordinary so far, just a new scope that will only allow access to two mailboxes. Let’s see what happens if we then replace the unscoped management role assignment for the Mail Recipients role we have included in our newly created “test” Role Group with one scoped to this new management scope. Here are the details of said scoped management role assignment (using “test” for the name of every object can be confusing, go figure!):

Get-ManagementRoleAssignment "Mail Recipients-test" | select Name,Role,RoleAssignee????,RecipientWriteScope,CustomRecipientWriteScope

Name : Mail Recipients-test
Role : Mail Recipients
RoleAssigneeType : RoleGroup
RoleAssigneeName : test
RecipientWriteScope : CustomRecipientScope
CustomRecipientWriteScope : test

Until now, we were able to run any of the 143 cmdlets included in the Mail Recipients role against any object within the directory. With the new scope in effect, the list of cmdlets should remain the same, however their execution can only happen against the two mailboxes included in the scope. Let’s test this! The first cmdlet on the screenshot below is executed against a mailbox within the scope, the second one against a mailbox not in the scope:

Beautiful! We now know our new management scope is in effect and it helped us restrict access in CBA scenarios even further! The last scenario enabled by the recent RBAC model improvements is creating direct management role assignments for service principal, with or without a management scope. As we covered this scenario in our previous articles, and it’s technically only supported for just a handful of “application” roles, we will skip covering it here.

Before closing the article, it’s important to highlight one limitation. None of the methods outlined above will work for the old Remote PowerShell connectivity method, i.e. when you are connecting via the -UseRPSSession switch. In other words, you need to be using the latest version of the Exchange Online PowerShell module, which proxies all cmdlets against the REST endpoints. Refer to the official documentation for more information on this!

In summary, we covered yet another set of scenarios made possible thanks to the recent improvements of the Exchange Online RBAC model. Leveraging said improvements, it is now possible to create granular management role assignments for service principal objects that are used in automation scenarios via Certificate-based authentication. The robust controls allow us to limit both the set of permissions (the list of cmdlets) the service principal will have access to and the set of objects (scope) it will be able to run it against. This is a great improvement, especially when compared to the “unrestricted access” behavior we see with other APIs that leverage the application permissions model. Kudos to the Exchange team!

This entry was posted in Azure AD, Exchange Online, Microsoft 365, Office 365, PowerShell. Bookmark the permalink.

Leave a Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.