Panther medium experimental python

Azure Privileged or Elevated Role Assignment

Detects when a privileged or elevated Azure role is assigned. Privileged roles include Owner, Contributor, User Access Administrator, Security Admin, and other high-impact administrative roles. Elevated roles include resource-specific roles with significant permissions like Storage Blob Data Owner, Key Vault Administrator, etc.

View Source

Detection Logic

from panther_azureactivity_helpers import (
    add_role_assignment_fields,
    azure_activity_alert_context,
    azure_activity_success,
    azure_parse_json_string,
    get_role_definition_id,
    match_role_name,
)

ROLE_ASSIGNMENT_WRITE = "MICROSOFT.AUTHORIZATION/ROLEASSIGNMENTS/WRITE"
ELEVATE_ACCESS_ACTION = "MICROSOFT.AUTHORIZATION/ELEVATEACCESS/ACTION"

# Common privileged role definition IDs (subscription-level built-in roles)
PRIVILEGED_ROLES = {
    "8e3af657-a8ff-443c-a75c-2fe8c4bcb635": "Owner",
    "b24988ac-6180-42a0-ab88-20f7382dd24c": "Contributor",
    "18d7d88d-d35e-4fb5-a5c3-7773c20a72d9": "User Access Administrator",
    "fb1c8493-542b-48eb-b624-b4c8fea62acd": "Security Admin",
    "92b92042-07d9-4307-87f7-36a593fc5850": "Azure File Sync Administrator",
    "a8889054-8d42-49c9-bc1c-52486c10e7cd": "Reservations Administrator",
    "f58310d9-a9f6-439a-9e8d-f62e7b41a168": "Role Based Access Control Administrator",
    "150f5e0c-0603-4f03-8c7f-cf70034c4e90": "Data Purger",
}

ELEVATED_ROLES = {
    "ba92f5b4-2d11-453d-a403-e96b0029c9fe": "Storage Blob Data Contributor",
    "b7e6dc6d-f1e8-4753-8033-0f276bb0955b": "Storage Blob Data Owner",
    "dffb1e0c-446f-4dde-a09f-99eb5cc68b96": "Azure Arc Kubernetes Admin",
    "a001fd3d-188f-4b5d-821b-7da978bf7442": "Cognitive Services OpenAI Contributor",
    "00482a5a-887f-4fb3-b363-3b7fe8e74483": "Key Vault Administrator",
    "8b54135c-b56d-4d72-a534-26097cfdc8d8": "Key Vault Data Access Administrator",
    "4633458b-17de-408a-b874-0445c86b69e6": "Key Vault Secrets User",
}

# Combine all role mappings for lookup
ALL_ROLES = {**PRIVILEGED_ROLES, **ELEVATED_ROLES}


def extract_role_name(event):
    # Extract and return the role name being assigned from the event
    request_body = azure_parse_json_string(
        event.deep_get("properties", "requestbody", default=None)
    )
    role_def_id = get_role_definition_id(request_body)
    return match_role_name(role_def_id, ALL_ROLES)


def rule(event):
    # For elevate access, operationName is a dict with "value" key
    operation_name_value = event.deep_get("operationName", "value", default="")
    if operation_name_value:
        operation_name_value = str(operation_name_value).upper()
        # Check if this is the elevate access action (subscription-level elevation)
        if (
            operation_name_value == ELEVATE_ACCESS_ACTION
            and event.deep_get("status", "value") == "Succeeded"
        ):
            return True

    # For role assignments, operationName is a string
    operation_name = event.get("operationName", "")
    if isinstance(operation_name, str):
        operation_name = operation_name.upper()
        # Check if this is a privileged/elevated role assignment
        if operation_name == ROLE_ASSIGNMENT_WRITE:
            return extract_role_name(event) is not None and azure_activity_success(event)

    return False


def title(event):
    operation_name_value = event.deep_get(
        "operationName", "value", default="<UNKNOWN_OP_VALUE>"
    ).upper()

    # Handle elevate access action (subscription-level elevation)
    if operation_name_value == ELEVATE_ACCESS_ACTION:
        caller_identity = event.deep_get("identity", "claims", "name", default="<UNKNOWN_USER>")
        return f"Azure subscription access elevated by [{caller_identity}]"

    # Handle role assignment
    role_assignment = event.deep_get("resourceId", default="<UNKNOWN_ASSIGNMENT>")
    role_name = extract_role_name(event) or "<UNKNOWN_ROLE>"
    role_str = "<UNKNOWN_ROLE_TYPE>"
    if role_name in PRIVILEGED_ROLES.values():
        role_str = "privileged"
    if role_name in ELEVATED_ROLES.values():
        role_str = "elevated"
    return f"Azure [{role_str}] role " f"[{role_name}] assigned on " f"[{role_assignment}]"


def severity(event):
    operation_name_value = event.deep_get(
        "operationName", "value", default="<UNKNOWN_OP_VALUE>"
    ).upper()

    # Elevate access action grants User Access Administrator at root scope
    if operation_name_value == ELEVATE_ACCESS_ACTION:
        return "HIGH"

    # Get the role name being assigned
    role_name = extract_role_name(event)

    if role_name:
        # Check if it's a privileged role
        if role_name in PRIVILEGED_ROLES.values():
            return "HIGH"
        # Check if it's an elevated role
        if role_name in ELEVATED_ROLES.values():
            return "MEDIUM"

    return "DEFAULT"


def alert_context(event):
    context = azure_activity_alert_context(event)

    # Parse and add request body fields
    request_body = azure_parse_json_string(
        event.deep_get("properties", "requestbody", default=None)
    )
    add_role_assignment_fields(context, request_body)

    # Add role name
    role_name = extract_role_name(event)
    if role_name:
        context["role_name"] = role_name

    return context

Field Validations

Loading…

Comments (0)

Loading comments...