Substantive Overview
In modern Entra ID environments, non-human identities (Service Principals and Managed Identities) often outnumber human users. Every SaaS app integrated for SSO, every custom script, and every automation tool creates an identity object with permissions.
This is the new "Shadow IT" frontier. Attackers increasingly target these identities because they often have high privileges (e.g., Directory.ReadWrite.All), no MFA, and weak secrets (Client Secrets) that never rotate.
A mature governance model distinguishes between App Registrations (the definition of the app) and Service Principals (the instance of the app in the tenant). It enforces Workload Identity Federation (OIDC) over secrets where possible, restricts who can consent to permissions, and aggressively retires unused credentials.
Architecture & Patterns
Pattern 1: The App Object vs. Service Principal
Understanding the relationship is critical. The App Registration is the template; the Service Principal is the actual identity that holds permissions.
Pattern 2: Workload Identity Federation (Secret-less)
The secure way to connect external workloads (GitHub Actions, Kubernetes) to Entra ID without managing secrets.
Key Design Decisions
| Decision | Options | Recommendation | Context |
|---|---|---|---|
| Developer Access | Allow all users to register apps vs. Admin only | Allow (Restricted) | Blocking app registration entirely stifles innovation. Allow it, but restrict Consent (what permissions they can grant). |
| Consent Policy | User Consent vs. Admin Consent Workflow | Admin Consent Workflow | Never allow users to consent to app permissions. Route requests to admins or app owners via the workflow. |
| Secret Management | Client Secrets (Passwords) vs. Certificates vs. Federation | Federation > Certs > Secrets | Secrets leak. Federation eliminates the secret. Certificates are better but still require rotation. |
| Permission Grant | Delegated vs. Application | Delegated (Preferred) | "Application" permissions (App-only) are powerful and dangerous. "Delegated" acts on behalf of a user, inheriting their limits. |
| Ownership | Individual vs. Group | Service Account / Group | Never bind a critical app to a single human owner who might leave. |
Implementation Strategy
Phase 0: Discovery
- Inventory: Export all Service Principals with
CloudAppSecurityor PowerShell. Look for "stale" apps (no sign-in > 90 days). - Secret Audit: Identify apps with secrets expiring > 2 years or never.
- Permission Audit: Query Graph API for apps holding
*.*.Allpermissions (e.g.,Mail.Read.All).
Phase 1: Lockdown
- Disable User Consent: Switch "Users can consent to apps accessing company data" to No.
- Enable Admin Consent Workflow: Configure the reviewers (Identity Team).
- Publisher Verification: For multi-tenant apps, pay attention to "Verified Publisher" status.
Phase 2: Modernization
- Managed Identities: Migrate Azure-hosted code (VMs, Functions) to use Managed Identities instead of App Registrations.
- Federation: Convert GitHub Actions / Terraform pipelines to use Workload Identity Federation.
Phase 3: Governance
- Expiration Policy: Enforce max secret lifetime (e.g., 6 months).
- Access Reviews: Set up Access Reviews for Service Principals assigned to highly privileged roles.
Phase 4: Monitoring
- Alerting: Alert on creation of new App Registrations with "High" privileges.
- Credential Hygiene: Monitor for "Client Secret Added" events on sensitive apps.
Risks & Anti-Patterns
| Risk | Likelihood | Impact | Mitigation |
|---|---|---|---|
| Over-privileged Apps | High | Critical | App has Directory.ReadWrite.All but only needs to read users. Mitigation: Least privilege review. |
| Hardcoded Secrets | High | High | Developers checking secrets into Git. Mitigation: Workload Identity Federation. |
| Abandoned Apps | High | Medium | App remains after project dies, secret leaks later. Mitigation: Auto-expiry of secrets, stale app cleanup. |
| Illicit Consent Grant | Medium | High | Phishing attack tricks user into granting OAuth token to attacker app. Mitigation: Disable user consent. |
| Multi-Tenant Exposure | Low | High | Accidentally making an app "Multi-Tenant" allows external access. Mitigation: Default to Single Tenant. |
KPIs & Outcomes
- Apps with Secrets: Reduce count (replace with Managed Identity/Federation).
- Stale Apps: fewer than 1% of total apps.
- Privileged Apps: 100% of apps with "Tier 0" permissions are reviewed quarterly.
- Consent Requests: Processed within SLA (e.g., 24 hours).
Workshop Questions
- Can any user in the tenant register a new application?
- Do you use Managed Identities for Azure resources (VMs, Logic Apps)?
- How do you manage Client Secrets? (Key Vault? Spreadsheet?)
- Do you have an inventory of which app connects to which data?
- What is the process for a developer to request "Write" access to the Directory?
- Have you ever reviewed the "Enterprise Applications" list for unknown vendors?
- Do you use GitHub Actions or GitLab CI to deploy to Azure?
- Do you have policies preventing long-lived secrets (e.g., 2 years)?
- Who is responsible for rotating certificates for apps?
- Are you alerting on the addition of new credentials to existing apps?
- Do you use "App Roles" to manage authorization within your custom apps?
- How do you handle "reply URLs" (redirect URIs)? Are wildcards allowed? (Security risk)
- Do you have a naming convention for App Registrations?
- What happens when an app owner leaves the organization?
- Do you allow "low impact" permissions (User.Read) without admin consent?
Checklist
- Consent Settings: Set to "Do not allow user consent".
- Admin Workflow: Configure reviewers and email notifications.
- Secret Expiry: Scan for non-expiring secrets.
- Owners: Ensure all apps have at least 2 active owners.
- Cleanup: Delete apps with no sign-ins for 180 days (soft delete first).
- Integration: Connect App Registrations to Defender for Cloud Apps for visibility.
- Permissions: Review all apps with
Applicationpermissions (not Delegated).
