Azure Service Principal Authentication from Multiple Countries

Detects when an Azure service principal authenticates from multiple countries within a short time window, which may indicate stolen credentials being used from different geographic locations. Service principals typically authenticate from consistent locations tied to their deployment infrastructure. Authentication from multiple countries in a brief period suggests credential compromise, particularly when the source countries do not align with the organization's expected operating regions. This pattern has been observed in attacks using stolen CI/CD credentials, phished service principal secrets, and compromised automation accounts.

Elastic rule (View on GitHub)

  1[metadata]
  2creation_date = "2026/03/10"
  3integration = ["azure"]
  4maturity = "production"
  5updated_date = "2026/03/10"
  6
  7[rule]
  8author = ["Elastic"]
  9description = """
 10Detects when an Azure service principal authenticates from multiple countries within a short time window, which may
 11indicate stolen credentials being used from different geographic locations. Service principals typically authenticate
 12from consistent locations tied to their deployment infrastructure. Authentication from multiple countries in a brief
 13period suggests credential compromise, particularly when the source countries do not align with the organization's
 14expected operating regions. This pattern has been observed in attacks using stolen CI/CD credentials, phished service
 15principal secrets, and compromised automation accounts.
 16"""
 17false_positives = [
 18    """
 19    Service principals used by globally distributed CI/CD systems (e.g., GitHub Actions runners in multiple regions) may
 20    legitimately authenticate from different countries. Baseline the expected geographic distribution for each service
 21    principal.
 22    """,
 23    """
 24    VPN or proxy usage by administrators managing service principals from different locations may produce multi-country
 25    sign-in patterns. Correlate with the administrator's known travel or access patterns.
 26    """,
 27]
 28from = "now-8h"
 29interval = "1h"
 30language = "esql"
 31license = "Elastic License v2"
 32name = "Azure Service Principal Authentication from Multiple Countries"
 33note = """## Triage and analysis
 34
 35### Investigating Azure Service Principal Authentication from Multiple Countries
 36
 37Service principals are non-interactive identities used for automation and application access. Unlike user accounts,
 38they rarely change geographic location. Authentication from multiple countries in a short window is a strong indicator
 39of credential compromise.
 40
 41### Possible investigation steps
 42
 43- Identify the service principal using the `app_id` and `app_display_name` from the alert.
 44- Review the list of countries and source IPs — do they match known infrastructure locations?
 45- Check when the service principal credentials were last rotated — stale credentials are more likely compromised.
 46- Investigate what resources were accessed after authentication using Azure Activity Logs and Graph Activity Logs.
 47- Correlate with Azure AD Audit Logs for recent changes to the service principal (new credentials, federated
 48  identities, owner changes).
 49- Check if the service principal has Azure Arc or Kubernetes-related role assignments, which could indicate
 50  targeting of cluster resources.
 51
 52### False positive analysis
 53- If the service principal is used by a CI/CD pipeline, check if the different countries align with known runner locations. Baseline the expected geographic distribution for that SP.
 54- If administrators manage the SP, correlate with known travel patterns or VPN usage that could explain multi-country access.
 55
 56### Response and remediation
 57
 58- Immediately rotate the service principal credentials (secrets and certificates).
 59- Revoke active sessions and tokens.
 60- Review and remove any unauthorized role assignments.
 61- Audit resources accessed from the suspicious locations.
 62- Enable conditional access policies to restrict service principal authentication by location if supported.
 63"""
 64references = [
 65    "https://learn.microsoft.com/en-us/entra/identity/monitoring-health/concept-sign-ins",
 66    "https://learn.microsoft.com/en-us/entra/identity/conditional-access/workload-identities",
 67    "https://www.microsoft.com/en-us/security/blog/2025/08/27/storm-0501s-evolving-techniques-lead-to-cloud-based-ransomware/",
 68    "https://www.wiz.io/blog/lateral-movement-risks-in-the-cloud-and-how-to-prevent-them-part-3-from-compromis",
 69]
 70risk_score = 73
 71rule_id = "db97a2aa-3ba5-4fa5-b8b9-bf42284edb5f"
 72severity = "high"
 73tags = [
 74    "Domain: Cloud",
 75    "Domain: Identity",
 76    "Data Source: Azure",
 77    "Data Source: Microsoft Entra ID",
 78    "Data Source: Microsoft Entra ID Sign-In Logs",
 79    "Use Case: Identity and Access Audit",
 80    "Use Case: Threat Detection",
 81    "Tactic: Initial Access",
 82    "Resources: Investigation Guide",
 83]
 84timestamp_override = "event.ingested"
 85type = "esql"
 86
 87query = '''
 88FROM logs-azure.signinlogs-* metadata _id, _index
 89| WHERE event.dataset == "azure.signinlogs"
 90    AND azure.signinlogs.category == "ServicePrincipalSignInLogs"
 91    AND azure.signinlogs.properties.status.error_code == 0
 92    AND source.geo.country_iso_code IS NOT NULL
 93    AND azure.signinlogs.properties.service_principal_id IS NOT NULL
 94    AND NOT azure.signinlogs.properties.app_owner_tenant_id IN (
 95        "f8cdef31-a31e-4b4a-93e4-5f571e91255a",
 96        "72f988bf-86f1-41af-91ab-2d7cd011db47"
 97    )
 98
 99| EVAL
100    Esql.source_ip_string = TO_STRING(source.ip),
101    Esql.source_ip_country_pair = CONCAT(Esql.source_ip_string, " - ", source.geo.country_name)
102
103| STATS
104    Esql.source_geo_country_iso_code_count_distinct = COUNT_DISTINCT(source.geo.country_iso_code),
105    Esql.source_geo_country_name_values = VALUES(source.geo.country_name),
106    Esql.source_geo_city_name_values = VALUES(source.geo.city_name),
107    Esql.source_ip_values = VALUES(source.ip),
108    Esql.source_ip_country_pair_values = VALUES(Esql.source_ip_country_pair),
109    Esql.source_network_org_name_values = VALUES(`source.as.organization.name`),
110    Esql.resource_display_name_values = VALUES(azure.signinlogs.properties.resource_display_name),
111    Esql.app_id_values = VALUES(azure.signinlogs.properties.app_id),
112    Esql.app_owner_tenant_id_values = VALUES(azure.signinlogs.properties.app_owner_tenant_id),
113    Esql.source_ip_count_distinct = COUNT_DISTINCT(source.ip),
114    Esql.source_geo_city_name_count_distinct = COUNT_DISTINCT(source.geo.city_name),
115    Esql.source_network_org_name_count_distinct = COUNT_DISTINCT(`source.as.organization.name`),
116    Esql.timestamp_first_seen = MIN(@timestamp),
117    Esql.timestamp_last_seen = MAX(@timestamp),
118    Esql.event_count = COUNT(*)
119    BY azure.signinlogs.properties.service_principal_id, azure.signinlogs.properties.app_display_name
120
121| WHERE Esql.source_geo_country_iso_code_count_distinct >= 2
122| KEEP *
123'''
124
125
126[[rule.threat]]
127framework = "MITRE ATT&CK"
128[[rule.threat.technique]]
129id = "T1078"
130name = "Valid Accounts"
131reference = "https://attack.mitre.org/techniques/T1078/"
132[[rule.threat.technique.subtechnique]]
133id = "T1078.004"
134name = "Cloud Accounts"
135reference = "https://attack.mitre.org/techniques/T1078/004/"
136
137
138
139[rule.threat.tactic]
140id = "TA0001"
141name = "Initial Access"
142reference = "https://attack.mitre.org/tactics/TA0001/"
143
144[rule.investigation_fields]
145field_names = [
146    "azure.signinlogs.properties.service_principal_id",
147    "azure.signinlogs.properties.app_display_name",
148    "Esql.source_geo_country_iso_code_count_distinct",
149    "Esql.source_geo_country_name_values",
150    "Esql.source_geo_city_name_values",
151    "Esql.source_ip_values",
152    "Esql.source_ip_country_pair_values",
153    "Esql.source_network_org_name_values",
154    "Esql.resource_display_name_values",
155    "Esql.app_id_values",
156    "Esql.app_owner_tenant_id_values",
157    "Esql.source_ip_count_distinct",
158    "Esql.source_geo_city_name_count_distinct",
159    "Esql.source_network_org_name_count_distinct",
160    "Esql.timestamp_first_seen",
161    "Esql.timestamp_last_seen",
162    "Esql.event_count",
163]

Triage and analysis

Investigating Azure Service Principal Authentication from Multiple Countries

Service principals are non-interactive identities used for automation and application access. Unlike user accounts, they rarely change geographic location. Authentication from multiple countries in a short window is a strong indicator of credential compromise.

Possible investigation steps

  • Identify the service principal using the app_id and app_display_name from the alert.
  • Review the list of countries and source IPs — do they match known infrastructure locations?
  • Check when the service principal credentials were last rotated — stale credentials are more likely compromised.
  • Investigate what resources were accessed after authentication using Azure Activity Logs and Graph Activity Logs.
  • Correlate with Azure AD Audit Logs for recent changes to the service principal (new credentials, federated identities, owner changes).
  • Check if the service principal has Azure Arc or Kubernetes-related role assignments, which could indicate targeting of cluster resources.

False positive analysis

  • If the service principal is used by a CI/CD pipeline, check if the different countries align with known runner locations. Baseline the expected geographic distribution for that SP.
  • If administrators manage the SP, correlate with known travel patterns or VPN usage that could explain multi-country access.

Response and remediation

  • Immediately rotate the service principal credentials (secrets and certificates).
  • Revoke active sessions and tokens.
  • Review and remove any unauthorized role assignments.
  • Audit resources accessed from the suspicious locations.
  • Enable conditional access policies to restrict service principal authentication by location if supported.

References

Related rules

to-top