Query Details
// Early draft: List of Directory Roles including known attack paths (defined by Emilien Socchi repository: https://github.com/emiliensocchi/azure-tiering/blob/main/Entra%20roles/tiered-entra-roles.json), classification by EntraOps, categories and rich details by Graph API and their role members with flags for Guest, Risky User and count of role members from IdentityInfo. let SensitiveEntraDirectoryRoles = externaldata(RoleName: string, RoleId: string, Categories: string, RichDescription: string, isPrivileged: bool, Classification: dynamic, RolePermissions:dynamic)["https://raw.githubusercontent.com/Cloud-Architekt/AzurePrivilegedIAM/main/Classification/Classification_EntraIdDirectoryRoles.json"] with(format='multijson') | where Classification.EAMTierLevelName != "Unclassified" | mv-expand RolePermissions | extend Categories = split(Categories,',') | summarize EntraOpsCategory = make_set(RolePermissions.Category), Categories = make_set(Categories) by RoleName, RoleId, isPrivileged, EntraOpsClassification = tostring(Classification.EAMTierLevelName), RichDescription; let KnownAttackPaths = externaldata(id: string, pathType: string, knownShortestPath: string, example: string)["https://raw.githubusercontent.com/emiliensocchi/azure-tiering/main/Entra%20roles/tiered-entra-roles.json"] with(format='multijson') | where isnotempty(knownShortestPath) or isnotempty(example) | project-rename RoleId = id, AttackPathType = pathType, ShortestAttackPath = knownShortestPath, AttackPathExample = example; let PrivilegedUsers = IdentityInfo | where TimeGenerated > ago(14d) | summarize arg_max(TimeGenerated, *) by AccountObjectId | mv-expand AssignedRoles | extend RoleName = tostring(AssignedRoles); SensitiveEntraDirectoryRoles | join kind=inner ( PrivilegedUsers ) on RoleName | extend RoleAssignment = bag_pack_columns(AccountName, AccountUPN, UserType, Tags, IsAccountEnabled, RiskState) | summarize RoleMembers = count(), RoleAssignments = make_list(RoleAssignment), RiskState = make_list(RiskState), UserType = make_list(UserType) by RoleName, RoleId, tostring(Categories), tostring(EntraOpsCategory), isPrivileged, tostring(EntraOpsClassification), tostring(RichDescription) | extend RiskyAdmins = iff(RiskState has "atRisk", true, false) | extend GuestAsAdmins = iff(UserType has "Guest", true, false) | project-reorder RiskState, RoleName, RichDescription, EntraOpsClassification, isPrivileged, EntraOpsCategory,Categories, RoleMembers, RoleAssignments | sort by RoleName asc | join kind=inner ( KnownAttackPaths) on RoleId | project-away RiskState, UserType, RoleId1 // Filter for risky or external users only | where RiskyAdmins = true or GuestAsAdmins == true
This query is designed to generate a comprehensive list of sensitive directory roles in an Azure environment, enriched with various details and classifications. Here's a simplified breakdown of what the query does:
Load Sensitive Directory Roles: It fetches a list of directory roles from an external JSON file, including details like role name, ID, categories, descriptions, and classifications.
Filter and Expand Roles: It filters out unclassified roles and expands the role permissions to categorize them.
Load Known Attack Paths: It fetches known attack paths for these roles from another external JSON file, renaming and projecting relevant fields.
Fetch Privileged Users: It retrieves information about privileged users from the IdentityInfo table, focusing on users who have been active in the last 14 days.
Join Roles with Users: It joins the directory roles with the privileged users, creating a detailed list of role assignments, including flags for risky users and guest users.
Summarize and Extend Data: It summarizes the data to count role members and includes additional flags for risky admins and guest admins.
Filter and Sort: Finally, it filters the results to include only roles with risky or guest admins and sorts the list by role name.
In essence, the query provides a detailed and filtered list of sensitive directory roles, highlighting those with potential security risks due to the presence of risky or guest users.

Thomas Naunheim
Released: August 8, 2024
Tables
Keywords
Operators