Extending RBAC for Applications to Managed Identities

RBAC for Applications is a preview mechanism to control the access Azure AD apps have to Exchange Online mailboxes. V3.0 of the Exchange Online management PowerShell module supports authentication using Azure Automation managed identities. I like using managed identities to run scheduled Exchange Online scripts, and it seems natural to use RBAC for Applications to ensure that the Azure AD apps used for managed identities should be properly authorized to access mailboxes.

As an example of using RBAC for Applications to control an Azure AD app that uses managed identity to run scripts, I decided to adapt the room mailbox usage report script. The script uses the Calendars.Read Graph permission to extract calendar information. This is one of the permissions supported by RBAC for Applications, so it seemed like a good and practical choice to demonstrate the principal. Adapting a script that runs interactively for Azure Automation isn’t difficult, but it takes some care (here are some hints).

Authentication with Azure is one significant difference. Here’s how the adapted code obtains an access token for the managed identity and uses it to connect to Exchange Online:

$ResourceURL = "https://graph.microsoft.com/" 
$Response = [System.Text.Encoding]::Default.GetString((Invoke-WebRequest -UseBasicParsing -Uri "$($env:IDENTITY_ENDPOINT)?Resource=$ResourceURL" -Method 'GET' -Headers @{'X-IDENTITY-HEADER' = "$env:IDENTITY_HEADER"; 'Metadata' = 'True'}).RawContentStream.ToArray()) | ConvertFrom-Json 
$AccessToken = $Response.access_token 

Connect-ExchangeOnline -ManagedIdentity -Organization office365itpros.onmicrosoft.com

Preparing for Automation

Managed identities run in the context of an Azure Automation account. All my existing Azure Automation accounts have assigned Graph permissions that are needed to perform different operations. The point about RBAC for Applications is that Exchange Online evaluates if an app should receive permission to access mailboxes based on a filter (the management scope). To avoid any issues with permissions assigned to other accounts, I decided to start with a blank slate and created a new Azure Automation account called RBACforApps.

In most cases, scripts that interact with Exchange Online use cmdlets in the Exchange Online management module. That isn’t the case here because the script I’ve chosen to use processes data with a mixture of standard PowerShell cmdlets and Graph API requests. However, a script that involves Exchange data that doesn’t run some Exchange Online cmdlets is a rarity, so I include details of how to configure the Azure Automation account so that it can run Exchange Online cmdlets here.

First, you must import the Exchange Online management PowerShell module into the automation account. If you don’t import the module, the account can’t run any Exchange Online cmdlets. If you plan to use the account to run cmdlets from other modules, you must import those modules too.

Next, if the automation account needs to run Exchange Online cmdlets, you must assign the permission to manage Exchange as an administrator to the automation account. In effect, you allow the account to run the cmdlets as if an administrator logged into an interactive PowerShell session. To assign the Manage Exchange as Application role to the Azure Automation account, run this PowerShell code, which uses cmdlets from the Microsoft Graph PowerShell SDK:

Connect-MgGraph

$ManagedIdentityApp = Get-MgServicePrincipal -Filter "displayName eq 'RBACforApps'"
$ExoApp = Get-MgServicePrincipal -Filter "AppId eq '00000002-0000-0ff1-ce00-000000000000'"
$AppPermission = $ExoApp.AppRoles | Where-Object {$_.DisplayName -eq "Manage Exchange As Application"}
$AppRoleAssignment = @{
"PrincipalId" = $ManagedIdentityApp.Id
"ResourceId" = $ExoApp.Id
"AppRoleId" = $AppPermission.Id
}
New-MgServicePrincipalAppRoleAssignment -ServicePrincipalId $ManagedIdentityApp.Id -BodyParameter $AppRoleAssignment

Finally, before an Azure Automation account can run Exchange Online cmdlets, you must assign the Exchange administrator role to the app used by the Azure Automation account. For a checklist of items to follow to ensure that an app can run Exchange Online cmdlets, see this article.

Run a Baseline Test

To establish that the Azure Automation account can sign into Exchange Online with a managed identity, create a test runbook that runs an Exchange Online cmdlet. A simple Get-EXOMailbox command to report details of some mailbox is sufficient to validate that everything works.

Before we introduce RBAC for Applications into the equation, we should run a baseline test using normal Graph permissions. To do this, we assign the Graph permissions required by the API requests issued in the script (Place.Read.All and Calendars.Read) to the RBACforApps app. Then add the code from the room mailbox usage script and make sure that it runs as normal.

Prepare to Apply RBAC for Applications Restrictions

It’s easy to find room mailboxes by running the Get-EXOMailbox cmdlet and passing the RoomMailbox value in the RecipientTypeDetails parameter. For example:

Get-ExoMailbox -RecipientTypeDetails RoomMailbox | Set-Mailbox -CustomAttribute1 'PublicRoom'

If necessary, later, we can remove access to the mailbox by updating CustomAttribute1 to store another value. The test of the script proved that we have a working code. Now we remove the Calendars.Read permission from the RBACforApps app. This ensures that the managed identity will only be able to access the room mailboxes if it satisfies the requirements of RBAC for Applications.

[Array]$SPPermissions = Get-MgServicePrincipalAppRoleAssignment -ServicePrincipalId $ManagedIdentityApp.Id
$GraphApp = Get-MgServicePrincipal -Filter "AppId eq '00000003-0000-0000-c000-000000000000'" # Microsoft Graph
$Role = $GraphApp.AppRoles | Where-Object {$_.Value -eq "Calendars.Read"}
$Assignment = $SpPermissions | Where-Object {$_.AppRoleId -eq $Role.Id}
Remove-MgServicePrincipalAppRoleAssignment -AppRoleAssignmentId $Assignment.Id -ServicePrincipalId $ManagedIdentityApp.Id

Now we create the foundation for RBAC for Applications control over access to the room mailbox calendars. This is done by creating:

  • A service principal object in Exchange Online that points to the service principal of the enterprise app used by the managed identity.
  • A management scope that finds the room mailboxes.
  • A management role assignment to link the Exchange Online service principal object, management scope, and Application Calendars.Read permission.

The result is that when Exchange Online sees an attempt by the app used by the managed identity to access calendars in certain mailboxes, it checks if the calendars belong to the mailboxes defined in the management scope. If this is true, Exchange Online allows access. Here are the commands that I used:

# Grab the Application and Service Principal Identifiers for the app used by the
# managed identity
$SP = Get-MgServicePrincipal -All
$ServicePrincipalId = $SP | Where-Object {$_.displayName -eq "RBACforApps"} | Select-Object -ExpandProperty Id
$AppId = $SP | Where-Object {$_.displayName -eq "RBACforApps"} | Select-Object -ExpandProperty AppId

# Define the service principal object in Exchange Online
New-ServicePrincipal -AppId $AppId -ServiceId $ServicePrincipalId -DisplayName 'RBACforApps'

DisplayName                              ServiceId                                 AppId
-----------                              ---------                                 -----
RBACforApps                              2a492904-9d96-4ece-97e4-c55798a873f5      415e4ba8-635f-4689-b069-22dea1fcfdb3

# Define the management scope for room mailboxes
New-ManagementScope -Name "Room Mailboxes" -RecipientRestrictionFilter "CustomAttribute1 -eq 'PublicRoom'"

Name           ScopeRestrictionType Exclusive RecipientRoot RecipientFilter                   ServerFilter
----           -------------------- --------- ------------- ---------------                   ------------
Room Mailboxes RecipientScope       False                   CustomAttribute1 -eq 'PublicRoom'

# Create the management role assignment to link everything together
New-ManagementRoleAssignment -App $AppId -Role "Application Calendars.Read" -CustomResourceScope "Room Mailboxes"

Testing Selective Access

Because we’ve removed the Calendars.Read permission from its app, the Azure Automation runbook now depends on RBAC for Applications to gain access to room mailbox calendars. Check that everything still works by executing the runbook through the test pane in the Azure admin center. Figure 1 shows the results. All is well, and we note that the Board Conference Room is the most heavily used.

The Azure Automation runbook processes room mailbox calendars
Figure 1: The Azure Automation runbook processes room mailbox calendars

The next step tests selective access. Remove the app’s access to the Board Conference Room mailbox by updating the custom attribute.

Set-Mailbox -Identity "Board Conference Room" -CustomAttribute1 $Null

Proceed to execute the runbook again. This time, RBAC for Applications will not grant access to the Board Conference Room mailbox because it doesn’t come within the management scope defined for the role assignment, so the room doesn’t feature in the usage statistics. Remember that Exchange Online caches management scopes for better performance, so wait 30 minutes before testing with the updated scope. Figure 2 shows the outcome – as expected, there’s no sign of the Board conference room!

RBAC for Applications stops access to a room mailbox
Figure 2: RBAC for Applications stops access to a room mailbox

You can download the runbook code that I used from GitHub.

Control is Important

RBAC for Applications enables selective access for Azure AD apps to Exchange Online mailboxes. Many scripts that process large quantities of mailboxes run as background or scheduled jobs. It’s great that RBAC for Applications works with scripts executed by Azure Automation with managed identities. The ability to exert control over user data is always appreciated. It would just be nice if RBAC for Applications covered SharePoint Online, Teams, and other potential repositories holding confidential data.

About the Author

Tony Redmond

Tony Redmond has written thousands of articles about Microsoft technology since 1996. He is the lead author for the Office 365 for IT Pros eBook, the only book covering Office 365 that is updated monthly to keep pace with change in the cloud. Apart from contributing to Practical365.com, Tony also writes at Office365itpros.com to support the development of the eBook. He has been a Microsoft MVP since 2004.

Leave a Reply