☁️Entra IDPrivileged AccessApplications

Rôle Admin de Service Principal Entra Sur-Privilégié : Détection et Correction

Les service principals Entra sur-privilégiés, sans owner, désactivés mais toujours permissionnés, ou rattachés à une organisation externe forment une surface d'admin permanente, à l'abri du MFA. Requêtes de détection et étapes de remédiation.

Younes AZABARPar Younes AZABAR10 min de lecture
Rôle Admin de Service Principal Entra Sur-Privilégié : Détection et Correction

Ce qui rend un rôle admin de service principal Entra sur-privilégié

Un rôle admin de service principal Entra sur-privilégié par rapport à ce que son automatisation fait réellement est l'une des identités les moins revues de Microsoft Entra ID — et l'une des plus dangereuses, car contrairement à un admin humain, elle n'a jamais à passer le MFA, a rarement un owner de cycle de vie, et survit souvent au projet qui l'a créée. Un service principal est l'identité locale au tenant d'une application ou d'un script : c'est l'identité avec laquelle Terraform, un pipeline CI/CD ou une automatisation personnalisée s'authentifie lorsqu'il appelle Microsoft Graph. Donnez-lui un rôle admin d'annuaire tel que Global Administrator, Privileged Role Administrator ou Application Administrator, et il peut faire tout ce qu'un admin humain dans ce rôle peut faire — créer des utilisateurs, réinitialiser des identifiants, consentir à de nouvelles permissions, modifier l'Accès Conditionnel.

Il convient de distinguer ceci d'une exposition connexe mais différente. Un rôle d'annuaire (le sujet de cet article) accorde une capacité administrative à l'échelle du tenant, assignée via roleManagement/directory/roleAssignments. Une attribution de rôle d'application (app role assignment) — les permissions Graph API déléguées ou applicatives comme Directory.ReadWrite.All accordées via servicePrincipals/{id}/appRoleAssignedTo (Grant an appRoleAssignment for a service principal) — est un mécanisme distinct, limité à une seule API de ressource, et fait l'objet de l'article Permissions Graph API dangereuses App Registration Entra. Un service principal peut ne détenir ni l'un ni l'autre, l'un des deux, ou les deux ; cet article traite du côté rôle d'annuaire de cette équation.

Le problème du côté rôle d'annuaire est l'exposition, pas le rôle en lui-même. Un service principal avec un rôle admin sur-privilégié reste actif 24 h/24, s'authentifie de façon non interactive avec un client secret ou un certificat, et — selon les recommandations de Microsoft sur le risque des workload identities — les workload identities « ne peuvent pas effectuer d'authentification multifacteur », « n'ont souvent aucun processus formel de cycle de vie », et « doivent stocker leurs identifiants ou secrets quelque part » (Securing workload identities with Microsoft Entra ID Protection). L'application obligatoire du MFA Microsoft Entra n'atteint pas non plus explicitement ces identités : Microsoft confirme que les workload identities « ne sont concernées par aucune des deux phases » du déploiement du MFA obligatoire (Plan for mandatory Microsoft Entra multifactor authentication). Un secret divulgué pour un service principal avec rôle admin est une session admin divulguée, à l'abri du MFA.

Cette faille est rarement une simple erreur de configuration isolée. C'est généralement un ensemble d'angles morts liés qui se cumulent : le rôle admin est plus large que ce dont l'automatisation a besoin, personne ne possède le service principal, le désactiver ne retire pas réellement la permission, et — de plus en plus — l'identité qui détient le rôle n'est même pas native de votre tenant.

Comment les service principals sur-privilégiés apparaissent

Permanent, pas éligible

Privileged Identity Management (PIM) permet de rendre l'assignation de rôle d'un admin humain éligible — inactive jusqu'à activation, limitée dans le temps, et journalisée. Les service principals ne peuvent pas utiliser ce modèle : les rôles Microsoft Entra, les rôles Azure et PIM pour les groupes ne peuvent accorder à un service principal qu'une assignation active, car les assignations éligibles nécessitent une étape d'activation (approbation, challenge MFA) qu'une identité non interactive ne peut pas effectuer (Eligible and time-bound role assignments in Azure RBAC). En pratique, chaque service principal avec un rôle admin dans votre tenant est une assignation permanente par conception — il n'y a aucun filet de sécurité PIM qui la limite dans le temps, sauf si quelqu'un a séparément défini une expiration d'assignation.

Aucun owner

servicePrincipal.owners est censé répondre à la question « qui est responsable de ceci ». Microsoft Graph l'expose comme une collection que l'on peuple avec un appel POST /servicePrincipals/{id}/owners $ref (servicePrincipal: Add owner) — mais rien n'oblige à la peupler à la création. Un service principal qui apparaît lors d'un balayage des assignations de rôles avec une collection owners vide détient un rôle admin dont personne n'est notifié, que personne ne revoit lors d'un offboarding, et que personne ne peut expliquer lors d'un appel d'incident.

Désactivé mais toujours permissionné

accountEnabled sur un service principal est un booléen qui bloque la connexion lorsqu'il est à false — « aucun utilisateur ne peut se connecter à cette application, même s'il y est assigné » (servicePrincipal resource type). Cela ne touche pas aux assignations de rôle ou de rôle d'application — les retirer est une opération distincte avec son propre cmdlet, Remove-MgServicePrincipalAppRoleAssignment (Microsoft Learn). Une équipe qui « décommissionne » une intégration en passant accountEnabled à false et en s'arrêtant là laisse l'assignation de rôle admin totalement intacte — réactiver le compte, ou un attaquant capable de repasser ce même flag, restaure instantanément l'accès admin.

D'une organisation externe

Tous les service principals de votre tenant n'ont pas été créés par vous. Les app registrations multi-tenant créent un service principal localement tandis que l'objet application sous-jacent reste dans le tenant d'origine du vendeur ou du partenaire — enregistré sous appOwnerOrganizationId, que Microsoft Entra inscrit aussi dans les détails complémentaires de l'événement d'audit lors du provisionnement du service principal (Understand why a service principal was created in your tenant). Lorsque appOwnerOrganizationId ne correspond pas à l'ID de votre propre tenant et que ce service principal détient également un rôle admin, vous avez délégué un accès admin permanent à une identité contrôlée par un tiers — l'équivalent applicatif de l'exposition cross-tenant des comptes invités que la plupart des équipes surveillent déjà pour les comptes utilisateurs, mais presque jamais pour les applications.

Détection

Récupérez chaque assignation de rôle d'annuaire, puis croisez-les pour déterminer quels principals sont des service principals plutôt que des utilisateurs ou des groupes — Get-MgRoleManagementDirectoryRoleAssignment ne filtre pas par type de principal à lui seul, il faut donc résoudre cela avec une recherche via Get-MgServicePrincipal (List Microsoft Entra role assignments) :

Connect-MgGraph -Scopes "RoleManagement.Read.Directory","Application.Read.All"

$roles = Get-MgRoleManagementDirectoryRoleDefinition
$spAssignments = foreach ($role in $roles) {
    Get-MgRoleManagementDirectoryRoleAssignment -Filter "roleDefinitionId eq '$($role.Id)'" |
        ForEach-Object {
            $sp = Get-MgServicePrincipal -ServicePrincipalId $_.PrincipalId -ErrorAction SilentlyContinue
            if ($sp) {
                [pscustomobject]@{
                    ServicePrincipal = $sp.DisplayName
                    RoleAssigned     = $role.DisplayName
                    AccountEnabled   = $sp.AccountEnabled
                    OwnerCount       = (Get-MgServicePrincipalOwner -ServicePrincipalId $sp.Id).Count
                    AppOwnerOrgId    = $sp.AppOwnerOrganizationId
                }
            }
        }
}
$spAssignments | Format-Table -AutoSize

La même requête fonctionne directement contre Microsoft Graph sans le module PowerShell — utile pour un script s'exécutant hors d'un poste avec le SDK Graph installé :

GET https://graph.microsoft.com/v1.0/roleManagement/directory/roleAssignments?$filter=roleDefinitionId eq '{role-template-id}'

Chaque résultat renvoie un principalId ; résolvez-le via GET /servicePrincipals/{id} pour confirmer le type de principal et récupérer accountEnabled, appOwnerOrganizationId, et — via GET /servicePrincipals/{id}/owners — la collection owners dans le même appel (List Microsoft Entra role assignments).

DétecteurCe qu'il faut vérifierPourquoi c'est important
PA_SERVICE_PRINCIPAL_ADMIN / SP_HIGH_PRIVILEGETout service principal ci-dessus avec un rôle Global Administrator, Privileged Role Administrator, ou un autre rôle de haut niveauAccès admin permanent, incapable d'effectuer le MFA
SP_NO_OWNEROwnerCount -eq 0 sur un service principal détenant un rôleAucun humain responsable pour le revoir ou le révoquer
SP_DISABLED_WITH_PERMISSIONSAccountEnabled -eq $false mais l'assignation de rôle se résout toujoursLa permission a survécu à ce qui ressemblait à un décommissionnement
SP_EXTERNAL_ORGANIZATIONAppOwnerOrganizationId présent et différent de l'ID de votre propre tenantRôle admin détenu par une identité qu'une autre organisation contrôle

Pour l'événement d'assignation lui-même, filtrez les journaux d'audit Microsoft Entra sur le service Core Directory et la catégorie Role Management, puis recherchez les entrées d'activité « Add member to role », en limitant TargetResources au type ServicePrincipal pour isoler les attributions non humaines de celles des utilisateurs (Easily Manage Privileged Role Assignments in Microsoft Entra ID Using Audit Logs). Exportez ces journaux avant qu'ils n'expirent — la rétention des journaux d'audit Entra est courte par défaut et facile à perdre sans diagnostic settings configurés.

⚠️

⚠️ Avertissement : AccountEnabled -eq $false sur un service principal n'est pas une remédiation. Cela stoppe la connexion, pas l'assignation de rôle — traitez un service principal désactivé avec un rôle admin comme toujours privilégié tant que vous n'avez pas confirmé que l'assignation elle-même a été retirée.

Remédiation

💡

💡 Gain rapide : Exécutez une première fois le script de détection ci-dessus et triez en priorité chaque résultat SP_NO_OWNER et SP_EXTERNAL_ORGANIZATION — ce sont les deux catégories que personne d'autre dans le tenant ne surveille probablement déjà.

  1. Ajustez le rôle à la juste taille. Remplacez les rôles admin larges (Global Administrator, Privileged Role Administrator) par le rôle intégré ou personnalisé le plus étroit couvrant les appels Graph réels de l'automatisation — la plupart des intégrations n'ont besoin que d'Application Administrator ou d'un rôle limité à une ressource, pas de Global Administrator. Un service principal qui ne fait que provisionner des utilisateurs n'a pas besoin du même rôle qu'un service principal qui gère l'Accès Conditionnel.
  2. Assignez un owner. POST /servicePrincipals/{id}/owners avec un $ref vers un ingénieur responsable, afin que l'assignation apparaisse dans les revues d'accès au lieu de ne surgir que lors d'un incident.
  3. Retirez les permissions avant de désactiver. Exécutez Remove-MgServicePrincipalAppRoleAssignment (ou l'opération équivalente de désassignation de rôle d'annuaire) dans le cadre du runbook de décommissionnement — ne vous fiez pas uniquement à accountEnabled: $false, et ne considérez une intégration « désactivée » comme clôturée que lorsque l'assignation de rôle elle-même a disparu.
  4. Définissez une expiration quand c'est possible. Comme les service principals ne peuvent détenir que des assignations actives, utilisez l'option de date de fin de l'assignation au moment de l'octroi, afin qu'un rôle admin ne devienne pas silencieusement permanent par défaut.
  5. Encadrez les workload identities avec l'Accès Conditionnel. Conditional Access for workload identities peut bloquer la connexion d'un service principal mono-tenant selon la localisation ou l'état de risque d'Identity Protection — cela n'impose pas le MFA (les service principals ne le peuvent pas), mais cela referme une partie de la faille que le MFA ne peut pas atteindre.
  6. Examinez les service principals d'organisations externes selon leurs propres mérites. Pour chaque détection SP_EXTERNAL_ORGANIZATION détenant un rôle admin, confirmez que la relation avec le vendeur est toujours active et que le rôle est toujours justifié — le même niveau de rigueur que vous appliqueriez à un compte invité avec un accès permanent, appliqué à une application plutôt qu'à une personne.

Cela complète la revue que la plupart des équipes effectuent déjà pour l'accès privilégié humain — voir Accès Privilégié Azure : Trop d'Admins Globaux et Comment auditer la sécurité Microsoft Entra ID — et c'est distinct, bien que lié, des permissions Graph API dangereuses sur l'app registration elle-même, qui constituent une exposition séparée du rôle d'annuaire du service principal.

Comment EtcSec détecte cela

L'audit Azure d'EtcSec vérifie PA_SERVICE_PRINCIPAL_ADMIN et SP_HIGH_PRIVILEGE sur chaque assignation de rôle d'annuaire détenue par un service principal, et signale séparément SP_NO_OWNER, SP_DISABLED_WITH_PERMISSIONS, et SP_EXTERNAL_ORGANIZATION, afin que les failles d'ownership, de cycle de vie et de cross-tenant ci-dessus remontent comme des findings au lieu de nécessiter un balayage PowerShell manuel chaque trimestre sur chaque définition de rôle du tenant.

ℹ️

ℹ️ Remarque : EtcSec vérifie automatiquement cette vulnérabilité à chaque audit Azure. Lancez un audit gratuit pour vérifier votre environnement.