Qué hace que un rol de administrador de service principal en Entra esté sobreprivilegiado
Un rol de administrador de service principal en Entra sobreprivilegiado respecto a lo que su automatización realmente hace es una de las identidades menos revisadas en Microsoft Entra ID — y una de las más peligrosas, porque a diferencia de un admin humano, nunca tiene que pasar el MFA, rara vez tiene un owner de ciclo de vida, y a menudo sobrevive al proyecto que lo creó. Un service principal es la identidad local al tenant de una aplicación o script: la identidad con la que Terraform, un pipeline CI/CD, o una automatización personalizada se autentica al llamar a Microsoft Graph. Otórguele un rol de administrador de directorio como Global Administrator, Privileged Role Administrator, o Application Administrator, y podrá hacer todo lo que un admin humano en ese rol puede hacer — crear usuarios, restablecer credenciales, consentir nuevos permisos, modificar el Acceso Condicional.
Vale la pena distinguir esto de una exposición relacionada pero diferente. Un rol de directorio (el tema de este artículo) otorga capacidad administrativa a nivel de todo el tenant, asignada mediante roleManagement/directory/roleAssignments. Una asignación de rol de aplicación (app role assignment) — los permisos delegados o de aplicación de Graph API como Directory.ReadWrite.All concedidos mediante servicePrincipals/{id}/appRoleAssignedTo (Grant an appRoleAssignment for a service principal) — es un mecanismo distinto, limitado a una sola API de recurso, y es el tema tratado en Permisos Graph API Peligrosos de App Registration en Entra. Un service principal puede no tener ninguno, tener uno de los dos, o ambos; este artículo trata del lado del rol de directorio de esa ecuación.
El problema del lado del rol de directorio es la exposición, no el rol en sí. Un service principal con un rol de administrador sobreprivilegiado permanece activo las 24 horas, se autentica de forma no interactiva con un client secret o un certificado, y — según las propias recomendaciones de Microsoft sobre el riesgo de las workload identities — las workload identities «no pueden realizar autenticación multifactor», «a menudo no tienen un proceso formal de ciclo de vida», y «necesitan almacenar sus credenciales o secretos en algún lugar» (Securing workload identities with Microsoft Entra ID Protection). La aplicación obligatoria del MFA de Microsoft Entra tampoco alcanza explícitamente a estas identidades: Microsoft confirma que las workload identities «no se ven afectadas por ninguna de las dos fases» del despliegue del MFA obligatorio (Plan for mandatory Microsoft Entra multifactor authentication). Un secreto filtrado de un service principal con rol admin es una sesión de administrador filtrada, inmune al MFA.
Esta brecha rara vez es un único error de configuración. Suele ser un conjunto de puntos ciegos relacionados que se acumulan: el rol admin es más amplio de lo que necesita la automatización, nadie es el owner del service principal, deshabilitarlo no elimina realmente el permiso, y — cada vez más — la identidad que posee el rol ni siquiera es nativa de su tenant.
Cómo ocurren los service principals sobreprivilegiados
Permanente, no elegible
Privileged Identity Management (PIM) permite que la asignación de rol de un admin humano sea elegible — inactiva hasta que la activa, limitada en el tiempo, y registrada. Los service principals no pueden usar ese modelo: los roles de Microsoft Entra, los roles de Azure y PIM para grupos solo pueden otorgar a un service principal una asignación activa, porque las asignaciones elegibles requieren un paso de activación (aprobación, un desafío MFA) que una identidad no interactiva no puede realizar (Eligible and time-bound role assignments in Azure RBAC). En la práctica, todo service principal con rol admin en su tenant es una asignación permanente por diseño — no hay red de seguridad de PIM que la limite en el tiempo, a menos que alguien haya definido por separado una expiración de la asignación.
Sin owner
servicePrincipal.owners está pensado para responder «quién es responsable de esto». Microsoft Graph lo expone como una colección que se puebla con una llamada POST /servicePrincipals/{id}/owners $ref (servicePrincipal: Add owner) — pero nada obliga a poblarla en la creación. Un service principal que aparece en un barrido de asignaciones de roles con una colección owners vacía tiene un rol admin del que nadie recibe notificación, que nadie revisa en el offboarding, y que nadie puede explicar en una llamada de incidente.
Deshabilitado pero aún con permisos
accountEnabled en un service principal es un booleano que bloquea el inicio de sesión cuando está en false — «ningún usuario puede iniciar sesión en esta app, aunque esté asignado a ella» (servicePrincipal resource type). Esto no afecta a las asignaciones de rol o de rol de aplicación — eliminarlas es una operación distinta con su propio cmdlet, Remove-MgServicePrincipalAppRoleAssignment (Microsoft Learn). Un equipo que «da de baja» una integración poniendo accountEnabled en false y deteniéndose ahí deja la asignación de rol admin totalmente intacta — volver a habilitar la cuenta, o un atacante capaz de revertir ese mismo flag, restaura el acceso admin al instante.
De una organización externa
No todos los service principals de su tenant fueron creados por usted. Los app registrations multi-tenant crean un service principal localmente mientras el objeto de aplicación subyacente permanece en el tenant de origen del proveedor o del partner — registrado como appOwnerOrganizationId, que Microsoft Entra también escribe en los detalles adicionales del evento de auditoría cuando se aprovisiona el service principal (Understand why a service principal was created in your tenant). Cuando appOwnerOrganizationId no coincide con el ID de su propio tenant y ese service principal también posee un rol admin, usted ha delegado un acceso admin permanente a una identidad controlada por un tercero — el equivalente en aplicaciones a la exposición cross-tenant de cuentas invitado que la mayoría de los equipos ya rastrean para cuentas de usuario, pero casi nunca para aplicaciones.
Detección
Extraiga cada asignación de rol de directorio, y luego cruce cuáles principals son service principals frente a usuarios o grupos — Get-MgRoleManagementDirectoryRoleAssignment no filtra por tipo de principal por sí solo, así que resuélvalo con una búsqueda contra 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 misma consulta funciona directamente contra Microsoft Graph sin el módulo de PowerShell — útil para un script que se ejecuta fuera de una estación de trabajo con el SDK de Graph instalado:
GET https://graph.microsoft.com/v1.0/roleManagement/directory/roleAssignments?$filter=roleDefinitionId eq '{role-template-id}'
Cada resultado devuelve un principalId; resuélvalo contra GET /servicePrincipals/{id} para confirmar el tipo de principal y obtener accountEnabled, appOwnerOrganizationId, y — mediante GET /servicePrincipals/{id}/owners — la colección owners en la misma llamada (List Microsoft Entra role assignments).
| Detector | Qué comprobar | Por qué importa |
|---|---|---|
PA_SERVICE_PRINCIPAL_ADMIN / SP_HIGH_PRIVILEGE | Cualquier service principal anterior con un rol Global Administrator, Privileged Role Administrator, u otro rol de alto nivel | Acceso admin permanente, incapaz de MFA |
SP_NO_OWNER | OwnerCount -eq 0 en un service principal con rol asignado | Ningún humano responsable de revisarlo o revocarlo |
SP_DISABLED_WITH_PERMISSIONS | AccountEnabled -eq $false pero la asignación de rol sigue resolviéndose | El permiso sobrevivió a lo que parecía una baja |
SP_EXTERNAL_ORGANIZATION | AppOwnerOrganizationId presente y distinto del ID de su propio tenant | Rol admin en manos de una identidad que controla otra organización |
Para el propio evento de asignación, filtre los logs de auditoría de Microsoft Entra por el servicio Core Directory y la categoría Role Management, y luego busque entradas de actividad «Add member to role», limitando TargetResources al tipo ServicePrincipal para aislar las concesiones no humanas de las de los usuarios (Easily Manage Privileged Role Assignments in Microsoft Entra ID Using Audit Logs). Exporte estos logs antes de que caduquen — la retención de logs de auditoría de Entra es corta por defecto y fácil de perder sin diagnostic settings configurados.
⚠️ Advertencia: AccountEnabled -eq $false en un service principal no es remediación. Detiene el inicio de sesión, no la asignación de rol — trate un service principal desactivado con rol admin como todavía privilegiado hasta confirmar que la propia asignación ha sido eliminada.
Remediación
💡 Ganancia rápida: Ejecute el script de detección anterior una vez y priorice cada resultado SP_NO_OWNER y SP_EXTERNAL_ORGANIZATION primero — esas son las dos categorías que probablemente nadie más en el tenant esté ya vigilando.
- Ajuste el rol al tamaño correcto. Sustituya los roles admin amplios (Global Administrator, Privileged Role Administrator) por el rol integrado o personalizado más estrecho que cubra las llamadas Graph reales de la automatización — la mayoría de las integraciones necesitan Application Administrator o un rol limitado a un recurso, no Global Administrator. Un service principal que solo aprovisiona usuarios no necesita el mismo rol que uno que gestiona el Acceso Condicional.
- Asigne un owner.
POST /servicePrincipals/{id}/ownerscon un$refa un ingeniero responsable para que la asignación aparezca en las revisiones de acceso en lugar de salir a la luz solo durante un incidente. - Elimine los permisos antes de deshabilitar. Ejecute
Remove-MgServicePrincipalAppRoleAssignment(o la desasignación equivalente de rol de directorio) como parte del runbook de baja — no confíe solo enaccountEnabled: $false, y no considere cerrada una integración «deshabilitada» hasta que la propia asignación de rol haya desaparecido. - Establezca una expiración cuando pueda. Como los service principals solo pueden tener asignaciones activas, use la opción de fecha de fin de la asignación en el momento de la concesión para que un rol admin no se vuelva silenciosamente permanente por defecto.
- Controle las workload identities con Acceso Condicional. Conditional Access for workload identities puede bloquear el inicio de sesión de un service principal de un solo tenant según la ubicación o el estado de riesgo de Identity Protection — no forzará el MFA (los service principals no pueden hacerlo), pero cierra parte de la brecha que el MFA no puede alcanzar.
- Revise los service principals de organizaciones externas según sus propios méritos. Para cada resultado
SP_EXTERNAL_ORGANIZATIONcon un rol admin, confirme que la relación con el proveedor sigue vigente y que el rol sigue justificado — el mismo escrutinio que aplicaría a una cuenta invitado con acceso permanente, aplicado a una aplicación en lugar de a una persona.
Esto complementa la revisión que la mayoría de los equipos ya realiza para el acceso privilegiado humano — vea Acceso privilegiado Azure: roles, PIM y administración permanente y Cómo auditar la seguridad de Microsoft Entra ID — y es distinto, aunque relacionado, de los permisos Graph API peligrosos en el propio app registration, que constituyen una exposición separada del rol de directorio del service principal.
Cómo lo detecta EtcSec
La auditoría de Azure de EtcSec verifica PA_SERVICE_PRINCIPAL_ADMIN y SP_HIGH_PRIVILEGE en cada asignación de rol de directorio en manos de un service principal, y señala por separado SP_NO_OWNER, SP_DISABLED_WITH_PERMISSIONS, y SP_EXTERNAL_ORGANIZATION para que las brechas de ownership, ciclo de vida y cross-tenant anteriores aparezcan como hallazgos en lugar de requerir un barrido manual de PowerShell cada trimestre sobre cada definición de rol del tenant.
ℹ️ Nota: EtcSec comprueba automáticamente esta vulnerabilidad en cada auditoría de Azure. Ejecute una auditoría gratuita para verificar su entorno.
Explore las páginas de identidad que apoyan este tema
