• Microsoft 365
  • Limiter l’accès aux boîtes mails – Exchange Online

    J’ai récemment utilisé New-ManagementScope dans Exchange Online pour limiter les boîtes mail accessibles par une App registration. Le besoin était simple : permettre à une application de consulter certaines boîtes, sans lui ouvrir l’ensemble du tenant.

    C’est un cas que l’on peut rencontrer avec un outil de ticketing, un traitement automatique de messages ou une application métier. Quelques boîtes sont nécessaires au fonctionnement de l’outil. Les autres n’ont aucune raison d’être accessibles.

    L’exemple couvre une application qui lit la messagerie via Microsoft Graph, en mode application. Nous allons construire son périmètre avec RBAC for Applications, lui associer un droit de lecture et vérifier le résultat. Les noms et adresses utilisés ci-dessous sont des exemples à remplacer.

    L’objectif

    Autoriser la lecture des boîtes support@contoso.com et factures@contoso.com, puis vérifier que direction@contoso.com reste inaccessible à cette application.

    Pourquoi une permission Mail.Read peut-elle être trop large ?

    Dans Microsoft Graph, la permission Application Mail.Read permet de lire les messages sans utilisateur connecté. Accordée à l’échelle du tenant, elle couvre les boîtes de l’organisation. Ce n’est pas la même chose qu’une permission Delegated, utilisée au nom d’un utilisateur.

    Si votre application n’a besoin que de deux boîtes, ce droit global dépasse donc le besoin. Et limiter la liste des adresses dans son code ne suffit pas : cette liste peut être modifiée alors que l’autorisation, elle, reste large.

     

    Le scope, le rôle et l’application : qui fait quoi ?

    Élément Utilité dans notre configuration
    Service principal Représente l’application du tenant. Exchange doit disposer d’une référence vers ce service principal Entra.
    Management Scope Sélectionne les boîtes concernées au moyen d’un filtre Exchange. Il ne donne aucun accès à lui seul.
    Attribution de rôle Associe l’application à un droit et à notre scope : ici, Application Mail.Read.

    C’est l’association de ces trois éléments qui nous intéresse. New-ManagementScope prépare le périmètre ; New-ManagementRoleAssignment l’utilise pour l’attribution de permission.

    ⚠️ Les autorisations peuvent se cumuler

    Un rôle RBAC limité ne neutralise pas une permission globale déjà consentie dans Entra. Si Mail.Read y reste accordée sans restriction, l’application conserve cet accès. Nous traiterons ce point avant les tests réels.

    Avant de commencer

    • Une application enregistrée dans Entra, avec son Application (client) ID et l’Object ID de son service principal.
    • Deux boîtes Exchange Online à autoriser et une boîte existante à utiliser comme contrôle hors scope.
    • Un compte disposant du rôle Entra Exchange Administrator et des droits de délégation Exchange appropriés, fournis par Organization Management ou une délégation équivalente.
    • Pour révoquer les consentements existants, les droits Entra adaptés, par exemple Cloud Application Administrator selon l’opération.
    • Le module ExchangeOnlineManagement. Pour le test Graph proposé plus bas : PowerShell 7, Microsoft.Graph.Authentication et un secret client valide de l’application.

    Les commandes de configuration sont à exécuter avec le compte administrateur. Le test Graph utilisera ensuite l’identité de l’application. Gardez la même session pour conserver les variables définies au fil des étapes.

    1. Se connecter à Exchange Online

    # Installation si le module n'est pas encore présent
    Install-Module ExchangeOnlineManagement -Scope CurrentUser
    
    Import-Module ExchangeOnlineManagement
    Connect-ExchangeOnline -UserPrincipalName "admin@contoso.com"

    Remplacez le compte d’exemple par votre compte d’administration et effectuez l’authentification demandée.

    2. Référencer l’application dans Exchange

    Dans le centre d’administration Entra, ouvrez Entra ID > Enterprise apps > All applications, sélectionnez l’application puis consultez Overview. Relevez son Application ID et son Object ID.

    Attention à l’Object ID

    Utilisez celui de l’Enterprise application. L’Object ID affiché dans App registrations désigne un autre objet et ne convient pas pour ce paramètre.

    $AppId = "<APPLICATION-CLIENT-ID>"
    $ServicePrincipalObjectId = "<OBJECT-ID-ENTERPRISE-APPLICATION>"
    $ScopeName = "Scope-App-LectureMail"
    $AssignmentName = "App-LectureMail-MailRead"
    
    # Vérifier d'abord si la référence Exchange existe déjà
    Get-ServicePrincipal |
        Where-Object { $_.AppId -eq $AppId } |
        Format-List DisplayName, AppId, ObjectId

    Si aucune référence n’est retournée, créez-la :

    New-ServicePrincipal -AppId $AppId `
        -ObjectId $ServicePrincipalObjectId `
        -DisplayName "App-LectureMail"

    Si elle existe déjà, réutilisez-la. Cette commande ne crée pas une deuxième App registration : elle référence l’identité existante dans Exchange.

    3. Créer le périmètre des boîtes autorisées

    Pour cet exemple, je sélectionne directement les boîtes par leurs adresses avec EmailAddresses. Ce champ contient l’adresse principale et les alias. Microsoft recommande de l’utiliser à la place de PrimarySmtpAddress pour ce type de filtre.

    $RecipientFilter = "(RecipientTypeDetails -eq 'UserMailbox' -or RecipientTypeDetails -eq 'SharedMailbox') -and (EmailAddresses -eq 'smtp:support@contoso.com' -or EmailAddresses -eq 'smtp:factures@contoso.com')"
    
    # Prévisualiser la sélection avant de créer le scope
    Get-Recipient -Filter $RecipientFilter -ResultSize Unlimited |
        Format-Table DisplayName, PrimarySmtpAddress, RecipientTypeDetails
    
    # À exécuter après avoir vérifié les boîtes retournées
    New-ManagementScope -Name $ScopeName `
        -RecipientRestrictionFilter $RecipientFilter

    Le filtre retient des boîtes utilisateur ou partagées correspondant à l’une des deux adresses. Vérifiez que la prévisualisation retourne bien les deux boîtes attendues avant de poursuivre.

    On sélectionne une boîte entière

    Une adresse ou un alias sert ici à identifier la boîte. Ce filtre ne limite pas la lecture aux seuls messages reçus sur cette adresse : le droit portera sur les messages de la boîte sélectionnée.

    4. Associer le droit de lecture au scope

    Nous pouvons maintenant relier notre application au rôle Application Mail.Read et au scope :

    New-ManagementRoleAssignment -Name $AssignmentName `
        -Role "Application Mail.Read" `
        -App $ServicePrincipalObjectId `
        -CustomResourceScope $ScopeName

    Le paramètre à retenir est -CustomResourceScope. Il indique le périmètre de cette attribution applicative. Ne le supprimez pas pour contourner une erreur.

    Notre besoin est la consultation : nous n’ajoutons donc pas de rôle d’envoi ou de modification. Mail.ReadWrite inclut notamment la modification et la suppression de messages ; Mail.Send répond à un autre besoin.

    5. Retirer les droits globaux qui couvrent le même besoin

    C’est l’étape à ne pas oublier si l’application disposait déjà d’autorisations Graph.

    ⚠️ Application déjà utilisée en production

    Identifiez les traitements qui utilisent cette même identité avant de retirer leurs permissions. Préparez les attributions RBAC nécessaires et vérifiez leur scope. La validation de l’accès réel doit ensuite être refaite après le retrait des droits globaux.

    1. Ouvrez Entra ID > Enterprise apps > All applications > votre application > Permissions.
    2. Dans Admin consent, examinez les permissions applicatives réellement accordées.
    3. Pour les droits globaux remplacés par RBAC, utilisez le menu … > Revoke permission.
    4. Vérifiez aussi App registrations > votre application > API permissions et retirez les permissions configurées devenues inutiles, afin d’éviter de les réaccorder lors d’un prochain consentement.

    Ne vous limitez pas à chercher Mail.Read : une permission globale plus large, comme Mail.ReadWrite, permet également la lecture. Le résultat attendu est l’absence d’une autre autorisation qui ouvre encore les boîtes hors périmètre. Les permissions nécessaires à d’autres API doivent être évaluées séparément.

    Dans ce scénario RBAC, le droit de lecture ciblé est porté par Exchange. Il n’est pas nécessaire de rajouter Mail.Read dans Entra pour le faire fonctionner.

    6. Tester les autorisations dans Exchange

    Nous allons tester chaque boîte, y compris celle que l’application ne doit pas pouvoir consulter :

    $MailboxesToTest = @(
        "support@contoso.com"
        "factures@contoso.com"
        "direction@contoso.com"
    )
    
    foreach ($Mailbox in $MailboxesToTest) {
        Write-Host "Test RBAC : $Mailbox"
        Test-ServicePrincipalAuthorization `
            -Identity $ServicePrincipalObjectId `
            -Resource $Mailbox |
            Format-Table RoleName, AllowedResourceScope, InScope
    }
    Boîte testée Résultat attendu pour notre attribution Mail.Read
    support@contoso.com InScope = True
    factures@contoso.com InScope = True
    direction@contoso.com InScope = False

    Lisez toutes les lignes retournées : un autre rôle ou un autre périmètre peut aussi autoriser l’application. False sur notre seule attribution ne décrit pas forcément l’ensemble de ses accès.

    Le test RBAC a une limite

    Cette commande n’évalue pas les permissions accordées séparément dans Entra. Elle ne remplace donc pas un appel réel avec l’application. Les changements RBAC sont aussi soumis à un cache de 30 minutes à 2 heures ; la commande de test contourne ce cache.

    7. Vérifier l’accès réel avec Microsoft Graph

    Pour ce test, utilisez bien le Client ID de l’application que vous venez de configurer. Une connexion Graph interactive avec votre compte administrateur testerait un autre contexte.

    L’exemple suivant utilise un secret client existant, saisi à l’invite. Il ne faut pas inscrire sa valeur dans le script. Si votre application s’authentifie déjà avec un certificat, utilisez ce même mécanisme pour le test.

    # Dans PowerShell 7, installation si nécessaire
    Install-Module Microsoft.Graph.Authentication -Scope CurrentUser
    Import-Module Microsoft.Graph.Authentication
    
    # Fermer une éventuelle session Graph précédente
    if (Get-MgContext) { Disconnect-MgGraph | Out-Null }
    
    $TenantId = "<TENANT-ID>"
    $ClientSecret = Read-Host "Valeur du secret client" -AsSecureString
    $AppCredential = [System.Management.Automation.PSCredential]::new(
        $AppId, $ClientSecret
    )
    
    Connect-MgGraph -TenantId $TenantId `
        -ClientSecretCredential $AppCredential `
        -ContextScope Process -NoWelcome
    
    Get-MgContext | Select-Object ClientId, TenantId, AuthType

    Vérifiez le Client ID et le tenant retournés ; AuthType doit indiquer AppOnly. Après une modification de permissions, repartez d’une nouvelle connexion pour renouveler le jeton.

    Testez maintenant les deux boîtes autorisées, puis celle située hors scope. L’API attend un ID d’objet Entra ou un UPN dans /users/{id} : ne supposez pas qu’un alias SMTP fonctionne. Les valeurs ci-dessous supposent que les UPN correspondent aux adresses indiquées ; remplacez-les sinon par les bons UPN ou IDs.

    # Une réponse 200 est attendue pour chaque boîte autorisée,
    # même si la liste de messages est vide.
    Invoke-MgGraphRequest -Method GET -Uri 'https://graph.microsoft.com/v1.0/users/support@contoso.com/messages?$top=1&$select=id'
    
    Invoke-MgGraphRequest -Method GET -Uri 'https://graph.microsoft.com/v1.0/users/factures@contoso.com/messages?$top=1&$select=id'
    
    # Une réponse 403 est attendue pour cette boîte existante hors scope.
    Invoke-MgGraphRequest -Method GET -Uri 'https://graph.microsoft.com/v1.0/users/direction@contoso.com/messages?$top=1&$select=id'
    
    Disconnect-MgGraph

    Le résultat recherché est un accès réussi sur les deux premières boîtes et un refus sur la troisième. Un 401 indique un problème d’authentification ; un 404 ne prouve pas que le scope fonctionne. Vérifiez notamment que la boîte de contrôle existe et que son identifiant est correct.

    Si la boîte hors scope reste accessible après propagation, reprenez les permissions Entra et les autres attributions RBAC de cette application. Ne validez pas la configuration sur la seule présence du scope.

    8. Faire évoluer le périmètre

    Pour ajouter une troisième boîte, modifiez le filtre du scope existant. Prévisualisez toujours le nouveau résultat avant de l’appliquer :

    $NewRecipientFilter = "(RecipientTypeDetails -eq 'UserMailbox' -or RecipientTypeDetails -eq 'SharedMailbox') -and (EmailAddresses -eq 'smtp:support@contoso.com' -or EmailAddresses -eq 'smtp:factures@contoso.com' -or EmailAddresses -eq 'smtp:commandes@contoso.com')"
    
    Get-Recipient -Filter $NewRecipientFilter -ResultSize Unlimited |
        Format-Table DisplayName, PrimarySmtpAddress, RecipientTypeDetails
    
    # Après validation de la sélection
    Set-ManagementScope -Identity $ScopeName `
        -RecipientRestrictionFilter $NewRecipientFilter

    L’attribution utilise toujours le même scope. Attention : modifier un scope partagé avec d’autres attributions modifie aussi leur périmètre. Rejouez les tests après chaque changement.

    Pour une liste plus importante, vous pouvez prévoir un filtre fondé sur un attribut Exchange dédié ou sur l’appartenance à un groupe. L’approche par adresses convient ici à une petite liste explicite ; elle doit être revue si les adresses sont renommées ou réattribuées.

    Et les Application Access Policies ?

    Vous trouverez encore des tutoriels utilisant New-ApplicationAccessPolicy. Microsoft présente désormais cette approche comme legacy et recommande RBAC for Applications pour les nouvelles configurations.

    Le fonctionnement diffère : une Application Access Policy limite des permissions consenties dans Entra, tandis que RBAC attribue des rôles applicatifs avec leur périmètre dans Exchange. Si une ancienne policy existe, suivez une migration complète avant de la supprimer.

    Mon avis

    Pour moi, ce réglage devrait faire partie des vérifications quand on connecte une application à la messagerie. On commence souvent par vérifier si l’outil arrive à lire les mails. Il faut aussi vérifier ce qu’il ne doit pas pouvoir lire.

    Je garderais donc une trace du besoin, du Client ID, du rôle attribué et des boîtes autorisées, avec un test positif et un test négatif. C’est ce qui permettra de reprendre la configuration proprement quand le besoin évoluera.

    Et vous ?

    Vos applications ont-elles accès uniquement aux boîtes dont elles ont besoin ?

    Laisser un commentaire

    Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

    12 mins