Cloud Knowledge

Your Go-To Hub for Cloud Solutions & Insights

Advertisement

Master Entra ID app & service-principal governance

Master Entra ID app & service-principal governance

Application, Service Principal & App-Consent Governance in Microsoft Entra ID — Complete Guide

Many organisations struggle to manage apps that integrate with Microsoft Entra ID: app registrations proliferate, service principals end up with excessive permissions, and users get blocked by misconfigured consents or roles. This end-to-end guide shows governance frameworks, operational playbooks, troubleshooting with PowerShell & Microsoft Graph, audit queries, and remediation examples you can copy directly into your runbook.

Cloud governance and team collaboration

Executive summary

Application and service-principal governance is essential for modern identity security. Organisations must build processes for:

  • Inventory & discovery of app registrations and service principals
  • Assigning and enforcing owners and lifecycle responsibilities
  • Permission & consent reviews (delegated & application permissions)
  • Detecting and remediating over-privileged and stale non-human identities
  • Automating alerts and integrating findings with IAM/IGA tooling

This article provides a practical, hands-on playbook (PowerShell + Graph examples), sample detection rules, and a governance checklist you can implement today.


Foundations: Application objects, Service Principals & Consent (quick primer)

What's an Application object?

An application object is created in the home tenant when developers register an app (client id, redirect URIs, permissions, secrets or certificates). It represents the definition of your app and its capabilities.

What's a Service Principal?

A service principal (SP) is the runtime identity used to access resources in a tenant. For single-tenant apps the app object and service principal both exist in the same tenant; for multi-tenant apps, the SP is created in each consumer tenant upon consent.

Consent & Permissions — two types

  • Delegated permissions: app acts on behalf of a signed-in user.
  • Application permissions: app acts as itself (no user context) and often require admin consent because they can provide broad access.

Governance must track both the permissions requested in app manifest and permissions actually granted to the service principal via OAuth2 permission grants and app role assignments.


Common governance failures & real risks

Below are the patterns we see repeatedly in organisations and why they matter:

Shadow app registrations

Developers or third-party tools create app registrations without formal approvals. Over time there may be thousands of app objects—many with no owner, expired credentials, or broad permissions.

Over-privileged service principals

Some SPs retain high-impact permissions (Directory.ReadWrite.All, RoleManagement.ReadWrite.Directory, etc.) even though they were only meant to run a limited job. These are prime targets for attackers.

Orphaned or inactive identities

SPs with no sign-in activity but active credentials represent a dormant risk—unchanged credentials can be weaponised if leaked.

Blind admin consent

End users or overly permissive policies allow apps to obtain admin-level consents without review, enabling data exfiltration or privilege escalation.


Governance framework — practical components

Adopt a layered model: People, Process, Technology.

1) People: ownership & accountability

  • Require a named owner (team + backup) for every app registration and service principal.
  • Owners certify permissions & usage quarterly.
  • Active developer education: how to register apps properly and use managed identities where possible.

2) Process: lifecycle & certification

  • Standardize app registration via a central portal / approval workflow (ITSM request + justification).
  • Secrets/certificates must have defined expiry, rotation, and approval steps.
  • Certification campaigns (every 90 days) to review permissions and owners—document decisions.

3) Technology: detection, monitoring & automation

  • Central inventory (Graph + PowerShell) into a dashboard (Power BI / SIEM).
  • Detect high-risk permissions, new admin consents, secret additions and owner changes.
  • Automated remediation: disable stale SPs, block risky permissions, generate tickets for owners.

Discovery & Inventory — scripts you can run now

Run these PowerShell + Microsoft Graph queries to build a baseline inventory. The examples use the Microsoft Graph PowerShell SDK (recommended) and raw REST Graph where noted.

Prerequisites (PowerShell)

# Install & import Microsoft Graph PowerShell (if not already installed)
Install-Module -Name Microsoft.Graph -Scope CurrentUser
Import-Module Microsoft.Graph

# Connect with appropriate scopes for inventory (run interactively)
Connect-MgGraph -Scopes "Application.Read.All","Directory.Read.All","AuditLog.Read.All"
    

A. Export all App Registrations & Service Principals

# Export all applications and service principals to CSV
$apps = Get-MgApplication -All
$sps  = Get-MgServicePrincipal -All

$apps | Select-Object Id, DisplayName, AppId, SignInAudience, PublishedPermissionScopes |
  Export-Csv -Path ".\entra_apps.csv" -NoTypeInformation

$sps | Select-Object Id, DisplayName, AppId, ServicePrincipalType, AccountEnabled, SignInActivity |
  Export-Csv -Path ".\entra_serviceprincipals.csv" -NoTypeInformation
    

B. Get owner(s) for each service principal

# Map service principals to owners (UserPrincipalName or display name)
$report = foreach ($sp in (Get-MgServicePrincipal -All)) {
  $owners = try { (Get-MgServicePrincipalOwner -ServicePrincipalId $sp.Id -ErrorAction Stop) } catch { @() }
  [PSCustomObject]@{
    DisplayName = $sp.DisplayName
    AppId       = $sp.AppId
    ObjectId    = $sp.Id
    Owners      = ($owners | ForEach-Object { $_.UserPrincipalName -or $_.DisplayName }) -join ';'
    AccountEnabled = $sp.AccountEnabled
    LastSignIn     = $sp.SignInActivity.LastSignInDateTime
  }
}
$report | Export-Csv -Path ".\sp_owner_mapping.csv" -NoTypeInformation
    

C. List OAuth2 permission grants (who granted what)

# OAuth2PermissionGrants show consented permissions across tenants (useful for multi-tenant apps)
Get-MgOauth2PermissionGrant -All | Select-Object ClientId,ConsentType,PrincipalId,ResourceId,Scope |
  Export-Csv -Path ".\oauth2_permission_grants.csv" -NoTypeInformation
    

D. Graph API: get appRoleAssignments for a specific SP (REST example)

GET https://graph.microsoft.com/v1.0/servicePrincipals/{servicePrincipalObjectId}/appRoleAssignments?$top=999
Authorization: Bearer <access_token>
    

Export these outputs into a central spreadsheet or database and visualise the following KPIs:

  • # of apps with no owner
  • # of SPs with Directory.* or RoleManagement.* permissions
  • # of unused credentials (no sign-ins & active credentials)
  • Top 50 apps by number of granted scopes

Detecting high-risk & over-privileged principals

Prioritise remediation by risk score. Use a combination of: privilege level, last sign-in, owner assigned, and whether the principal is multi-tenant.

PowerShell: find SPs with high-risk app permissions

# Define high-risk delegated/application permissions by resource + scope name
$highRiskScopes = @("Directory.ReadWrite.All","Directory.AccessAsUser.All","RoleManagement.ReadWrite.Directory")

$highRiskSPs = Get-MgServicePrincipal -All | Where-Object {
  $sp = $_
  # Check OAuth2PermissionGrants where ResourceAppId equals the target service principal AppId and scope matches
  $grants = Get-MgOauth2PermissionGrant -All | Where-Object { $_.ClientId -eq $sp.Id -or $_.ResourceId -eq $sp.Id }
  foreach ($g in $grants) { if ($highRiskScopes -contains $g.Scope) { return $true } }
  return $false
}

$highRiskSPs | Select DisplayName, AppId, Id, SignInActivity | Export-Csv .\highrisk_sps.csv -NoTypeInformation
    

KQL (Microsoft Sentinel / Log Analytics): detect SP credential creation

// Look for Service Principal credential add events
AuditLogs
| where ActivityDisplayName == "Add service principal key" or ActivityDisplayName == "Add credential"
| project TimeGenerated, ActivityDisplayName, Actor, TargetResources, AdditionalDetails
| top 50 by TimeGenerated
    

Use the outputs above to create an automated ticket for each high-risk SP and require the owner to justify the permissions or schedule a remediation action (disable/rotate/remove).


Remediation playbook examples (repeatable)

Playbook: Disable an inactive but highly privileged service principal

Goal: Immediately minimize risk by disabling access while owner validates necessity.

  1. Identify SP with SignInActivity older than 90 days and with Directory.* permission (inventory step).
  2. Temporarily set AccountEnabled to false (disabled). Create a ticket assigned to owner with remediation SLA 7 days.
  3. If owner confirms usage, require justification and plan to rotate credentials and minimize permissions to least privilege. If owner does not respond, schedule deletion per policy.
# Disable service principal
Update-MgServicePrincipal -ServicePrincipalId <ObjectId> -AccountEnabled:$false

# Add a note in your ITSM system (pseudo)
Write-Host "Ticket created for SP <DisplayName> - Owner: <owner> - Action: Disabled pending review"
    

Playbook: Revoke application permissions (admin consent removal)

Goal: Remove a specific OAuth2 permission grant for a client app.

# Find OAuth2 grants for the client and revoke them
$grants = Get-MgOauth2PermissionGrant -All | Where-Object { $_.ClientId -eq "<clientId>" -and $_.Scope -like "*Directory.ReadWrite.All*" }
foreach ($g in $grants) {
  Remove-MgOauth2PermissionGrant -Oauth2PermissionGrantId $g.Id
}
    

Playbook: Rotate a client secret or certificate

Goal: Rotate credentials with minimal downtime.

  1. Create a new secret/cert on the application registration with a short overlap period.
  2. Update the consuming service to use the new secret/cert.
  3. After verification, remove the old credential and document rotation in the app manifest.
# Add a new password credential (secret) for app
$pwd = New-MgApplicationPassword -ApplicationId <appObjectId> -DisplayName "Rotation-2025" -EndDateTime (Get-Date).AddYears(1)
Write-Output "New secret created. Secret value (copy immediately): $($pwd.SecretText)"
    

App-Consent governance & control

App consent is where security and productivity collide. Users want to accelerate onboarding to SaaS; security wants to prevent data leakage. A pragmatic approach balances convenience and risk.

Policy choices

  • Block user consent: Only admins can consent to apps that request high-impact permissions.
  • Allow limited user consent: permit selected delegated scopes for verified publishers only.
  • Allow all user consent: not recommended for enterprise tenants unless combined with strict monitoring.

Admin consent workflow (recommended)

  1. User requests an app via a portal (with business justification).
  2. Security reviews requested scopes; if acceptable, admin consents and assigns owners.
  3. Consent is recorded (Ticket + approval metadata) and tied to the app record for periodic review.

Detecting recent consent grants (PowerShell)

# Recent admin consent grants (Audit logs)
Search-UnifiedAuditLog -StartDate (Get-Date).AddDays(-30) -EndDate (Get-Date) -RecordType AzureActiveDirectory | 
  Where-Object { $_.Operations -match "Consent to application" } | Select-Object CreationDate, UserIds, Operations, AuditData
    

When a new admin consent appears, trigger a workflow: validate scopes, record the owner, and schedule an expiration review.


Operational dashboards & KPIs

Your governance program should be metrics-driven. Suggested KPIs and dashboards:

  • Number of apps with no owner (target: 0)
  • Number of SPs with Directory.* permissions
  • Number of secrets/certs expiring in next 30 days
  • Number of inactive SPs (>90 days no sign-in)
  • Number of admin consent events per month (and top requesting apps)

Build a Power BI report that ingests CSV outputs or use your SIEM (Sentinel) to produce charts and automated alerts.


Integrations & tools to accelerate governance

Combine Entra ID native capabilities with third-party IGA or PAM tools:

  • Microsoft Entra Governance / Entitlement Management: for user access packages and expiry control.
  • IGA vendors: SailPoint, Saviynt — for certification campaigns including app/service principal entitlements.
  • PAM & Just-in-Time: extend JIT concepts to non-human identities using time-bound role assignments and credential vaulting.
  • SIEM / UEBA: Microsoft Sentinel or third-party tools for anomalous behavior and credential changes.

Where possible prefer managed identities (Azure Managed Identity) for Azure services instead of app secrets—this removes secret lifecycle management from your scope.


Case study (short): Right-sizing a large tenant

An enterprise with ~8,000 app registrations implemented a 90-day governance sprint:

  1. Inventoryed all apps and SPs via Graph (PowerShell exports).
  2. Tagged each object with owner; escalated unowned apps to product teams.
  3. Created an auto-ticket for any SP with Directory.* permissions; owners had 7 days to justify.
  4. Disabled 17% of SPs as orphaned; rotated credentials on 9% with imminent expiry; consent policy tightened for user consent.

Result: attack surface reduced (measured as number of privileged SPs) by 42% and secret expiries were reduced to zero within 120 days.


Advanced Microsoft Graph patterns

Use the Graph to programmatically manage manifests, app roles, and consent grants. Below are several example REST payloads and queries.

A. Find all appRoleAssignments for a user or service principal

GET https://graph.microsoft.com/v1.0/users/{userId}/appRoleAssignments
GET https://graph.microsoft.com/v1.0/servicePrincipals/{spId}/appRoleAssignedTo
Authorization: Bearer <token>
    

B. Update application manifest to add an app role

PATCH https://graph.microsoft.com/v1.0/applications/{appObjectId}
Content-Type: application/json
Authorization: Bearer <token>

{
  "appRoles": [
    {
      "allowedMemberTypes": [ "User" ],
      "description": "Read-only readers",
      "displayName": "Reader",
      "id": "a-generated-guid",
      "isEnabled": true,
      "value": "Reader"
    }
  ]
}
    

C. Revoke all OAuth consents for a client (dangerous — use with caution)

# PowerShell pseudo: remove all OAuth2PermissionGrants for a client
Get-MgOauth2PermissionGrant -All | Where-Object { $_.ClientId -eq "<clientId>" } | ForEach-Object {
  Remove-MgOauth2PermissionGrant -Oauth2PermissionGrantId $_.Id
}
    

Warning: revoking admin consents can break integrations. Always perform change control and notify stakeholders.


Checklist: immediate actions for your first 30/90/180 days

Day 0–30: Rapid discovery & quick wins

  • Run full inventory (PowerShell scripts above). Export to CSV.
  • Identify apps/SPs with no owner — assign temporary owners.
  • Find SPs with Directory.* and notify owners (or disable if orphaned).
  • Enable sign-in logs and streaming to SIEM for service principal events.

Day 31–90: Policy & process

  • Publish app registration process (approval + naming convention + required metadata).
  • Define consent policy — block or limit user consent depending on risk tolerance.
  • Roll out certification campaigns to owners (quarterly cadence).

Day 91–180: Automate & integrate

  • Integrate results into IGA (if available) and run automatic alerts for high risk.
  • Implement JIT and credential vaulting for critical service principals.
  • Measure KPIs and review metrics with security leadership monthly.

FAQ — quick answers

Q: Should I delete all unused app registrations?

A: Not immediately. First disable inactive service principals, notify owners, and follow a retention policy before deletion to avoid breaking integrations.

Q: Are managed identities always the best option?

A: For Azure workloads, yes—managed identities remove secret management. For cross-tenant SaaS or custom apps you still need app registrations and SPNs.

Q: How often should we run certification campaigns?

A: Quarterly is a pragmatic starting point. High-risk principals should be reviewed monthly.


Glossary — short

Application object
Definition of an app in the home tenant — contains redirect URIs, app roles, permissions and credential definitions.
Service principal
Runtime identity used by an app in a specific tenant. Controls access to resources in that tenant.
OAuth2PermissionGrant
An object representing an OAuth consent grant (delegated or application) given to a client.

Resources & further reading

Authoritative references we rely on:

Internal resources and articles on cloudknowledge.in (link to be used for site SEO anchors).


Appendix: More PowerShell & Graph troubleshooting snippets

Query: Which apps request admin consent for Directory.* scopes

# Find applications that request Directory.* scopes declared in their requiredResourceAccess
$appRequiringDirectory = Get-MgApplication -All | Where-Object {
  $_.RequiredResourceAccess -ne $null -and ($_.RequiredResourceAccess | Where-Object {
     $_.ResourceAppId -and ($_.ResourceAccess | Where-Object { $_.Type -eq "Scope" -and $_.Id -ne $null })
  })
}
$appRequiringDirectory | Select DisplayName, AppId, Id | Export-Csv .\apps_requesting_directory_scopes.csv -NoTypeInformation
    

Query: List secrets/certificates with expiry dates

# Secrets on application objects
Get-MgApplication -All | ForEach-Object {
  $app = $_
  foreach ($cred in $app.PasswordCredentials) {
    [PSCustomObject]@{
      DisplayName = $app.DisplayName
      AppId       = $app.AppId
      KeyId       = $cred.KeyId
      EndDate     = $cred.EndDateTime
      StartDate   = $cred.StartDateTime
    }
  }
} | Export-Csv .\app_secrets_expiry.csv -NoTypeInformation
    

Query: Last sign-ins for service principals (faster approach)

# SignInActivity is available via Get-MgServicePrincipal; it may not always be populated.
Get-MgServicePrincipal -All | Select DisplayName, AppId, SignInActivity | Export-Csv .\sp_signin_activity.csv -NoTypeInformation
    

Final recommendations — quick actionable list

  1. Run discovery scripts this week and build a central inventory.
  2. Enforce owners for every app & service principal within 30 days.
  3. Disable or quarantine orphaned principals; create tickets for remediation.
  4. Lock down user consent policy and reason admin consents via an approval portal.
  5. Track secrets & cert expiry, automate notifications 60/30/7 days before expiry.
  6. Integrate audit logs with SIEM to detect credential additions, admin consents, owner changes.
  7. Include service principals in your entitlement management and certification campaigns.

© 2025 • cloudknowledge.in — Practical guidance for Entra ID identity governance.

Leave a Reply

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