AnalysisType: rule
Filename: azure_automation_account_created.py
RuleID: "Azure.MonitorActivity.Automation.AccountCreated"
DisplayName: "Azure Automation Account Created"
Enabled: true
LogTypes:
- Azure.MonitorActivity
Severity: Info
Description: >
Detects when an Azure Automation account is created. Azure Automation accounts can be used to
automate management tasks and orchestrate actions across systems. Adversaries may create
Automation accounts to maintain persistence in their target's environment by leveraging managed
identities and runbooks to execute code with elevated privileges.
Reports:
MITRE ATT&CK:
- TA0003:T1078 # Persistence: Valid Accounts
- TA0005:T1078 # Defense Evasion: Valid Accounts
Tags:
- Persistence
- Defense Evasion
- Valid Accounts
Runbook: |
1. Query Azure Monitor Activity logs for all automation-related operations (runbook creation, webhook creation, job executions) for the newly created automation account in the 6 hours after the account was created
2. Find all automation account creations by the callerIpAddress in the past 24 hours to identify if multiple accounts are being created
3. Check if the callerIpAddress has created automation accounts in the past 90 days to establish if this is typical infrastructure deployment behavior
Reference: https://github.com/elastic/detection-rules/blob/main/rules/integrations/azure/persistence_automation_account_created.toml
SummaryAttributes:
- resourceId
- callerIpAddress
- correlationId
Tests:
- Name: Automation Account Created Successfully
ExpectedResult: true
Log:
{
"time": "2025-12-22T10:30:00.0000000Z",
"resourceId": "/subscriptions/12345678-1234-1234-1234-123456789abc/resourceGroups/automation-rg/providers/Microsoft.Automation/automationAccounts/malicious-automation",
"operationName": "MICROSOFT.AUTOMATION/AUTOMATIONACCOUNTS/WRITE",
"operationVersion": "2021-06-22",
"category": "Administrative",
"resultType": "Success",
"resultSignature": "200",
"callerIpAddress": "1.1.1.1",
"correlationId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"level": "Informational",
"location": "eastus",
"tenantId": "87654321-4321-4321-4321-111111111111"
}
- Name: Automation Account Created Case Insensitive
ExpectedResult: true
Log:
{
"time": "2025-12-22T11:15:00.0000000Z",
"resourceId": "/subscriptions/11111111-1111-1111-1111-111111111111/resourceGroups/prod-automation/providers/Microsoft.Automation/automationAccounts/prod-automation-account",
"operationName": "microsoft.automation/automationaccounts/write",
"category": "Administrative",
"resultType": "Succeeded",
"callerIpAddress": "2.2.2.2",
"correlationId": "b2c3d4e5-f6a7-8901-bcde-f23456789012",
"level": "Information",
"location": "westeurope",
"tenantId": "22222222-2222-2222-2222-222222222222"
}
- Name: Different Operation
ExpectedResult: false
Log:
{
"time": "2025-12-22T13:00:00.0000000Z",
"resourceId": "/subscriptions/44444444-4444-4444-4444-444444444444/resourceGroups/automation-rg/providers/Microsoft.Automation/automationAccounts/existing-account",
"operationName": "MICROSOFT.AUTOMATION/AUTOMATIONACCOUNTS/DELETE",
"category": "Administrative",
"resultType": "Success",
"callerIpAddress": "4.4.4.4",
"correlationId": "d4e5f6a7-b8c9-0123-def0-456789012345",
"tenantId": "44444444-4444-4444-4444-444444444444"
}
# ------ paired body: azure_automation_account_created.py ------
from panther_azureactivity_helpers import (
azure_activity_alert_context,
azure_activity_success,
extract_resource_name_from_id,
)
AUTOMATION_ACCOUNT_WRITE = "MICROSOFT.AUTOMATION/AUTOMATIONACCOUNTS/WRITE"
def rule(event):
return event.get(
"operationName", ""
).upper() == AUTOMATION_ACCOUNT_WRITE and azure_activity_success(event)
def title(event):
resource_id = event.get("resourceId", "<UNKNOWN_RESOURCE>")
account_name = extract_resource_name_from_id(
resource_id, "automationAccounts", default="<UNKNOWN_ACCOUNT>"
)
return f"Azure Automation Account Created: [{account_name}]"
def alert_context(event):
context = azure_activity_alert_context(event)
resource_id = event.get("resourceId", "")
account_name = extract_resource_name_from_id(resource_id, "automationAccounts", default="")
if account_name:
context["automation_account_name"] = account_name
return context