Exchange Online Custom RBAC Role for AWS
Hi All,
I’ve had an interesting Use Case some Weeks ago.
The collegues from the AWS Cloud Team wanted to create a Mailenabled Security List for each Application they create. So they can inform the right People and i guess also assign permissions to these People.
I expected, that this will be an easy task. Just a few Microsoft Graph Commands to create a Group and add Members. But i was very wrong. As soon as a Group has an Emailaddress, the Object needs to be managed via “ExchangeOnlineManagement” PowerShell.
Security groups are for controlling user access to resources. By checking whether a user is a member of a security group, your app can make authorization decisions when that user is trying to access some secure resources in your app. Security groups can have users, other security groups, devices, and service principals as members.
Mail-enabled security groups are used in the same way as security groups, but can be used to send emails to group members. Mail-enabled security groups can’t be created or updated through the API; instead, they’re read-only. Learn more in the Manage mail-enabled security groups Exchange article.
Solution
We came up with the following Solution:
- Create an Entra ID App
- Assign Exchange.ManageAsApp
- Restrict the App with a specific Recipient Filter (Group needs to start with AAD-AWS)
- Restrict the APP with a customized RBAC Role
- Create/Modify/Delete Distribution Group
- Add/Remove Group Members
This Blog Article is based on:
Create EntraID Application
First we need to create the Entra ID Application with the Microsoft Graph PowerShell Modules
###############################################################################
# Connect-MgGraph
# Requires EntraID "Application Adminstrator" or "Global Administrator" Role
###############################################################################
Connect-MgGraph -Scopes "Application.Read.All","Application.ReadWrite.All","User.Read.All"
###############################################################################
# Create EntraID Application
###############################################################################
$AppName = "EXO-DistGroup-RBAC"
$App = New-MgApplication -DisplayName $AppName
$APPObjectID = $App.Id
$AppID = $App.AppId
Prepare the Self-Signed Certificate for Certificate Based Authentication (CBA) with Exchange Online
###############################################################################
# Create a Self Signed Certificate
###############################################################################
$Subject = "EXO-DistGroup-RBAC"
$NotAfter = (Get-Date).AddMonths(+24)
$Cert = New-SelfSignedCertificate -Subject $Subject -CertStoreLocation "Cert:\CurrentUser\My" -KeySpec Signature -NotAfter $Notafter -KeyExportPolicy Exportable
$ThumbPrint = $Cert.ThumbPrint
Add the Certificate to the Entra ID Application
###############################################################################
# Add Certificate to Entra ID Application
###############################################################################
# Get Certificate with Thumbprint from UserCertStore
$Cert = Get-ChildItem -Path cert:\CurrentUser\my\$ThumbPrint
# Create a keyCredential (Certificate) for App
$keyCreds = @{
Type = "AsymmetricX509Cert";
Usage = "Verify";
key = $cert.RawData
}
Update-MgApplication -ApplicationId $APPObjectID -KeyCredentials $keyCreds
Add the Exchange.ManageAsApp Permission
###############################################################################
# Add Entra ID Application Permissions
###############################################################################
$params = @{
RequiredResourceAccess = @(
@{
ResourceAppId = "00000002-0000-0ff1-ce00-000000000000"
ResourceAccess = @(
@{
Id = "dc50a0fb-09a3-484d-be87-e023b12c6440"
Type = "Role"
}
)
}
)
}
Update-MgApplication -ApplicationId $APPObjectID -BodyParameter $params
Grant Admin Consent with Browser Sign-In
###############################################################################
# Grant Admin Consent - Opens URL in Browser
###############################################################################
#https://login.microsoftonline.com/{tenant-id}/adminconsent?client_id={client-id}
$TenantID = $App.PublisherDomain
$URL = "https://login.microsoftonline.com/$TenantID/adminconsent?client_id=$AppID"
Start-Process $URL
It will open a Browser Window where you need to Sign-In
And Grant the Permissions
Application
This is the resulting Entra ID Application
Create Exchange RBAC Role and Management Scope
Now we need to Login to Exchange with the Exchange Administrator Role to prepare the Exchange Online RBAC Role and Management Scope.
###############################################################################
# Connect-ExchangeOnline
###############################################################################
Connect-ExchangeOnline
First we create the Management Scope. Only Objects with the DisplayName that Starts with “AAD-AWS” can be managed.
###############################################################################
# ManagementScope
###############################################################################
$RecipientFilter = "(DisplayName -like 'AAD-AWS*')"
Get-Recipient -RecipientPreviewFilter $RecipientFilter
New-ManagementScope -Name "AAD-AWS" -RecipientRestrictionFilter $RecipientFilter
We need to figure out the best built-in role to use as a parent for our new custom RBAC Role.
You will need both ManagementRoles “Security Group Creation and Membership” and “Distribution Groups” because of the Confirm Parameter.
###############################################################################
# Management Role
###############################################################################
Get-ManagementRole | where {$_.Name -like "*group*"}
Get-ManagementRoleEntry -Identity "Security Group Creation and Membership\*"
Get-ManagementRoleEntry -Identity "Distribution Groups\*"
Let’s create the RBAC Role with the Parent.
###############################################################################
# New-ManagementRole
###############################################################################
$ManagementRoleName01 = "CUSTOM-AWS-SecurityGroup"
New-ManagementRole -Parent "Security Group Creation and Membership" -Name $ManagementRoleName01
List the Management Role Entrys
###############################################################################
# Get-ManagementRoleEntry
###############################################################################
Get-ManagementRoleEntry -Identity "$ManagementRoleName01\*"
Remove unneeded cmdlets from our new RBAC Role
###############################################################################
# Remove unneeded commands
###############################################################################
Remove-ManagementRoleEntry -Identity "$ManagementRoleName01\Get-EligibleDistributionGroupForMigration" -Confirm:$false
Remove-ManagementRoleEntry -Identity "$ManagementRoleName01\Get-OrganizationalUnit" -Confirm:$false
Remove-ManagementRoleEntry -Identity "$ManagementRoleName01\Get-UnifiedAuditSetting" -Confirm:$false
Remove-ManagementRoleEntry -Identity "$ManagementRoleName01\Set-Group" -Confirm:$false
Remove-ManagementRoleEntry -Identity "$ManagementRoleName01\Set-UnifiedAuditSetting" -Confirm:$false
Remove-ManagementRoleEntry -Identity "$ManagementRoleName01\Write-AdminAuditLog" -Confirm:$false
Remove-ManagementRoleEntry -Identity "$ManagementRoleName01\Start-AuditAssistant" -Confirm:$false
Remove-ManagementRoleEntry -Identity "$ManagementRoleName01\Get-Mailbox" -Confirm:$false
Remove-ManagementRoleEntry -Identity "$ManagementRoleName01\Get-SweepRule" -Confirm:$false
Remove-ManagementRoleEntry -Identity "$ManagementRoleName01\Get-Recipient" -Confirm:$false
Remove-ManagementRoleEntry -Identity "$ManagementRoleName01\Get-DynamicDistributionGroupMember" -Confirm:$false
Remove-ManagementRoleEntry -Identity "$ManagementRoleName01\Test-DatabaseEvent" -Confirm:$false
Remove-ManagementRoleEntry -Identity "$ManagementRoleName01\Get-ScopeEntities" -Confirm:$false
Remove-ManagementRoleEntry -Identity "$ManagementRoleName01\Get-ScopeAdmins" -Confirm:$false
Remove-ManagementRoleEntry -Identity "$ManagementRoleName01\Test-MailboxAssistant" -Confirm:$false
Remove-ManagementRoleEntry -Identity "$ManagementRoleName01\Get-BookingMailbox" -Confirm:$false
Check the Resulting RBAC Role
###############################################################################
# Check-ManagementRoleEntry after removal
###############################################################################
Get-ManagementRoleEntry -Identity "$ManagementRoleName01\*"
###############################################################################
# New-ManagementRole
###############################################################################
$ManagementRoleName02 = "CUSTOM-AWS-DistributionGroup"
New-ManagementRole -Parent "Distribution Groups" -Name $ManagementRoleName02
###############################################################################
# Get-ManagementRoleEntry
###############################################################################
Get-ManagementRoleEntry -Identity "$ManagementRoleName02\*"
###############################################################################
# Remove unneeded commands
###############################################################################
Remove-ManagementRoleEntry -Identity "$ManagementRoleName02\Get-EligibleDistributionGroupForMigration" -Confirm:$false
Remove-ManagementRoleEntry -Identity "$ManagementRoleName02\Get-AcceptedDomain" -Confirm:$false
Remove-ManagementRoleEntry -Identity "$ManagementRoleName02\Get-BookingMailbox" -Confirm:$false
Remove-ManagementRoleEntry -Identity "$ManagementRoleName02\Test-MailboxAssistant" -Confirm:$false
Remove-ManagementRoleEntry -Identity "$ManagementRoleName02\Get-ScopeAdmins" -Confirm:$false
Remove-ManagementRoleEntry -Identity "$ManagementRoleName02\Get-ScopeEntities" -Confirm:$false
Remove-ManagementRoleEntry -Identity "$ManagementRoleName02\Set-Group" -Confirm:$false
Remove-ManagementRoleEntry -Identity "$ManagementRoleName02\Set-DistributionGroup" -Confirm:$false
Remove-ManagementRoleEntry -Identity "$ManagementRoleName02\New-DistributionGroup" -Confirm:$false
Remove-ManagementRoleEntry -Identity "$ManagementRoleName02\Test-DatabaseEvent" -Confirm:$false
Remove-ManagementRoleEntry -Identity "$ManagementRoleName02\Set-DynamicDistributionGroup" -Confirm:$false
Remove-ManagementRoleEntry -Identity "$ManagementRoleName02\Get-DynamicDistributionGroupMember" -Confirm:$false
Remove-ManagementRoleEntry -Identity "$ManagementRoleName02\New-DynamicDistributionGroup" -Confirm:$false
Remove-ManagementRoleEntry -Identity "$ManagementRoleName02\Get-DistributionGroup" -Confirm:$false
Remove-ManagementRoleEntry -Identity "$ManagementRoleName02\Write-AdminAuditLog" -Confirm:$false
Remove-ManagementRoleEntry -Identity "$ManagementRoleName02\Stop-ExoJob" -Confirm:$false
Remove-ManagementRoleEntry -Identity "$ManagementRoleName02\Start-AuditAssistant" -Confirm:$false
Remove-ManagementRoleEntry -Identity "$ManagementRoleName02\Set-UnifiedAuditSetting" -Confirm:$false
Remove-ManagementRoleEntry -Identity "$ManagementRoleName02\Set-OrganizationConfig" -Confirm:$false
Remove-ManagementRoleEntry -Identity "$ManagementRoleName02\Remove-DynamicDistributionGroup" -Confirm:$false
Remove-ManagementRoleEntry -Identity "$ManagementRoleName02\Remove-DistributionGroup" -Confirm:$false
Remove-ManagementRoleEntry -Identity "$ManagementRoleName02\Remove-ExoJob" -Confirm:$false
Remove-ManagementRoleEntry -Identity "$ManagementRoleName02\Receive-ExoJob" -Confirm:$false
Remove-ManagementRoleEntry -Identity "$ManagementRoleName02\Get-User" -Confirm:$false
Remove-ManagementRoleEntry -Identity "$ManagementRoleName02\Get-UnifiedAuditSetting" -Confirm:$false
Remove-ManagementRoleEntry -Identity "$ManagementRoleName02\Get-Recipient" -Confirm:$false
Remove-ManagementRoleEntry -Identity "$ManagementRoleName02\Get-OrganizationalUnit" -Confirm:$false
Remove-ManagementRoleEntry -Identity "$ManagementRoleName02\Get-MailboxPreferredLocation" -Confirm:$false
Remove-ManagementRoleEntry -Identity "$ManagementRoleName02\Get-Mailbox" -Confirm:$false
Remove-ManagementRoleEntry -Identity "$ManagementRoleName02\Get-MailUser" -Confirm:$false
Remove-ManagementRoleEntry -Identity "$ManagementRoleName02\Get-Group" -Confirm:$false
Remove-ManagementRoleEntry -Identity "$ManagementRoleName02\Get-ExoJob" -Confirm:$false
Remove-ManagementRoleEntry -Identity "$ManagementRoleName02\Get-DynamicDistributionGroup" -Confirm:$false
Remove-ManagementRoleEntry -Identity "$ManagementRoleName02\Get-DistributionGroupMember" -Confirm:$false
###############################################################################
# Check-ManagementRoleEntry after removal
###############################################################################
Get-ManagementRoleEntry -Identity "$ManagementRoleName02\*"
Finally we need to get the Details for creating the Service Principal in Exchange Online
###############################################################################
# Get AzureAD Application with Microsoft.Graph PowerShell
###############################################################################
# Connect-MgGraph -Scopes 'Application.Read.All'
$Filter = "DisplayName eq '" + $AppName + "'"
$ServicePrincipalDetails = Get-MgServicePrincipal -Filter $Filter
$ServicePrincipalDetails
$ServicePrincipalID = $ServicePrincipalDetails.ID
Create the Service Principal in Exchange Online.
###############################################################################
# Create Exchange Service Principal
###############################################################################
New-ServicePrincipal -AppId $AppId -ObjectId $ServicePrincipalID -DisplayName "EXO Serviceprincipal $AppName"
Get-ServicePrincipal | where {$_.AppId -eq "$AppID"}
Create the RoleGroup and assingn the new RBAC Role with the Management Scope to the Service Principal
###############################################################################
# New-RoleGroup
###############################################################################
$SP = Get-ServicePrincipal | where {$_.AppId -eq $AppID}
$ServiceId = $SP.ServiceId
New-RoleGroup -Name 'Icewolf-AWS-Group' -Roles $ManagementRoleName01,$ManagementRoleName02 -CustomRecipientWriteScope "AAD-AWS" -Description "Custom Role for AWS Mailenabled Security Group"
Add-RoleGroupMember -Identity "Icewolf-AWS-Group" -Member $ServicePrincipalID
Testing the Solution
Time to put our Solution at a Test
###############################################################################
# Connect-ExchangeOnline
###############################################################################
$AppID = "c292695d-13c4-4cb1-9378-66b9d91e73d2"
$CertificateThumbprint = "8C4BF617BF6633170F0F47C9AC16B8E8835F6E25"
$TenantID = "icewolfch.onmicrosoft.com"
Connect-ExchangeOnline -AppId $AppID -CertificateThumbprint $CertificateThumbprint -Organization $TenantID -ShowBanner:$false
Get-Module
Get-Command -Module tmpEXO_c2fvmgy4.frb
Now let’s try to create Mail Enabled Security Groups that matches / not matches the ManagementScope
###############################################################################
# Testing Group Manipulation
###############################################################################
#Group that matches ManagementScope
New-DistributionGroup -Name "AAD-AWS-DEMO" -Type Security
#Group that does not match the ManagementScope
New-DistributionGroup -Name "AAD-XXX-DEMO" -Type Security
Now let’s add and remove Distribution Group Members
# Add-/Get-/Remove-DistributionGroupMember
Add-DistributionGroupMember -Identity "AAD-AWS-DEMO" -Member m.muster@icewolf.ch -BypassSecurityGroupManagerCheck
Get-DistributionGroupMember -Identity "AAD-AWS-DEMO"
Remove-DistributionGroupMember -Identity "AAD-AWS-DEMO" -Member m.muster@icewolf.ch -BypassSecurityGroupManagerCheck -Confirm:$false
Get-DistributionGroupMember -Identity "AAD-AWS-DEMO"
# Remove Distribution Group
Remove-DistributionGroup -Identity "AAD-AWS-DEMO" -BypassSecurityGroupManagerCheck -Confirm:$false
# Disconnect from Exchange Online
Disconnect-ExchangeOnline -Confirm:$false
Summary
I think it’s a well designed Solution that gives the AWS Cloud Team exactly the right permissions to do the Job they need to. I guess that also others from the Community can benefit from this Solution. This Article has all the Scripts needed to automate the entire Process.
Regards
Andres Bohren