Query Details
// This query can help you to detect Azure RBAC role assignments.
//
// Click "Save as function", in Parameters write in the fields:
// "timespan" "query_frequency" "1d"
//
// If you name the function "AzureRBACRoleAssignments", you can check the function with queries like the following:
//
// AzureRBACRoleAssignments()
//
// AzureRBACRoleAssignments(1h)
//
//let query_frequency = 1d;
//let Function = (query_frequency:timespan = 1d){
let query_period = 14d;
let _PIM_ids = toscalar(
_GetWatchlist("Activity-ExpectedSignificantActivity")
| where Activity == "PrivilegedIdentityManagement" and Notes has "[App]"
| summarize make_list(ActorId)
);
let _PrivAzureRBACRoles = toscalar(
_GetWatchlist("RegEx-PrivAzureRBACRoles")
| summarize RegEx = make_list(RegEx)
| extend RegEx = strcat(@'^(', strcat_array(RegEx, '|'), @')$')
);
let _Users =
IdentityInfo
| where TimeGenerated > ago(query_period)
| summarize arg_max(TimeGenerated, *) by AccountObjectId
| project-away TimeGenerated
;
let _AADApps = _GetWatchlist("UUID-AADApps");
let _Groups = _GetWatchlist("UUID-AADGroups");
let _AzureSubscriptions = _GetWatchlist("UUID-AzureSubscriptions");
let _AzureRBACRoles = _GetWatchlist("UUID-AzureRBACRoles");
let _ResourceManagementPIM = materialize(
AuditLogs
| where TimeGenerated > ago(query_frequency)
| where Category == "ResourceManagement" and LoggedByService == "PIM" and AADOperationType matches regex "Role" and not(AADOperationType == "CreateRoleUpdateRequest")
| mv-apply AdditionalDetail = AdditionalDetails on (
summarize ParsedAdditionalDetails = make_bag(pack(tostring(AdditionalDetail["key"]), tostring(AdditionalDetail["value"])))
)
// | mv-apply TargetResource = TargetResources on (
// summarize TargetResourcesTypes = make_list(tostring(TargetResource["type"]))
// )
| mv-apply TargetResource = TargetResources on (
summarize TargetResource = make_list(TargetResource) by TargetResourceType = tostring(TargetResource["type"])
| extend TargetResource = iff(array_length(TargetResource) == 1, TargetResource[0], TargetResource)
| summarize ParsedTargetResources = make_bag(pack(TargetResourceType, TargetResource))
)
| project
TimeGenerated,
LoggedByService,
Category,
AADOperationType,
OperationName,
Result,
ResultReason,
ActivateOperation = OperationName has_any ("activation", "deactivate"),
EligibleOperation = OperationName has "eligible",
RemoveOperation = OperationName has "remove",
PermanentOperation = OperationName has "permanent",
// Information about the actor
ActorIdentity = Identity,
// Information about the actor, if it was a user
ActorUserId = tostring(InitiatedBy["user"]["id"]),
ActorUserPrincipalName = tolower(tostring(InitiatedBy["user"]["userPrincipalName"])),
ActorUserIPAddress = tostring(InitiatedBy["user"]["ipAddress"]),
ActorUserRoles = tostring(InitiatedBy["user"]["roles"]),
// Information about the actor, if it was an application
ActorAppName = tostring(InitiatedBy["app"]["displayName"]),
ActorAppId = tostring(InitiatedBy["app"]["appId"]),
ActorAppServicePrincipalName = tostring(InitiatedBy["app"]["servicePrincipalName"]),
ActorAppServicePrincipalId = tostring(InitiatedBy["app"]["servicePrincipalId"]),
// Information about the role
RoleProvider = tostring(ParsedTargetResources["Provider"]["displayName"]),
//RoleDefinitionOriginType = tostring(ParsedAdditionalDetails["RoleDefinitionOriginType"]),
TargetRoleName = tostring(TargetResources[0]["displayName"]),
TargetRoleTemplateId = tostring(ParsedAdditionalDetails["TemplateId"]),
// Information about the targets
TargetManagementGroupId = tostring(ParsedTargetResources["managementgroup"]["id"]),
TargetManagementGroupName = tostring(ParsedTargetResources["managementgroup"]["displayName"]),
TargetSubscriptionId = extract(@"\/subscriptions\/([^\/]+)\/", 1, tostring(ParsedAdditionalDetails["RoleDefinitionOriginId"])),
TargetSubscriptionName = tostring(ParsedTargetResources["subscription"]["displayName"]),
TargetGroupName = tostring(ParsedTargetResources["Group"]["displayName"]),
TargetGroupId = tostring(ParsedTargetResources["Group"]["id"]),
TargetUserPrincipalName = tostring(ParsedTargetResources["User"]["userPrincipalName"]),
TargetUserId = tostring(ParsedTargetResources["User"]["id"]),
// JSONs containers
InitiatedBy,
AdditionalDetails,
TargetResources,
RequestId = iff(isempty(array_length(ParsedTargetResources["Request"])), tostring(ParsedTargetResources["Request"]["id"]), tostring(ParsedTargetResources["Request"][0]["id"])),
RoleScheduleId = iff(isempty(array_length(ParsedTargetResources["Request"])), tostring(ParsedTargetResources["RoleSchedule"]["id"]), tostring(ParsedTargetResources["Request"][1]["id"])),
CorrelationId,
Type
| extend
Caller = coalesce(ActorUserPrincipalName, ActorUserId, ActorAppServicePrincipalId),
CallerDisplayName = ActorIdentity,
CallerIpAddress = coalesce(ActorUserIPAddress, ""),
TargetId = coalesce(TargetUserId, TargetGroupId),
Target = coalesce(TargetUserPrincipalName, TargetGroupName),
SourceSystem = LoggedByService
| summarize
StartTime = min(TimeGenerated),
EndTime = max(TimeGenerated),
RequestedTimeGenerated = make_list_if(TimeGenerated, OperationName has "requested"),
CompletedTimeGenerated = make_list_if(TimeGenerated, not(OperationName has "requested") and Result == "success"),
RequestedCount = countif(OperationName has "requested"),
CompletedCount = countif(not(OperationName has "requested") and Result == "success"),
arg_max(TimeGenerated, *)
by CorrelationId, EligibleOperation, RemoveOperation, PermanentOperation, TargetManagementGroupId, TargetSubscriptionId, TargetRoleTemplateId, TargetGroupName, TargetUserPrincipalName, TargetUserId
| extend
RequestedTimeGenerated = iff(array_length(RequestedTimeGenerated) == 0, dynamic(null), RequestedTimeGenerated),
RequestedCount = iff(RequestedCount == 0, int(null), RequestedCount)
);
let _RoleAssignmentsAzure = materialize(
AzureActivity
| where TimeGenerated > ago(query_frequency)
| where ResourceProviderValue =~ "Microsoft.Authorization" and OperationNameValue has_any ("roleAssignments")
| extend PreferenceInteger = case(
ResourceProviderValue == "Microsoft.Authorization", 1,
ResourceProviderValue == "MICROSOFT.AUTHORIZATION", 0,
-1
)
// Group together Start, Accept, Success... operations
| summarize hint.shufflekey=CorrelationId
StartTime = min(TimeGenerated),
EndTime = max(TimeGenerated),
PropertiesDynamic = make_bag(pack(ActivityStatusValue, iff(PreferenceInteger == 1, todynamic(Properties), Properties_d))),
EventDataId = array_sort_asc(make_list(EventDataId)),
arg_max(TimeGenerated, *)
by CorrelationId, ResourceProviderValue, OperationNameValue, _ResourceId
| project-away EventDataId1
// Group together two kinds of logs (where ResourceProviderValue is all caps or title - MICROSOFT.AUTHORIZATION or Microsoft.Authorization)
| summarize hint.shufflekey=CorrelationId
PropertiesDynamic = make_bag(pack(ResourceProviderValue, PropertiesDynamic)),
EventDataId = make_bag(pack(ResourceProviderValue, EventDataId)),
take_any(TenantId, SourceSystem, CategoryValue, SubscriptionId, Type),
arg_min(PreferenceInteger, CallerIpAddress, Authorization, Authorization_d, Claims_d, Properties_d, EventSubmissionTimestamp, Hierarchy),
arg_max(PreferenceInteger, Level, OperationNameValue, Caller, HTTPRequest, OperationId, ResourceGroup, ResourceProviderValue, ActivityStatusValue, ActivitySubstatusValue, OperationName, ActivityStatus, ActivitySubstatus, Category, ResourceId, ResourceProvider, Resource)
by CorrelationId, TimeGenerated, StartTime, EndTime, _ResourceId
| project-away PreferenceInteger*
// Add origin events of operations (if a resource group is deleted, it might trigger a role assignment delete operation)
| join kind=leftouter (
AzureActivity
| where TimeGenerated > ago(query_frequency)
| where OperationNameValue has "/delete" and not(OperationNameValue has_any ("roleAssignments")) and ActivityStatusValue in ("Start", "Started")
| summarize take_any(*) by EventDataId
| extend StartOperationNameValue = coalesce(tostring(Properties_d["message"]), OperationNameValue), Start_HTTPRequest = HTTPRequest
| summarize arg_min(TimeGenerated, StartOperationNameValue, Start_HTTPRequest) by CorrelationId, Auxiliar = tolower(StartOperationNameValue)
| project-away TimeGenerated, Auxiliar
) on CorrelationId
| project-away CorrelationId1
| join kind=leftouter (
AzureActivity
| where TimeGenerated > ago(query_frequency)
| where OperationNameValue has "/delete" and not(OperationNameValue has_any ("roleAssignments")) and not(ActivityStatusValue in ("Start", "Started"))
| summarize take_any(*) by EventDataId
| extend GroupOperationNameValue = coalesce(tostring(Properties_d["message"]), OperationNameValue), Group_ResourceId = _ResourceId, Group_HTTPRequest = HTTPRequest
| summarize arg_min(TimeGenerated, GroupOperationNameValue, Group_HTTPRequest) by CorrelationId, Auxiliar = tolower(GroupOperationNameValue), Group_ResourceId
| project-away TimeGenerated, Auxiliar
) on CorrelationId
| project-away CorrelationId1
| where not(isnotempty(GroupOperationNameValue) and (not(_ResourceId contains Group_ResourceId) or _ResourceId == Group_ResourceId))
| extend OriginOperationNameValue = coalesce(StartOperationNameValue, GroupOperationNameValue, tostring(PropertiesDynamic["MICROSOFT.AUTHORIZATION"]["Start"]["message"]), tostring(PropertiesDynamic["Microsoft.Authorization"]["Start"]["message"]))
| extend OriginOperationNameValue = iff(OperationNameValue =~ OriginOperationNameValue, "", OriginOperationNameValue)
| project-away StartOperationNameValue, GroupOperationNameValue, Group_ResourceId
// Start coalescing fields
| extend
Caller = tolower(Caller),
AllCapsPropertiesDynamic = coalesce(PropertiesDynamic["MICROSOFT.AUTHORIZATION"]["Start"], PropertiesDynamic["MICROSOFT.AUTHORIZATION"]["Success"]),
TitlePropertiesDynamic = coalesce(PropertiesDynamic["Microsoft.Authorization"]["Started"], PropertiesDynamic["Microsoft.Authorization"]["Succeeded"])
| extend
ResourceId = coalesce(ResourceId, tostring(AllCapsPropertiesDynamic["entity"])),
Category = coalesce(Category, tostring(AllCapsPropertiesDynamic["eventCategory"])),
OperationNameValue = coalesce(tostring(AllCapsPropertiesDynamic["message"]), OperationNameValue),
ResourceProvider = coalesce(ResourceProvider, tostring(split(tostring(AllCapsPropertiesDynamic["message"]), "/")[0])),
Resource = coalesce(
Resource,
replace_regex(tostring(AllCapsPropertiesDynamic["resource"]), @"([a-f0-9]{8})([a-f0-9]{4})([a-f0-9]{4})([a-f0-9]{4})([a-f0-9]{12})", @"\1-\2-\3-\4-\5")
),
TargetResourceGroup = coalesce(tostring(split(split(tostring(AllCapsPropertiesDynamic["entity"]), "/resourceGroups/")[1], "/")[0]), ResourceGroup),
HTTPRequest = coalesce(HTTPRequest, tostring(AllCapsPropertiesDynamic["httpRequest"]), Start_HTTPRequest, Group_HTTPRequest),
Hierarchy = coalesce(Hierarchy, tostring(TitlePropertiesDynamic["hierarchy"])),
AppId = tostring(Claims_d["appid"]),
CallerType = case(
tostring(Claims_d["http://schemas.microsoft.com/identity/claims/scope"]) == "user_impersonation", "User",
tostring(Claims_d["idtyp"]) == "app", "App",
""
),
CallerRole = tostring(todynamic(Authorization)["evidence"]["role"]),
CallerRoleType = tostring(todynamic(Authorization)["evidence"]["principalType"]),
Body = todynamic(dynamic_to_json(coalesce(
PropertiesDynamic["MICROSOFT.AUTHORIZATION"]["Start"]["requestbody"],
PropertiesDynamic["Microsoft.Authorization"]["Started"]["requestbody"],
PropertiesDynamic["MICROSOFT.AUTHORIZATION"]["Success"]["responseBody"],
PropertiesDynamic["Microsoft.Authorization"]["Succeeded"]["responseBody"]
))),
CoalescedProperties = coalesce(
PropertiesDynamic["MICROSOFT.AUTHORIZATION"]["Success"],
PropertiesDynamic["Microsoft.Authorization"]["Succeeded"]
)
| extend
// BodyKeys = bag_keys(Body),
// PropertiesKeys = bag_keys(CoalescedProperties),
CallerIpAddress = coalesce(CallerIpAddress, tostring(todynamic(HTTPRequest)["clientIpAddress"])),
BodyPropertiesKeys = bag_keys(coalesce(Body["properties"], Body["Properties"]))
| extend
TargetId = coalesce(
tostring(Body["properties"]["principalId"]),
tostring(Body["Properties"]["PrincipalId"]),
replace_regex(tostring(CoalescedProperties["principalId"]), @"([a-f0-9]{8})([a-f0-9]{4})([a-f0-9]{4})([a-f0-9]{4})([a-f0-9]{12})", @"\1-\2-\3-\4-\5")
),
TargetRoleDefinitionId = coalesce(tostring(Body["properties"]["roleDefinitionId"]), tostring(Body["Properties"]["RoleDefinitionId"])),
TargetType = coalesce(tostring(Body["properties"]["principalType"]), tostring(Body["Properties"]["PrincipalType"]), iff(BodyPropertiesKeys has "EmailAddress", "User", ""))//,
// TargetCondition = coalesce(tostring(Body["Properties"]["Condition"]), ""),
// TargetConditionVersion = coalesce(tostring(Body["Properties"]["ConditionVersion"]), "")
| extend
TargetRoleTemplateId = coalesce(
tostring(split(TargetRoleDefinitionId, "/roleDefinitions/")[1]),
replace_regex(tostring(CoalescedProperties["roleDefinitionId"]), @"([a-f0-9]{8})([a-f0-9]{4})([a-f0-9]{4})([a-f0-9]{4})([a-f0-9]{12})", @"\1-\2-\3-\4-\5")
),
RemoveOperation = case(
OperationNameValue =~ "Microsoft.Authorization/roleAssignments/delete", true,
OperationNameValue =~ "Microsoft.Authorization/roleAssignments/write", false,
false
)
| project-away Body, CoalescedProperties, BodyPropertiesKeys, Start_HTTPRequest, Group_HTTPRequest, AllCapsPropertiesDynamic, TitlePropertiesDynamic//, TargetRoleDefinitionId
| lookup kind=leftouter (
union
(
_AADApps
| project CallerType = "App", Caller = tostring(ObjectId), CallerDisplayName = AppDisplayName
),
(
AuditLogs
| where TimeGenerated > ago(query_period)
| where Category == "ApplicationManagement" and OperationName has "service principal" and not(AADOperationType in ("Assign", "Unassign"))
| distinct Caller = tostring(TargetResources[0]["id"]), CallerDisplayName = tostring(TargetResources[0]["displayName"])//, TargetType = "ServicePrincipal"
| extend CallerType = "App"
)
| where isnotempty(Caller)
) on Caller//, CallerType
| extend CallerDisplayName = coalesce(CallerDisplayName, tostring(Claims_d["name"]))
| extend PermanentOperation = iff(CallerDisplayName == "MS-PIM" and Caller in (_PIM_ids), bool(null), true)
| lookup kind=leftouter (
_AADApps
| project AppId = tostring(AppId), AppDisplayName
| where isnotempty(AppId)
) on AppId
| project-rename TargetSubscriptionId = SubscriptionId
| lookup kind=leftouter (
_AzureSubscriptions
| project TargetSubscriptionId = tostring(SubscriptionId), TargetSubscriptionName = tostring(SubscriptionName)
) on TargetSubscriptionId
| lookup kind=leftouter (
union
(
_AADApps
| project TargetId = tostring(ObjectId), Target = tostring(AppDisplayName)//, TargetType = "ServicePrincipal"
),
(
AuditLogs
| where TimeGenerated > ago(query_period)
| where Category == "ApplicationManagement" and OperationName has "service principal" and not(AADOperationType in ("Assign", "Unassign"))
| distinct TargetId = tostring(TargetResources[0]["id"]), Target = tostring(TargetResources[0]["displayName"])//, TargetType = "ServicePrincipal"
),
(
_Users
| where isnotempty(AccountObjectId) and isnotempty(AccountUPN)
| project TargetId = AccountObjectId, Target = tostring(AccountUPN)//, TargetType = "User"
),
(
_Groups
| where isnotempty(ObjectId) and isnotempty(DisplayName)
| project TargetId = tostring(ObjectId), Target = tostring(DisplayName)//, TargetType = "Group"
)
| where isnotempty(TargetId)
| distinct *
) on TargetId//, TargetType
| lookup kind=leftouter (
_AzureRBACRoles
| project TargetRoleTemplateId = tostring(RoleId), TargetRoleName = tostring(RoleName)
| where isnotempty(TargetRoleTemplateId)
) on TargetRoleTemplateId
| project
TimeGenerated,
StartTime,
EndTime,
ResourceProvider,
Category,
CategoryValue,
ResourceProviderValue,
Level,
CallerIpAddress,
CallerType,
Caller,
CallerDisplayName,
CallerRole,
CallerRoleType,
AppId,
AppDisplayName,
OperationName,
OperationNameValue,
OriginOperationNameValue,
ActivityStatusValue,
//ActivityStatus,
ActivitySubstatusValue,
ActivitySubstatus,
TargetSubscriptionId,
TargetSubscriptionName,
TargetResourceGroup,
TargetType,
TargetId,
Target,
TargetRoleTemplateId,
TargetRoleName,
//TargetRoleDefinitionId,
// TargetCondition,
// TargetConditionVersion,
Authorization,
PropertiesDynamic,
HTTPRequest,
Authorization_d,
Properties_d,
Claims_d,
Resource,
ResourceId,
_ResourceId,
Hierarchy,
OperationId,
CorrelationId,
RemoveOperation,
PermanentOperation,
EventSubmissionTimestamp,
EventDataId,
//TenantId,
SourceSystem,
Type
);
union
(
union
(
_ResourceManagementPIM
| where not(EligibleOperation)
| lookup kind=leftouter (
_RoleAssignmentsAzure
| where CallerDisplayName == "MS-PIM" and Caller in (_PIM_ids) and isnotempty(TargetSubscriptionId) and isnotempty(TargetRoleTemplateId) and isnotempty(TargetId) and isnotempty(RemoveOperation)
| project-rename Azure_EndTime = EndTime, AzureActivity_CorrelationId = CorrelationId, Azure_CallerIpAddress = CallerIpAddress
| project-away TimeGenerated, StartTime, Category, Caller, CallerDisplayName, OperationName, TargetSubscriptionName, TargetRoleName, Target, SourceSystem, Type, PermanentOperation
) on TargetSubscriptionId, TargetRoleTemplateId, TargetId, RemoveOperation
| where not(isnotempty(Azure_EndTime) and Azure_EndTime > EndTime)
| summarize arg_max(Azure_EndTime, *) by TimeGenerated, CorrelationId, TargetSubscriptionId, TargetRoleTemplateId, TargetId, RemoveOperation
| extend CallerIpAddress = coalesce(CallerIpAddress, Azure_CallerIpAddress)
| project-away Azure_EndTime, Azure_CallerIpAddress
),
(
_ResourceManagementPIM
| where EligibleOperation
)
| project-rename AuditLogs_CorrelationId = CorrelationId
| project-away LoggedByService
),
(
_RoleAssignmentsAzure
| where not(CallerDisplayName == "MS-PIM" and Caller in (_PIM_ids) and isnotempty(TargetSubscriptionId) and isnotempty(TargetRoleTemplateId) and isnotempty(TargetId)) and isnotempty(RemoveOperation)
| project-rename AzureActivity_CorrelationId = CorrelationId
)
| where not(SourceSystem == "PIM" and isnotempty(CompletedCount) and CompletedCount == 0)
| extend
PrivilegedRole = isempty(TargetRoleName) or TargetRoleName matches regex _PrivAzureRBACRoles,
WorkingTime = IsWorkingTime(TimeGenerated),
AlertName = strcat(
iff(RemoveOperation, "Remove", "Add"),
" ",
iff(PermanentOperation, "permanent", iff(not(ActivateOperation), "temporary", "activated")),
" ",
iff(EligibleOperation, "eligible ", ""),
"member ",
iff(RemoveOperation, "from", "to"),
" Azure RBAC role"),
AlertDescription = strcat(
'This rule detects operations with Azure RBAC roles.\n\nThe ',
case(TargetType == "User", 'user', TargetType == "ServicePrincipal", 'service principal', TargetType == "Group", 'group', 'member'),
strcat(' "', coalesce(Target, TargetId), '"'),
' was ',
iff(RemoveOperation, 'removed from', 'added to'),
' role "',
coalesce(TargetRoleName, TargetRoleTemplateId),
'" in ',
iff(isnotempty(TargetResourceGroup), strcat('resource group "', TargetResourceGroup,'" from '), ''),
case(
isnotempty(TargetSubscriptionId), 'subscription "',
isnotempty(TargetManagementGroupId), 'management group "',
''),
case(
isnotempty(TargetSubscriptionId), coalesce(TargetSubscriptionName, TargetSubscriptionId),
isnotempty(TargetManagementGroupId), coalesce(TargetManagementGroupName, TargetManagementGroupId),
''),
'" by "',
iff(Caller matches regex @"[a-f0-9]+\-[a-f0-9]+\-[a-f0-9]+\-[a-f0-9]+\-[a-f0-9]+", coalesce(CallerDisplayName, Caller), Caller),
'".\n'
)
| extend AlertSeverity = case(
// Remove operations by Azure AD PIM (assumedly automatic)
RemoveOperation and CallerDisplayName == "Azure AD PIM" and AppDisplayName == "MS-PIM" and Caller in (_PIM_ids), "Informational",
// Remove operations originated by resource group deletion
RemoveOperation and SourceSystem == "Azure" and isnotempty(OriginOperationNameValue), "Informational",
// Direct Azure operations
not(SourceSystem == "PIM") and PrivilegedRole, "High",
not(SourceSystem == "PIM") and not(PrivilegedRole), "Medium",
// Voluntary deactivation operations
AADOperationType == "DeactivateRole", "Informational",
// Activation
AADOperationType == "ActivateRole" and not(WorkingTime), "Medium",
AADOperationType == "ActivateRole" and WorkingTime, "Informational",
// Non-user target
not(TargetGroupName == Target or TargetType in ("User", "Group")), "High",
// Non-working hours
not(WorkingTime), "High",
// Working hours
WorkingTime and PrivilegedRole and PermanentOperation, "Medium",
WorkingTime and PrivilegedRole and not(PermanentOperation), "Medium",
WorkingTime and not(PrivilegedRole) and PermanentOperation, "Low",
WorkingTime and not(PrivilegedRole) and not(PermanentOperation), "Informational",
"High"
)
| project
Type,
SourceSystem,
StartTime,
EndTime,
ResourceProviderValue,
Category,
CallerIpAddress,
Caller,
CallerDisplayName,
AppDisplayName,
OriginOperationNameValue,
OperationNameValue,
ActivityStatusValue,
ActivitySubstatusValue,
OperationName,
Result,
ResultReason,
TargetManagementGroupName,
TargetSubscriptionName,
TargetResourceGroup,
TargetRoleName,
TargetGroupName,
//PrivilegedRole,
Target,
TargetType,
TargetManagementGroupId,
TargetSubscriptionId,
TargetRoleTemplateId,
TargetId,
AzureActivity_CorrelationId,
ResourceProvider,
CategoryValue,
Level,
CallerType,
CallerRoleType,
CallerRole,
AppId,
ActivitySubstatus,
Authorization,
PropertiesDynamic,
HTTPRequest,
Authorization_d,
Properties_d,
Claims_d,
Resource,
ResourceId,
_ResourceId,
Hierarchy,
OperationId,
AuditLogs_CorrelationId,
AADOperationType,
// WorkingTime,
// ActivateOperation,
// EligibleOperation,
// RemoveOperation,
// PermanentOperation,
ActorIdentity,
ActorUserId,
ActorUserPrincipalName,
ActorUserIPAddress,
ActorUserRoles,
ActorAppId,
ActorAppName,
ActorAppServicePrincipalId,
ActorAppServicePrincipalName,
//RoleProvider,
TargetGroupId,
TargetUserId,
TargetUserPrincipalName,
RequestId,
RoleScheduleId,
InitiatedBy,
AdditionalDetails,
TargetResources,
AlertName,
AlertSeverity,
AlertDescription
//};
//Function(query_frequency)
This query helps detect Azure RBAC role assignments by analyzing various logs and activities. It looks for operations where users or applications are added or removed from Azure RBAC roles. The query also considers factors like working hours, operation types, and target entities to determine the severity of the detected role assignments. The results provide information about the operation, target entity, caller, and more to help monitor and manage Azure RBAC role assignments effectively.

Jose Sebastián Canós
Released: October 6, 2023
Tables
Keywords
Operators