Workload identity sign-ins from a country outside the 14-day baseline may indicate compromised credentials or unauthorized access attempts. SOC teams should proactively hunt for this behavior in Azure Sentinel to detect potential credential theft and mitigate lateral movement risks.
KQL Query
let timeframe = 1d;
let lookback = 14d;
let BaselineCountries =
AADServicePrincipalSignInLogs
| where TimeGenerated >= ago(timeframe + lookback) and TimeGenerated < ago(timeframe)
| where ResultType == 0
| where isnotempty(Location)
| summarize KnownCountries = make_set(Location) by ServicePrincipalId;
AADServicePrincipalSignInLogs
| where TimeGenerated >= ago(timeframe)
| where ResultType == 0
| where isnotempty(Location)
| join kind=leftouter hint.strategy=broadcast BaselineCountries on ServicePrincipalId
| where isnull(KnownCountries) or not(set_has_element(KnownCountries, Location))
| extend AccountName = ServicePrincipalName
| project TimeGenerated, ServicePrincipalId, ServicePrincipalName, AccountName,
AppId, Location, IPAddress, ResourceDisplayName, CorrelationId
| sort by TimeGenerated desc
id: e366bd25-400c-433f-b984-c5b8aece15f2
name: Workload identity sign-in from a country not in 14-day baseline
description: |
Identifies service principal sign-ins from a country not present in the SP's
sign-in history over the preceding 14 days. A new-country sign-in for a workload
identity may indicate stolen client credentials or a compromised pipeline.
requiredDataConnectors:
- connectorId: AzureActiveDirectory
dataTypes:
- AADServicePrincipalSignInLogs
tactics:
- InitialAccess
- CredentialAccess
relevantTechniques:
- T1078.004
query: |
let timeframe = 1d;
let lookback = 14d;
let BaselineCountries =
AADServicePrincipalSignInLogs
| where TimeGenerated >= ago(timeframe + lookback) and TimeGenerated < ago(timeframe)
| where ResultType == 0
| where isnotempty(Location)
| summarize KnownCountries = make_set(Location) by ServicePrincipalId;
AADServicePrincipalSignInLogs
| where TimeGenerated >= ago(timeframe)
| where ResultType == 0
| where isnotempty(Location)
| join kind=leftouter hint.strategy=broadcast BaselineCountries on ServicePrincipalId
| where isnull(KnownCountries) or not(set_has_element(KnownCountries, Location))
| extend AccountName = ServicePrincipalName
| project TimeGenerated, ServicePrincipalId, ServicePrincipalName, AccountName,
AppId, Location, IPAddress, ResourceDisplayName, CorrelationId
| sort by TimeGenerated desc
entityMappings:
- entityType: Account
fieldMappings:
- identifier: Name
columnName: ServicePrincipalName
- entityType: IP
fieldMappings:
- identifier: Address
columnName: IPAddress
version: 1.0.0
metadata:
source:
kind: Community
author:
name: descambiado
support:
tier: Community
categories:
domains: [ "Security - Threat Protection", "Identity" ]
Scenario: A scheduled job runs a script that authenticates using a service principal to access Azure Blob Storage, and the IP address of the job’s execution location is newly registered in the last 14 days.
Filter/Exclusion: Exclude sign-ins from IP addresses associated with known infrastructure (e.g., Azure VMs, Azure DevOps pipelines) using the Azure IP Ranges list or by checking the client_ip field against a whitelist of trusted IPs.
Scenario: An admin performs a remote management task using Azure AD Connect to synchronize on-premises Active Directory with Azure AD, and the sign-in occurs from a new country due to the admin’s temporary location.
Filter/Exclusion: Exclude sign-ins from users with the “Global Administrator” or “Directory Reader” role, or use the user_principal_name field to filter out known admin accounts.
Scenario: A CI/CD pipeline (e.g., Azure DevOps) runs a deployment task that authenticates using a service principal, and the IP address used by the pipeline is newly registered in the last 14 days.
Filter/Exclusion: Exclude sign-ins from service principals associated with CI/CD pipelines by checking the app_display_name or app_id field against a list of known pipeline service principals.
Scenario: A system administrator uses a remote desktop connection (e.g., via Azure Bastion) to access a virtual machine, and the sign-in occurs from a new country due to the administrator’s location during a travel period.
Filter/Exclusion: Exclude sign-ins where the user_agent or client_app field indicates remote access tools (e.g., mstsc.exe, Azure Bastion), or use the user_principal_name field to exclude known admin accounts.
Scenario: A backup job (e.g., Azure Backup) runs and authenticates