Detection rules › Panther

Azure Policy DeployIfNotExists Action Triggered

Severity
medium
Log types
Azure.MonitorActivity
Tags
AZT508, Persistence, Defense Evasion, Valid Accounts, Cloud Accounts, Hide Artifacts
Reference
https://microsoft.github.io/Azure-Threat-Research-Matrix/Persistence/AZT508/AZT508
Source
github.com/panther-labs/panther-analysis

Detects when an Azure Policy with the DeployIfNotExists effect is triggered and executes a deployment. The DeployIfNotExists effect allows policies to automatically deploy resources when certain conditions are met. Adversaries may abuse this feature to establish persistence by creating policies that automatically deploy backdoors, malicious configurations, or unauthorized resources when specific conditions occur. This technique enables stealthy persistence as deployments appear to be legitimate policy enforcement actions.

MITRE ATT&CK coverage

Rule body yaml

AnalysisType: rule
Filename: azure_policy_deployifnotexists.py
RuleID: "Azure.MonitorActivity.Policy.DeployIfNotExists"
DisplayName: "Azure Policy DeployIfNotExists Action Triggered"
Enabled: true
LogTypes:
  - Azure.MonitorActivity
Severity: Medium
Description: >
  Detects when an Azure Policy with the DeployIfNotExists effect is triggered and executes a deployment.
  The DeployIfNotExists effect allows policies to automatically deploy resources when certain conditions are met.
  Adversaries may abuse this feature to establish persistence by creating policies that automatically deploy
  backdoors, malicious configurations, or unauthorized resources when specific conditions occur. This technique
  enables stealthy persistence as deployments appear to be legitimate policy enforcement actions.
Reports:
  MITRE ATT&CK:
    - TA0003:T1078.004 # Persistence: Valid Accounts - Cloud Accounts
    - TA0005:T1564 # Defense Evasion: Hide Artifacts
Tags:
  - AZT508
  - Persistence
  - Defense Evasion
  - Valid Accounts
  - Cloud Accounts
  - Hide Artifacts
Runbook: |
  1. Find all policy-related operations by the callerIpAddress in the 48 hours before and after this alert to identify if new policies were created or assignments were modified
  2. Query for the policy definition details to understand what resources are being deployed and review the deployment template for malicious configurations
  3. Check if similar DeployIfNotExists actions have been triggered from this policy in the past 30 days to determine if this is expected behavior
Reference: https://microsoft.github.io/Azure-Threat-Research-Matrix/Persistence/AZT508/AZT508
SummaryAttributes:
  - resourceId
  - callerIpAddress
  - correlationId
Tests:
  - Name: DeployIfNotExists Policy Triggered
    ExpectedResult: true
    Log:
      {
        "time": "2025-12-23T10:30:00.0000000Z",
        "resourceId": "/subscriptions/12345678-1234-1234-1234-123456789abc/resourceGroups/policy-rg/providers/Microsoft.Authorization/policyDefinitions/AutoDeployBackdoor",
        "operationName": "Microsoft.Authorization/policies/deployIfNotExists/action",
        "operationVersion": "2021-06-01",
        "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: Policy Deployment Success
    ExpectedResult: true
    Log:
      {
        "time": "2025-12-23T11:15:00.0000000Z",
        "resourceId": "/subscriptions/11111111-1111-1111-1111-111111111111/resourceGroups/prod-rg/providers/Microsoft.Authorization/policyAssignments/AutoDeploy",
        "operationName": "Microsoft.Authorization/policies/deployIfNotExists/action",
        "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: Case Insensitive Match
    ExpectedResult: true
    Log:
      {
        "time": "2025-12-23T12:00:00.0000000Z",
        "resourceId": "/subscriptions/33333333-3333-3333-3333-333333333333/resourceGroups/security-rg/providers/Microsoft.Authorization/policyDefinitions/MaliciousPolicy",
        "operationName": "microsoft.authorization/policies/deployifnotexists/action",
        "category": "Administrative",
        "resultType": "Success",
        "callerIpAddress": "3.3.3.3",
        "correlationId": "c3d4e5f6-a7b8-9012-cdef-333333333333",
        "level": "Informational",
        "location": "centralus",
        "tenantId": "33333333-3333-3333-3333-333333333333"
      }
  - Name: Different Operation
    ExpectedResult: false
    Log:
      {
        "time": "2025-12-23T14:00:00.0000000Z",
        "resourceId": "/subscriptions/55555555-5555-5555-5555-555555555555/resourceGroups/policy-rg/providers/Microsoft.Authorization/policyDefinitions/MyPolicy",
        "operationName": "Microsoft.Authorization/policyDefinitions/write",
        "category": "Administrative",
        "resultType": "Success",
        "callerIpAddress": "5.5.5.5",
        "correlationId": "e5f6a7b8-c9d0-1234-ef01-111111111111",
        "tenantId": "55555555-5555-5555-5555-555555555555"
      }

Detection logic

Condition

operationName in "MICROSOFT.AUTHORIZATION/POLICIES/DEPLOYIFNOTEXISTS/ACTION"
resultType in ["Success", "Succeeded"]

Indicators

Each row is a field, operator, and value that the rule matches. The corpus column counts how many other rules in the catalog look for the same combination: high numbers point to widely-used, community-vetted indicators. Blank or 1 shows that the indicator is specific to this rule.

FieldKindValues
operationNamein
  • MICROSOFT.AUTHORIZATION/POLICIES/DEPLOYIFNOTEXISTS/ACTION
resultTypein
  • Succeeded
  • Success