Listen to this Post

Introduction:
Managed identities in Microsoft Entra ID (formerly Azure AD) eliminate the need for developers to manage credentials, but assigning the correct Graph API permissions to these identities remains a tedious, parameter-heavy process. Without a streamlined approach, administrators often grant excessive privileges or misconfigure access, creating silent security gaps. Jan Bakker and Michael Morten Sonne have released open-source tools – including a web-based manager at `https://managedidentity.tech/` and a PowerShell-driven utility on GitHub – that simplify this task, yet understanding the underlying commands and hardening techniques is critical to avoid introducing new risks.
Learning Objectives:
- Automate assignment of Microsoft Graph API permissions to managed identities using community tools and native Azure CLI/PowerShell.
- Identify common misconfigurations that lead to privilege escalation in Entra ID environments.
- Implement least-privilege auditing and monitoring for managed identities using Azure Monitor and Log Analytics.
You Should Know:
- Understanding Managed Identities and Why Graph Permissions Are Painful
Managed identities are Azure service principals that automatically rotate credentials, but they lack a traditional user interface for granting Graph API scopes (e.g., Mail.Read, User.Read.All). Instead, you must navigate Azure RBAC, app registrations, and API permissions – a process that requires up to 12 different parameters. The tools mentioned (https://managedidentity.tech/` and `https://github.com/michaelmsonne/ManagedIdentityPermissionManager`) abstract this complexity by generating the required JSON payloads and executing `az rest or `Invoke-MgGraphRequest` commands under the hood.
Step‑by‑step to manually inspect current permissions (Linux/Windows – Azure CLI):
Login and set subscription az login az account set --subscription "YOUR_SUBSCRIPTION_ID" Get managed identity principal ID az identity list --resource-group "RG_NAME" --query "[].principalId" -o tsv Query Graph API for app role assignments (requires consented Graph API permission) az rest --method GET --uri "https://graph.microsoft.com/v1.0/servicePrincipals/<PRINCIPAL_ID>/appRoleAssignments" --headers "Content-Type=application/json"
If you see broad roles like `Application.ReadWrite.All` or Directory.ReadWrite.All, you may be over-privileged.
- Deploying the Managed Identity Graph Permissions Manager (Two Approaches)
Option A – Web tool (no install):
Navigate to https://managedidentity.tech/`. Authenticate with a delegated token (requires `Application.ReadWrite.All` and `AppRoleAssignment.ReadWrite.All` consented for your user). Select the target managed identity, choose Graph API permissions (e.g.,GroupMember.Read.All`), and the tool generates an ARM template or PowerShell script.
Option B – GitHub PowerShell module (more control):
Clone and import (Windows PowerShell 7+ or Linux pwsh) git clone https://github.com/michaelmsonne/ManagedIdentityPermissionManager.git cd ManagedIdentityPermissionManager Import-Module ./ManagedIdentityPermissionManager.psm1 Connect to Microsoft Graph (requires appropriate admin consent) Connect-MgGraph -Scopes "AppRoleAssignment.ReadWrite.All", "Application.Read.All" Add a Graph permission to a specific managed identity Add-MgGraphPermissionToManagedIdentity -ManagedIdentityName "myVMIdentity" -GraphPermission "User.Read.All" -ResourceGroup "RG_NAME"
The function internally calls `New-MgServicePrincipalAppRoleAssignment`. Verify with:
Get-MgServicePrincipalAppRoleAssignment -ServicePrincipalId "<MANAGED_ID_OBJECT_ID>"
- Manual Hardening: Native Azure CLI & PowerShell for Least Privilege
Instead of blindly trusting any tool, you should understand the native commands to audit changes. Below are verified commands to assign a specific Graph permission (e.g., Mail.Send) to a managed identity using Azure CLI on Linux/Windows:
Retrieve the managed identity service principal object ID
SP_ID=$(az identity show --name "IDENTITY_NAME" --resource-group "RG_NAME" --query principalId -o tsv)
Retrieve the Graph API service principal ID (fixed value for Microsoft Graph)
GRAPH_SP_ID="00000003-0000-0000-c000-000000000000"
Retrieve the app role ID for "Mail.Send" (requires jq)
ROLE_ID=$(az rest --method GET --uri "https://graph.microsoft.com/v1.0/servicePrincipals/$GRAPH_SP_ID/appRoles" --headers "Content-Type=application/json" | jq -r '.value[] | select(.value=="Mail.Send") | .id')
Assign the role to the managed identity
az rest --method POST --uri "https://graph.microsoft.com/v1.0/servicePrincipals/$SP_ID/appRoleAssignments" --body "{\"principalId\":\"$SP_ID\",\"resourceId\":\"$GRAPH_SP_ID\",\"appRoleId\":\"$ROLE_ID\"}"
Why this matters: Manually constructing the request reduces the risk of the tool miscopying IDs. Always test in a non-production tenant first.
4. Detecting Over-Permissioned Managed Identities with Azure Monitor
After using automation tools, you must continuously validate assignments. Deploy a Log Analytics query to flag identities with `Application.ReadWrite.All` or `RoleManagement.ReadWrite.Directory` – both are high-impact permissions.
Step‑by‑step to set up auditing (Azure Portal):
- Navigate to Monitor → Diagnostic settings for your managed identity’s resource (VM, Function App, etc.).
- Send AuditLogs and SignInLogs to a Log Analytics workspace.
- Run the following KQL query to detect risky Graph API role assignments:
AuditLogs | where OperationName == "Add app role assignment to service principal" | extend Target = tostring(TargetResources[bash].id) | where Target contains "/servicePrincipals/" | extend RoleId = tostring(AdditionalDetails[bash].value) | join kind=inner ( // Fetch role names from a known list (simplified) datatable(RoleId:string, RoleName:string) ["00000000-0000-0000-0000-000000000001", "Application.ReadWrite.All"], ["00000000-0000-0000-0000-000000000002", "RoleManagement.ReadWrite.Directory"] ) on RoleId | project TimeGenerated, InitiatedBy, Target, RoleName
Set alerts when `RoleManagement.ReadWrite.Directory` appears – this could allow an attacker with control over the managed identity to elevate to Global Admin.
5. Mitigation: Revoke Dangerous Permissions via PowerShell
If you discover that an automated tool assigned overly broad permissions (e.g., Directory.ReadWrite.All), revoke immediately:
List all app role assignments for the compromised managed identity
$assignments = Get-MgServicePrincipalAppRoleAssignment -ServicePrincipalId "$SP_ID"
Find the assignment ID for the dangerous role (e.g., Directory.ReadWrite.All)
$badAssignment = $assignments | Where-Object { $_.AppRoleId -eq "GUID_OF_DIRECTORY_READWRITE_ALL" }
Remove it
Remove-MgServicePrincipalAppRoleAssignment -ServicePrincipalId "$SP_ID" -AppRoleAssignmentId $badAssignment.Id
Windows/Linux cross-platform note: The Microsoft Graph PowerShell SDK works on both. Install via Install-Module Microsoft.Graph -Scope CurrentUser.
6. Infrastructure as Code (IaC) for Reproducible Hardening
Manual one-click tools are risky for production. Instead, define managed identity permissions declaratively using Bicep or Terraform, referencing the community tool’s output as a starting point.
Bicep example (assign Graph permission to a managed identity):
resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' existing = {
name: 'myIdentity'
}
resource graphSp 'Microsoft.Graph/servicePrincipals' existing = {
// Not native to Bicep – requires AzApi provider
// Use AzApi to create appRoleAssignment
}
More robust is to use the `microsoft.graph/appRoleAssignments` resource via the AzApi Bicep provider – a technique the community tools can generate for you. This prevents drift and enables peer review.
7. Future-Proofing: Conditional Access for Managed Identities
Microsoft is gradually introducing Conditional Access for workload identities. To prepare, ensure your managed identities are not excessively privileged today. Use the following script to generate a risk report across all subscriptions:
!/bin/bash Linux/Windows (WSL) – enumerate all managed identities and their Graph roles for id in $(az identity list --query "[].principalId" -o tsv); do echo "Checking $id" az rest --method GET --uri "https://graph.microsoft.com/v1.0/servicePrincipals/$id/appRoleAssignments" --query "value[].appRoleId" -o tsv done | sort | uniq -c
Redirect output to a CSV and review each role ID against Microsoft’s Graph permission reference (https://learn.microsoft.com/en-us/graph/permissions-reference). Any identity with more than 3 high-impact permissions should be re-architected.
What Undercode Say:
- Key Takeaway 1: Tools like `managedidentity.tech` and the GitHub PowerShell module dramatically reduce human error when assigning Graph API permissions, but they are not a substitute for manual validation using native Azure CLI and Graph API queries.
- Key Takeaway 2: Over-privileged managed identities are a silent vector for lateral movement – an attacker who compromises a VM with `RoleManagement.ReadWrite.Directory` can escalate to tenant admin without ever entering a password.
Analysis: The rise of AI‑generated tools (even Copilot‑assisted scripts) accelerates configuration but also obscures the underlying security boundaries. While no password was given in the original post, the real risk lies in assuming a one‑time permission assignment is permanent and harmless. Organizations must implement continuous auditing (Log Analytics), least‑privilege IaC templates, and workload‑identity Conditional Access previews. The community tools are excellent for learning and testing, but production hardening still demands a deep understanding of Entra ID’s app role assignment model and the strict use of `-WhatIf` flags.
Prediction:
Within 18 months, Microsoft will natively integrate a “Graph permission manager” into the Entra admin center for managed identities, heavily inspired by these community tools. However, this will also lead to a new wave of misconfigurations as companies rapidly assign permissions without proper review. Attackers will shift focus from stealing passwords to compromising managed identities with overly broad Graph roles – making automated detection (e.g., using the KQL query above) a standard SOC playbook in 2026. The only defense is not just automation, but automation paired with immutable audit trails and time‑bound, just‑in-time permissions for workload identities.
▶️ Related Video (70% Match):
🎯Let’s Practice For Free:
IT/Security Reporter URL:
Reported By: Jan Bakker – Hackers Feeds
Extra Hub: Undercode MoN
Basic Verification: Pass ✅


