Query Details

Az ADSPI Enriched By Entra Ops

Query

id: 571107c2-5abe-49ff-9867-445805502add
Function:
  Title: Parser for AzADServicePrincipalInsights with enriched classification of EntraOps
  Version: '1.0.0'
  LastUpdated: '2023-11-11'
Category: Microsoft Sentinel Parser
FunctionName: PrivilegedAzADSPI
FunctionAlias: PrivilegedAzADSPI
FunctionQuery: |
    let SensitiveMsGraphPermissions = externaldata(EAMTierLevelName: string, Category: string, AppRoleDisplayName: string)["https://raw.githubusercontent.com/Cloud-Architekt/AzurePrivilegedIAM/main/Classification/Classification_AppRoles.json"] with(format='multijson');
    let SensitiveAadDirectoryRoles = externaldata(Classification: string, RolePermissions: string, Category: string, RoleId: string)["https://raw.githubusercontent.com/Cloud-Architekt/AzurePrivilegedIAM/main/Classification/Classification_EntraIdDirectoryRoles.json"] with(format='multijson') | mv-expand parse_json(RolePermissions)
    | summarize Category = make_list(RolePermissions.Category) by AadDirectoryRoleId = RoleId, AadDirectoryRoleTierLevel = tostring(parse_json(Classification).EAMTierLevelName);
    let SpWithAppRole = AzADServicePrincipalInsights_CL
    | where TimeGenerated > ago(14d)
    | summarize arg_max(TimeGenerated, *) by ObjectId
    | mv-expand parse_json(SPAppRoleAssignments)
    | mv-expand SPAppRoleAssignments.AppRolePermission
    | extend AppRolePermission = tostring(SPAppRoleAssignments_AppRolePermission) 
    | extend SPObjectId = tostring(parse_json(SP)[0].SPObjectId)
    | join kind=leftouter(
        SensitiveMsGraphPermissions | project AppRolePermissionTierLevel = EAMTierLevelName, AppRolePermission = AppRoleDisplayName, Category
        ) on AppRolePermission
    | where isnotempty(AppRolePermission)
    | summarize AppRolePermissions = make_set(AppRolePermission), AppRolePermissionTierLevels = make_set(AppRolePermissionTierLevel) by SPObjectId;
    let SpWithDirectoryRole = AzADServicePrincipalInsights_CL
    | where TimeGenerated > ago(14d)
    | summarize arg_max(TimeGenerated, *) by ObjectId
    | mv-expand parse_json(SPAADRoleAssignments)
    | mv-expand SPAADRoleAssignments.roleDefinitionName, SPAADRoleAssignments.roleDefinitionId
    | extend AadDirectoryRoleId = tostring(SPAADRoleAssignments_roleDefinitionId)
    | extend AadDirectoryRoleName = tostring(SPAADRoleAssignments_roleDefinitionName)
    | extend SPObjectId = tostring(parse_json(SP)[0].SPObjectId)
    | join kind=leftouter(
        SensitiveAadDirectoryRoles
        ) on AadDirectoryRoleId
    | where isnotempty(AadDirectoryRoleName)
    | summarize AadDirectoryRoles = make_set(AadDirectoryRoleName), AadDirectoryRoleTierLevels = make_set(AadDirectoryRoleTierLevel) by SPObjectId;
    AzADServicePrincipalInsights_CL
    | where TimeGenerated > ago(14d)
    | summarize arg_max(TimeGenerated, *) by ObjectId
    | extend AppObjectId = tostring(parse_json(APP)[0].APPObjectId)
    | extend SPObjectId = tostring(parse_json(SP)[0].SPObjectId)
    | join kind=leftouter (
        union SpWithAppRole, SpWithDirectoryRole
        | summarize AppRolePermissions = make_set(AppRolePermissions), AppRolePermissionTierLevels = make_set(AppRolePermissionTierLevels), AadDirectoryRoles = make_set(AadDirectoryRoles), AadDirectoryRoleTierLevels = make_set(AadDirectoryRoleTierLevels) by SPObjectId
        ) on SPObjectId
    | extend Classification = iif((AppRolePermissionTierLevels contains "ControlPlane" or AadDirectoryRoleTierLevels contains "ControlPlane"), "ControlPlane", "Unclassified")
    | extend Classification = iif((Classification == "Unclassified" and (AppRolePermissionTierLevels contains "ManagementPlane" or AadDirectoryRoleTierLevels contains "ManagementPlane")), "ManagementPlane", Classification)
    | extend Classification = iif((Classification == "Unclassified" and (AppRolePermissionTierLevels contains "WorkloadPlane" or AadDirectoryRoleTierLevels contains "WorkloadPlane")), "WorkloadPlane", Classification)
    | extend Classification = iif((Classification == "Unclassified" and (AppRolePermissionTierLevels contains "UserAccess" or AadDirectoryRoleTierLevels contains "UserAccess")), "UserAccess", Classification)
    | extend WorkloadIdentityType = iff(ObjectType contains "SP MI", "ManagedIdentity", "Application")
    | project 
        WorkloadIdentityName = tostring(parse_json(SP)[0].SPDisplayName),
        WorkloadIdentityType,
        ServicePrincipalObjectId = SPObjectId,
        ServicePrincipalOwners = SPOwners,
        ServicePrincipalType = ObjectType,
        ApplicationObjectId = AppObjectId,
        ApplicationId = tostring(parse_json(SP)[0].SPAppId),
        ApplicationOwners = APPAppOwners,
        EntraIdRoles = AadDirectoryRoles,
        EntraGroupMemberships = APPAppOwners,
        AppRolePermissions,
        AzureRoles = SPAzureRoleAssignments,
        ManagedIdentityAssociatedAzureResources,
        ManagedIdentityFederatedIdentityCredentials,        
        EnterpriseAccessModelTiering = Classification

Explanation

This KQL query is designed to analyze and classify Azure Active Directory (AAD) service principals based on their roles and permissions. Here's a simplified breakdown of what the query does:

  1. Data Sources:

    • It pulls in external data about sensitive Microsoft Graph permissions and AAD directory roles from JSON files hosted on GitHub. These files contain classifications and categories for various roles and permissions.
  2. Service Principal Insights:

    • The query examines service principal insights from the AzADServicePrincipalInsights_CL table, focusing on records generated in the last 14 days.
  3. Role and Permission Analysis:

    • It identifies service principals with specific application roles and directory roles by expanding and parsing role assignments.
    • It joins this information with the external data to enrich the service principals with classification details based on their roles and permissions.
  4. Classification:

    • Service principals are classified into different tiers: "ControlPlane", "ManagementPlane", "WorkloadPlane", or "UserAccess", based on their role permissions and directory roles.
    • The classification is hierarchical, meaning if a service principal has roles in multiple tiers, it is classified into the highest tier present.
  5. Output:

    • The query projects a set of attributes for each service principal, including its name, type (Managed Identity or Application), object IDs, owners, roles, permissions, and the determined classification tier.
    • This output provides a comprehensive view of each service principal's identity and access model, helping to identify potentially sensitive or privileged identities within Azure Active Directory.

Overall, this query is used to enhance security monitoring by classifying service principals based on their access levels and roles, aiding in the identification of privileged identities within an organization's Azure environment.

Details

Thomas Naunheim profile picture

Thomas Naunheim

Released: November 23, 2023

Tables

AzADServicePrincipalInsights_CL

Keywords

MicrosoftSentinelParserAzureServicePrincipalInsightsEntraOpsPrivilegedIAMDirectoryRolesAppManagedIdentityApplicationResourcesEnterpriseAccessModelTiering

Operators

letexternaldatawithformatmv-expandparse_jsonsummarizemake_listbytostringwhereagoarg_maxextendjoinkindprojectisnotemptymake_setunioncontainsiififf

Actions

GitHub