Query Details

RULE 05 Automation Runbook New Caller

Query

// Rule    : Azure - Automation Runbook Created or Published by First-Time Caller
// Severity: High
// Tactics : Execution, Persistence
// MITRE   : T1059
// Freq    : PT6H   Period: P14D
//==========================================================================================

let KnownRunbookCallers = AzureActivity
    | where TimeGenerated between (ago(14d) .. ago(6h))
    | where OperationNameValue has_any ("AUTOMATION/AUTOMATIONACCOUNTS/RUNBOOKS/WRITE", "AUTOMATION/AUTOMATIONACCOUNTS/RUNBOOKS/PUBLISH/ACTION", "AUTOMATION/AUTOMATIONACCOUNTS/RUNBOOKS/DRAFT/WRITE")
    | where ActivityStatusValue =~ "Success"
    | distinct Caller;
let ExcludedPatterns = dynamic(["automation-account", "devops", "pipeline", "github", "bicep", "terraform"]);
AzureActivity
| where TimeGenerated > ago(6h)
| where OperationNameValue has_any ("AUTOMATION/AUTOMATIONACCOUNTS/RUNBOOKS/WRITE", "AUTOMATION/AUTOMATIONACCOUNTS/RUNBOOKS/PUBLISH/ACTION")
| where ActivityStatusValue =~ "Success"
| where not(tolower(Caller) has_any (ExcludedPatterns))
| where isnotempty(CallerIpAddress)
| where CallerIpAddress !startswith "168.63." and CallerIpAddress !startswith "169.254."
| where Caller !in (KnownRunbookCallers)
| summarize
    RunbookOpCount = count(),
    RunbookNames = make_set(tostring(split(ResourceId, "/")[-1]), 10),
    Operations = make_set(OperationNameValue, 5),
    SourceIPs = make_set(CallerIpAddress, 5),
    CallerIP = any(CallerIpAddress),
    FirstSeen = min(TimeGenerated),
    LastSeen = max(TimeGenerated)
    by Caller, ResourceGroup, SubscriptionId
| extend
    AccountName = tostring(split(Caller, "@")[0]),
    AccountUPNSuffix = tostring(split(Caller, "@")[1])

Explanation

This query is designed to identify potentially suspicious activities related to the creation or publication of Azure Automation Runbooks by users who have not previously performed such actions within a specified timeframe. Here's a simplified breakdown:

  1. Known Runbook Callers: The query first identifies users (Callers) who have successfully created or published runbooks in the past 14 days but not in the last 6 hours. These users are considered "known" and are stored in a list.

  2. Excluded Patterns: Certain patterns in usernames (like "automation-account", "devops", etc.) are excluded from further analysis to avoid false positives from expected automation activities.

  3. Current Activity Check: The query then checks for any runbook creation or publication activities in the last 6 hours. It focuses on successful operations and excludes known callers and those with certain IP address patterns (internal Azure IPs).

  4. New or Unusual Callers: It identifies new or unusual callers who have not been seen performing these operations before, summarizing their activities:

    • Counts the number of operations they performed.
    • Lists the runbooks they interacted with.
    • Records the types of operations and source IP addresses used.
    • Captures the first and last time these activities were seen.
  5. Output Details: For each new or unusual caller, it provides:

    • The caller's username and domain.
    • The resource group and subscription ID where the activities occurred.

This query is useful for detecting potential unauthorized or unexpected automation activities, which could indicate a security threat or policy violation.

Details

David Alonso profile picture

David Alonso

Released: March 12, 2026

Tables

AzureActivity

Keywords

AzureActivityCallerResourceGroupSubscriptionIdCallerIpAddressAccountNameAccountUPNSuffix

Operators

letbetweenagohas_any=~distinctdynamic>nottolowerisnotempty!startswith!insummarizecountmake_settostringsplitanyminmaxbyextend

Actions