Query Details

Added App Roles With Classification

Query

// Added API Permissions with enriched classification from EntraOps Privileged EAM
// Modified version from "Admin promotion after Role Management Application Permission Grant" (f80d951a-eddc-4171-b9d0-d616bb83efdc) and "Service Principal Assigned App Role With Sensitive Access" (dd78a122-d377-415a-afe9-f22e08d2112c) from Microsoft Sentinel Repo
let SensitiveMsGraphPermissions = externaldata(AppRoleDisplayName: string, AppRoleId: string, AppId: string, EAMTierLevelName: string, Category: string)["https://raw.githubusercontent.com/Cloud-Architekt/AzurePrivilegedIAM/main/Classification/Classification_MsGraphAppRoles.json"] with(format='multijson');
AuditLogs
| where TimeGenerated >ago(90d)
| where LoggedByService =~ "Core Directory"
| where Category =~ "ApplicationManagement"
| where AADOperationType =~ "Assign"  
| where OperationName == "Add app role assignment to service principal"
| where Result =~ "success"
| mv-expand TargetResources
| mv-expand TargetResources.modifiedProperties
| extend ModifiedProperty = tostring(TargetResources_modifiedProperties.displayName)
| where ModifiedProperty =~ "AppRole.Value"
| extend AppRole = tostring(parse_json(tostring(TargetResources_modifiedProperties.newValue)))
| extend InitiatingUserOrApp = iff(isnotempty(InitiatedBy.user.userPrincipalName),tostring(InitiatedBy.user.userPrincipalName), tostring(InitiatedBy.app.displayName))
| extend InitiatingUserOrAppId = iff(isnotempty(InitiatedBy.user.id),tostring(InitiatedBy.user.id), tostring(InitiatedBy.app.id))
| extend InitiatingIpAddress = iff(isnotempty(InitiatedBy.user.ipAddress), tostring(InitiatedBy.user.ipAddress), tostring(InitiatedBy.app.ipAddress))
| extend UserAgent = iff(AdditionalDetails[0].key == "User-Agent",tostring(AdditionalDetails[0].value),"")
| extend AddedPermission = replace_string(tostring(TargetResources_modifiedProperties.newValue),'"','')
| join kind=inner ( SensitiveMsGraphPermissions | project AddedPermissionClassification = EAMTierLevelName, AddedPermissionCategory = Category, AppRoleDisplayName ) on $left.AddedPermission == $right.AppRoleDisplayName
| mv-expand TargetResources.modifiedProperties | where TargetResources_modifiedProperties.displayName == "ServicePrincipal.ObjectID" | extend ServicePrincipalObjectID = replace_string(tostring(TargetResources_modifiedProperties.newValue),'"','')
| mv-expand TargetResources.modifiedProperties | where TargetResources_modifiedProperties.displayName == "ServicePrincipal.DisplayName" | extend ServicePrincipalDisplayName = replace_string(tostring(TargetResources_modifiedProperties.newValue),'"','')
| mv-expand TargetResources.modifiedProperties | where TargetResources_modifiedProperties.displayName == "ServicePrincipal.AppId" | extend ServicePrincipalAppId = replace_string(tostring(TargetResources_modifiedProperties.newValue),'"','')
| project-reorder OperationName, ServicePrincipalObjectID, ServicePrincipalDisplayName, ServicePrincipalAppId, InitiatingUserOrApp, InitiatingUserOrAppId, InitiatingIpAddress, UserAgent, AddedPermission, AddedPermissionClassification, AddedPermissionCategory

Explanation

This KQL (Kusto Query Language) query is designed to analyze audit logs to identify and classify sensitive permissions added to service principals in Azure Active Directory. Here's a simplified breakdown of what the query does:

  1. Load Sensitive Permissions Data: It starts by loading a JSON file from a GitHub repository that contains information about sensitive Microsoft Graph permissions, including their classification and category.

  2. Filter Audit Logs: The query then filters audit logs from the past 90 days, focusing on logs related to application management operations performed by the "Core Directory" service. Specifically, it looks for successful operations where an app role was assigned to a service principal.

  3. Extract and Process Data:

    • It expands the details of the target resources and their modified properties to extract relevant information.
    • It identifies the user or application that initiated the operation, along with their ID and IP address.
    • It captures the user agent string if available.
  4. Match and Classify Permissions:

    • The query matches the added permissions with the sensitive permissions data loaded earlier.
    • It classifies the added permissions based on their sensitivity level and category.
  5. Extract Service Principal Details:

    • It extracts the object ID, display name, and app ID of the service principal to which the permissions were added.
  6. Reorder and Present Results: Finally, the query organizes the results to display key information such as the operation name, service principal details, initiating user or app details, and the classification of the added permissions.

Overall, this query helps in identifying and understanding the context of sensitive permissions being assigned to service principals, which is crucial for security monitoring and compliance in Azure environments.

Details

Thomas Naunheim profile picture

Thomas Naunheim

Released: June 8, 2026

Tables

AuditLogs

Keywords

ApiPermissionsEntraOpsEAMAdminRoleManagementApplicationPermissionGrantServicePrincipalMicrosoftSentinelAuditLogsTimeGeneratedCoreDirectoryApplicationManagementAADOperationTypeOperationNameResultTargetResourcesModifiedPropertyAppRoleInitiatingUserOrAppInitiatingUserOrAppIdInitiatingIpAddressUserAgentAddedPermissionSensitiveMsGraphPermissionsAddedPermissionClassificationAddedPermissionCategoryAppRoleDisplayNameServicePrincipalObjectIDServicePrincipalDisplayNameServicePrincipalAppId

Operators

letexternaldatawith|where=~==mv-expandextendtostringparse_jsoniffisnotemptyreplace_stringjoinkind=innerprojectproject-reorder

Actions

GitHub