A user with no recent history of modifying Conditional Access Policies is attempting to alter security controls, potentially weakening organizational defenses. SOC teams should proactively hunt for this behavior to identify and mitigate unauthorized changes to critical security configurations in Azure Sentinel.
KQL Query
let known_users = (AuditLogs
| where TimeGenerated between(ago(14d)..ago(1d))
| where OperationName has "conditional access policy"
| where Result =~ "success"
| extend InitiatingUserPrincipalName = tostring(InitiatedBy.user.userPrincipalName)
| summarize by InitiatingUserPrincipalName);
AuditLogs
| where TimeGenerated > ago(1d)
| where OperationName has "conditional access policy"
| where Result =~ "success"
| extend InitiatingAppName = tostring(InitiatedBy.app.displayName)
| extend InitiatingAppId = tostring(InitiatedBy.app.appId)
| extend InitiatingAppServicePrincipalId = tostring(InitiatedBy.app.servicePrincipalId)
| extend InitiatingUserPrincipalName = tostring(InitiatedBy.user.userPrincipalName)
| extend InitiatingAadUserId = tostring(InitiatedBy.user.id)
| extend InitiatingIPAddress = tostring(InitiatedBy.user.ipAddress)
| extend CAPolicyName = tostring(TargetResources[0].displayName)
| where InitiatingUserPrincipalName !in (known_users)
| extend NewPolicyValues = TargetResources[0].modifiedProperties[0].newValue
| extend OldPolicyValues = TargetResources[0].modifiedProperties[0].oldValue
| extend InitiatingAccountName = tostring(split(InitiatingUserPrincipalName, "@")[0]), InitiatingAccountUPNSuffix = tostring(split(InitiatingUserPrincipalName, "@")[1])
| project-reorder TimeGenerated, OperationName, CAPolicyName, InitiatingAppId, InitiatingAppName, InitiatingAppServicePrincipalId, InitiatingUserPrincipalName, InitiatingAadUserId, InitiatingIPAddress, NewPolicyValues, OldPolicyValues
id: 25a7f951-54b7-4cf5-9862-ebc04306c590
name: Conditional Access Policy Modified by New User
description: |
'Detects a Conditional Access Policy being modified by a user who has not modified a policy in the last 14 days.
A threat actor may try to modify policies to weaken the security controls in place.
Investigate any change to ensure they are approved.
Ref: https://docs.microsoft.com/azure/active-directory/fundamentals/security-operations-infrastructure#conditional-access'
severity: Medium
requiredDataConnectors:
- connectorId: AzureActiveDirectory
dataTypes:
- AuditLogs
queryFrequency: 1d
queryPeriod: 14d
triggerOperator: gt
triggerThreshold: 0
tactics:
- DefenseEvasion
relevantTechniques:
- T1078.004
tags:
- AADSecOpsGuide
query: |
let known_users = (AuditLogs
| where TimeGenerated between(ago(14d)..ago(1d))
| where OperationName has "conditional access policy"
| where Result =~ "success"
| extend InitiatingUserPrincipalName = tostring(InitiatedBy.user.userPrincipalName)
| summarize by InitiatingUserPrincipalName);
AuditLogs
| where TimeGenerated > ago(1d)
| where OperationName has "conditional access policy"
| where Result =~ "success"
| extend InitiatingAppName = tostring(InitiatedBy.app.displayName)
| extend InitiatingAppId = tostring(InitiatedBy.app.appId)
| extend InitiatingAppServicePrincipalId = tostring(InitiatedBy.app.servicePrincipalId)
| extend InitiatingUserPrincipalName = tostring(InitiatedBy.user.userPrincipalName)
| extend InitiatingAadUserId = tostring(InitiatedBy.user.id)
| extend InitiatingIPAddress = tostring(InitiatedBy.user.ipAddress)
| extend CAPolicyName = tostring(TargetResources[0].displayName)
| where InitiatingUserPrincipalName !in (known_users)
| extend NewPolicyValues = TargetResources[0].modifiedProperties[0].newValue
| extend OldPolicyValues = TargetResources[0].modifiedProperties[0].oldValue
| extend InitiatingAccountName = tostring(split(InitiatingUserPrincipalName, "@")[0]), InitiatingAccountUPNSuffix = tostring(split(InitiatingUserPrincipalName, "@")[1])
| project-reorder TimeGenerated, OperationName, CAPolicyName, InitiatingAppId, InitiatingAppName, InitiatingAppServicePrincipalId, InitiatingUserPrincipalName, InitiatingAadUserId, InitiatingIPAddress, NewPolicyValues, OldPolicyValues
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: InitiatingUserPrincipalName
- identifier: Name
columnName: InitiatingAccountName
- identifier: UPNSuffix
columnName: InitiatingAccountUPNSuffix
- entityType: Account
fieldMappings:
- identifier: AadUserId
columnName: InitiatingAadUserId
- entityType: IP
fieldMappings:
- identifier: Address
columnName: InitiatingIPAddress
- entityType: CloudApplication
fieldMappings:
- identifier: AppId
columnName: InitiatingAppId
| Sentinel Table | Notes |
|---|---|
AuditLogs | Ensure this data connector is enabled |
Scenario: Scheduled Policy Compliance Check Run by Automation Tool
Description: A scheduled job (e.g., Azure Automation or third-party SIEM tool) runs a compliance check and inadvertently modifies a Conditional Access Policy.
Filter/Exclusion: userAgent contains "Azure Automation" OR userAgent contains "SIEM Tool"
Scenario: Admin Task to Update Policy for New Feature Rollout
Description: An admin updates a Conditional Access Policy to enable a new feature (e.g., Microsoft Entra ID feature update) and the user has not modified a policy in the last 14 days.
Filter/Exclusion: policyName contains "FeatureRollout" OR policyName contains "NewFeature"
Scenario: User Account Created for Temporary Access
Description: A temporary user account (e.g., created via Azure AD Privileged Identity Management or via a third-party tool) is used to modify a Conditional Access Policy.
Filter/Exclusion: userType contains "Temporary" OR userAccountCreated > 7 days ago
Scenario: Policy Modification via PowerShell Script
Description: A PowerShell script (e.g., used by DevOps or IT automation) modifies a Conditional Access Policy as part of a routine configuration update.
Filter/Exclusion: eventData contains "PowerShell" OR eventData contains "DevOps"
Scenario: User Access via Privileged Access Tool
Description: A user with elevated privileges (e.g., via Microsoft Entra ID Privileged Identity Management) modifies a Conditional Access Policy as part of a routine administrative task.
Filter/Exclusion: user contains "PIM" OR user contains "Privileged"