Secure Access To Mailboxes Via Graph


This is mainly for my own info, as a lot of this I could not find on a single website, and also found info on the now deprecated Application Access Policies and so rather than needing to hut for all this stuff all over the place…

To use Microsoft Graph to connect to Exchange Online mailboxes, and to do that securely, requires a number of steps. These steps are as follows and then the process you need is detailed below:

  1. Create a mailbox (if you don’t have that already), and for these steps this can be a shared mailbox as well as a regular mailbox, as a security principal is no longer required as we are no longer needing to use New-ApplicationAccessPolicy.
  2. Create an Application Registration in Entra ID
  3. Restrict application so it can only access the mailbox
  4. Test it all out

Creating the mailbox

There is nothing special about the Exchange Online mailbox you create for Graph access. And with “RBAC for Applications” (which replaces Application Access Policies) you can use Shared Mailboxes, Room or Resource mailboxes as well.

The mailbox does not need a licence if it is a shared mailbox. Though this means it will not support archives and is limited to 50GB of storage. If you need either of these then you need an Exchange Online Plan 2 licence assigned to the shared mailbox. If the mailbox fills up and you don’t delete content from it then use a Retention Policy to auto delete email older than x days/years from the mailbox instead of doing this programmatically.

Creating the application

Complete these steps from https://portal.azure.com/#view/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/~/RegisteredApps and create a new App Registration.

Give the application a suitable name and choose Single Tenant.

Once the application is created add the required API Permissions. The ones you need for the app are your choice, but permissions like “Application Mail.Send” and “Application Mail.ReadWrite” might be what you want. There are other permissions, but these are all “Application” permissions which means they run as the application and not the logged in user (which would be “Delegate” permissions).

Remove the User.Read delegated permission (confirm that you want to remove this even though it says you should not) and grant admin consent for all permissions.

Change to the “Branding & Properties” page and add “Internal Notes” to record the purpose of the application and who is the application sponsor (so you can tidy up apps later, or they grow like weeds). Add Owners – these people, if they have Application Administrator role can view and change the settings of this application without other admin permissions.

Finally for the application, create a new secret and communicate it securely with the owners (secrets can only be viewed once). Use a short duration for a secret. Record Application (Client) ID, Tenant ID and provide then to the app owners as well.

You also need the Object ID of the Enterprise App (not the App Registration). To get this visit App Registration > Overview > click Managed Application in Local Directory link. Copy ObjectID from here (the Enterprise App Object ID).

You will end up with something like the following; and the secret which you would store elsewhere:

  • Application Name: shared_mailbox_access
  • Application (Client) ID: d90043ed-xxxx-xxxx-xxxx-xxxxxxxxxx87
  • Enterprise App Object ID: 8de799a2-xxxx-xxxx-xxxx-xxxxxxxxxxa1
  • Tenant ID: 1c48ea50-xxxx-xxxx-xxxx-xxxxxxxxxx63
  • Client Secret: Stored encrypted elsewhere
  • Permissions: Mail.ReadWrite

Restrict mailbox access to the application

By default the Graph Exchange Online permissions (such as Mail.Read) allow access to all mailboxes in the tenant. Via Exchange Online PowerShell create a new Service Principal for the application (ClientID and Enterprise App ObjectID are needed for this). This is used to restrict the application (by ID) to a mailbox (the one created above) via the New-ManagementScope (here named after the AppID for clarity and using the Guid of the shared mailbox). It is then all tied together with the New-ManagementRoleAssignment using the App ID, the role (Application Mail.ReadWrite) and the RBAC scope created in the second PowerShell line. This is tied to the shared mailbox only in this example, other roles and targets are possible such as all the members of a distribution security group.

New-ServicePrincipal -AppID d90043ed-xxxx-xxxx-xxxx-xxxxxxxxxx87 -ObjectID 8de799a2-xxxx-xxxx-xxxx-xxxxxxxxxxa1 -DisplayName "shared_mailbox_access RBAC for Exchange Online"
Get-Mailbox name_of_shared_mailbox | FL GUID
New-ManagementScope -Name "rbac_d90043ed-xxxx-xxxx-xxxx-xxxxxxxxxx87" -RecipientRestrictionFilter "Guid -eq 'c49513eb-xxxx-xxxx-xxxx-xxxxxxxxxxd9'"
New-ManagementRoleAssignment -App d90043ed-xxxx-xxxx-xxxx-xxxxxxxxxx87 -Role "Application Mail.ReadWrite" -CustomResourceScope "rbac_d90043ed-xxxx-xxxx-xxxx-xxxxxxxxxx87"

The secrets in the earlier encrypted email and the above info should allow you to write your application and access the shared mailbox. Use Add-MailboxPermission shared_mailbox -User devUsername -AccessRights FullAccess to grant your developer access to the mailbox in Outlook as well.

Testing

To test that your scopes for RBAC are set up correctly, use Test-ServicePrincipalAuthorization and include both the mailbox that the application should have access too, and also another user and see that InScope should show “false” for the other user.

Test-ServicePrincipalAuthorization -Identity 8de799a2-xxxx-xxxx-xxxx-xxxxxxxxxxa1 -Resource mailbox@domain.com

To test all this out use the following PowerShell. This then becomes the crux of the code that you write for your actual application that accesses the mailbox as the application registration in the directory:

$ClientSecretCredential = Get-Credential -Credential "d90043ed-xxxx-xxxx-xxxx-xxxxxxxxxx87"
Connect-MgGraph -TenantId 1c48ea50-xxxx-xxxx-xxxx-xxxxxxxxxx63 -ClientSecretCredential $ClientSecretCredential
$messages = Invoke-mgGraphRequest -Method GET 'https://graph.microsoft.com/v1.0/users/mailbox@domain.com/messages'
$messages.value[0].subject

Posted

in

,

by

Comments

Leave a Reply

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

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