Query Details

06 AAD Prov Service Silence

Query

id: 9b1a0006-1006-4106-9106-aadprov00006
name: Provisioning Service Silence - Busy Job Stopped
version: 1.0.0
kind: Scheduled
description: |
  Detects when a previously busy provisioning job (>= 100 events/hour baseline
  over the past 7 days) has produced 0 events in the most recent 2-hour window.
  Sudden silence on a critical provisioning channel can indicate connector
  credential theft (attacker stopped the legitimate agent), deliberate
  sabotage of the sync pipeline to defeat lifecycle controls, or simply a
  broken connector that needs ops attention. Either way it warrants an alert.
  MITRE ATT&CK: T1562.001 (Impair Defenses: Disable or Modify Tools),
  T1531 (Account Access Removal).
severity: Medium
requiredDataConnectors:
  - connectorId: AzureActiveDirectory
    dataTypes:
      - AADProvisioningLogs
queryFrequency: 1h
queryPeriod: 7d
triggerOperator: gt
triggerThreshold: 0
tactics:
  - DefenseEvasion
  - Impact
relevantTechniques:
  - T1562
  - T1531
query: |
  let Baseline =
      AADProvisioningLogs
      | where TimeGenerated between (ago(7d) .. ago(2h))
      | extend SPName = tostring(parse_json(ServicePrincipal).Name)
      | summarize BaselinePerHour = count() / 168.0 by JobId, SPName
      | where BaselinePerHour >= 100;
  let Recent =
      AADProvisioningLogs
      | where TimeGenerated > ago(2h)
      | extend SPName = tostring(parse_json(ServicePrincipal).Name)
      | summarize RecentEvents = count() by JobId, SPName;
  Baseline
  | join kind=leftouter (Recent) on JobId, SPName
  | extend RecentEvents = coalesce(RecentEvents, 0)
  | where RecentEvents == 0
  | project JobId, SPName, BaselinePerHour, RecentEvents,
            DropRatio = 1.0,
            AlertReason = strcat("Job baseline ", round(BaselinePerHour,0), "/hr but 0 events in last 2h")
  | order by BaselinePerHour desc
entityMappings:
  - entityType: CloudApplication
    fieldMappings:
      - identifier: Name
        columnName: SPName
customDetails:
  BaselinePerHour: BaselinePerHour
  RecentEvents: RecentEvents
  AlertReason: AlertReason
alertDetailsOverride:
  alertDisplayNameFormat: "Provisioning silence on {{SPName}} (was {{BaselinePerHour}}/hr)"
  alertDescriptionFormat: "{{AlertReason}}. Confirm connector health, credentials, and recent admin actions on the SP."
  alertSeverityColumnName: ""
  alertTacticsColumnName: ""
incidentConfiguration:
  createIncident: true
  groupingConfiguration:
    enabled: true
    reopenClosedIncident: false
    lookbackDuration: PT24H
    matchingMethod: AnyAlert
    groupByEntities:
      - CloudApplication
    groupByAlertDetails: []
    groupByCustomDetails: []

Explanation

This query is part of a scheduled task designed to monitor Azure Active Directory provisioning jobs. Here's a simple breakdown of what it does:

  1. Purpose: The query checks for provisioning jobs that were previously active (producing at least 100 events per hour over the past 7 days) but have suddenly stopped producing any events in the last 2 hours. This sudden silence could indicate potential issues such as credential theft, sabotage, or a broken connector.

  2. Data Source: It uses data from Azure Active Directory provisioning logs.

  3. Process:

    • Baseline Calculation: It calculates the average number of events per hour for each job over the past 7 days.
    • Recent Activity Check: It checks for any events in the last 2 hours.
    • Comparison: It identifies jobs that had a high baseline activity but have zero events in the recent 2-hour window.
  4. Alert Generation: If a job meets the criteria (high baseline but no recent events), it generates an alert. The alert includes details like the job ID, service principal name, baseline activity rate, and a reason for the alert.

  5. Severity and Tactics: The alert is marked with a medium severity and is associated with tactics like Defense Evasion and Impact, referencing specific MITRE ATT&CK techniques.

  6. Incident Management: The query is configured to create incidents for these alerts, with options for grouping related alerts into a single incident.

In summary, this query helps detect potential issues in Azure AD provisioning jobs by identifying when a job that was previously busy suddenly stops, which could indicate a problem that needs attention.

Details

David Alonso profile picture

David Alonso

Released: June 1, 2026

Tables

AADProvisioningLogs

Keywords

AzureActiveDirectoryAADProvisioningLogsCloudApplicationServicePrincipalJobIdSPNameTimeGenerated

Operators

letbetweenagoextendtostringparse_jsonsummarizebywherejoinkind=leftouteroncoalesceprojectstrcatroundorder bydesc

Actions