Databricks Metastore Admin Privilege Granted


Description

Detects when metastore admin privileges are granted in Databricks through direct metastore ownership changes or addition to metastore admin groups. Metastore admins have extensive control over data access and governance policies in Unity Catalog.

Query · python

from panther_databricks_helpers import databricks_alert_context, is_metastore_admin_action


def rule(event):
    # Use helper to check for metastore admin actions
    if not is_metastore_admin_action(event):
        return False

    action = event.get("actionName", "")

    # For group membership changes, only alert on additions (not removals)
    # and ensure it's at the account level
    if action != "updateMetastore":
        # Exclude removals
        if action == "removePrincipalFromGroup":
            return False
        # Must be account-level event
        if event.get("serviceName") != "accounts":
            return False

    return True


def title(event):
    action = event.get("actionName", "Unknown Action")
    actor = event.deep_get("userIdentity", "email", default="Unknown Actor")

    if action == "updateMetastore":
        new_owner = event.deep_get("requestParams", "owner", default="Unknown Owner")
        return f"Metastore ownership changed to {new_owner} by {actor}"
    target_group = event.deep_get("requestParams", "targetGroupName", default="Unknown Group")
    principal = event.deep_get("requestParams", "principal") or event.deep_get(
        "requestParams", "targetUserName", default="Unknown Principal"
    )
    return f"Principal {principal} added to metastore admin group {target_group} by {actor}"


def dedup(event):
    action = event.get("actionName", "unknown")
    if action == "updateMetastore":
        metastore_id = event.deep_get("requestParams", "metastoreId", default="unknown")
        return f"metastore_admin_{metastore_id}"
    principal = event.deep_get("requestParams", "principal") or event.deep_get(
        "requestParams", "targetUserName", default="unknown"
    )
    return f"metastore_admin_group_{principal}"


def alert_context(event):
    return databricks_alert_context(
        event,
        additional_fields={
            "new_owner": event.deep_get("requestParams", "owner"),
            "target_group": event.deep_get("requestParams", "targetGroupName"),
            "principal": event.deep_get("requestParams", "principal")
            or event.deep_get("requestParams", "targetUserName"),
        },
    )

Analyst notes

  1. Query Unity Catalog audit logs for all metastore operations by the target principal in the 24 hours after this privilege grant
  2. Check if the target principal accessed sensitive catalogs or tables in the 6 hours after receiving admin rights
  3. Find all metastore admin grants in the past 90 days to identify unusual patterns
Raw source Databricks Metastore Admin Privilege Granted · Panther Python
Esc
Published by panther-labs/panther-analysis ↗, licensed under Apache 2.0 ↗. Reproduced here unmodified.
AnalysisType: rule
Filename: databricks_metastore_admin_privilege_granted.py
RuleID: "Databricks.Audit.MetastoreAdminPrivilegeGranted"
DisplayName: "Databricks Metastore Admin Privilege Granted"
Enabled: true
Status: Experimental
LogTypes:
  - Databricks.Audit
Tags:
  - Databricks
  - Privilege Escalation
  - Unity Catalog
Reports:
  MITRE ATT&CK:
    - TA0004:T1098 # Account Manipulation
Severity: Medium
Description: >
  Detects when metastore admin privileges are granted in Databricks through direct metastore
  ownership changes or addition to metastore admin groups. Metastore admins have extensive
  control over data access and governance policies in Unity Catalog.
Runbook: |
  1. Query Unity Catalog audit logs for all metastore operations by the target principal in the 24 hours after this privilege grant
  2. Check if the target principal accessed sensitive catalogs or tables in the 6 hours after receiving admin rights
  3. Find all metastore admin grants in the past 90 days to identify unusual patterns
Reference: https://github.com/databricks-solutions/cybersec-workspace-detection-app/blob/main/base/detections/event-based/metastore_admin_privilege_granted.py
Tests:
  - Name: Metastore Ownership Changed
    ExpectedResult: true
    Log:
      timestamp: 1234567890000
      serviceName: "unityCatalog"
      actionName: "updateMetastore"
      userIdentity:
        email: "admin@example.com"
      sourceIPAddress: "198.51.100.1"
      requestParams:
        metastoreId: "metastore-123"
        owner: "newadmin@example.com"
      response:
        statusCode: 200
  - Name: Added to Metastore Admin Group
    ExpectedResult: true
    Log:
      timestamp: 1234567890000
      serviceName: "accounts"
      actionName: "addPrincipalToGroup"
      userIdentity:
        email: "admin@example.com"
      sourceIPAddress: "198.51.100.1"
      requestParams:
        principal: "user@example.com"
        targetGroupName: "metastore-admins"
  - Name: Added to Unity Catalog Admin Group
    ExpectedResult: true
    Log:
      timestamp: 1234567890000
      serviceName: "accounts"
      actionName: "addPrincipalsToGroup"
      userIdentity:
        email: "admin@example.com"
      requestParams:
        targetUserName: "user@example.com"
        targetGroupName: "unity-catalog-admins"
  - Name: Metastore Update Without Owner Change
    ExpectedResult: false
    Log:
      timestamp: 1234567890000
      serviceName: "unityCatalog"
      actionName: "updateMetastore"
      userIdentity:
        email: "admin@example.com"
      requestParams:
        metastoreId: "metastore-123"
        name: "Production Metastore"
  - Name: Added to Non-Admin Group
    ExpectedResult: false
    Log:
      timestamp: 1234567890000
      serviceName: "accounts"
      actionName: "addPrincipalToGroup"
      userIdentity:
        email: "admin@example.com"
      requestParams:
        principal: "user@example.com"
        targetGroupName: "metastore-users"


# ------ paired body: databricks_metastore_admin_privilege_granted.py ------

from panther_databricks_helpers import databricks_alert_context, is_metastore_admin_action


def rule(event):
    # Use helper to check for metastore admin actions
    if not is_metastore_admin_action(event):
        return False

    action = event.get("actionName", "")

    # For group membership changes, only alert on additions (not removals)
    # and ensure it's at the account level
    if action != "updateMetastore":
        # Exclude removals
        if action == "removePrincipalFromGroup":
            return False
        # Must be account-level event
        if event.get("serviceName") != "accounts":
            return False

    return True


def title(event):
    action = event.get("actionName", "Unknown Action")
    actor = event.deep_get("userIdentity", "email", default="Unknown Actor")

    if action == "updateMetastore":
        new_owner = event.deep_get("requestParams", "owner", default="Unknown Owner")
        return f"Metastore ownership changed to {new_owner} by {actor}"
    target_group = event.deep_get("requestParams", "targetGroupName", default="Unknown Group")
    principal = event.deep_get("requestParams", "principal") or event.deep_get(
        "requestParams", "targetUserName", default="Unknown Principal"
    )
    return f"Principal {principal} added to metastore admin group {target_group} by {actor}"


def dedup(event):
    action = event.get("actionName", "unknown")
    if action == "updateMetastore":
        metastore_id = event.deep_get("requestParams", "metastoreId", default="unknown")
        return f"metastore_admin_{metastore_id}"
    principal = event.deep_get("requestParams", "principal") or event.deep_get(
        "requestParams", "targetUserName", default="unknown"
    )
    return f"metastore_admin_group_{principal}"


def alert_context(event):
    return databricks_alert_context(
        event,
        additional_fields={
            "new_owner": event.deep_get("requestParams", "owner"),
            "target_group": event.deep_get("requestParams", "targetGroupName"),
            "principal": event.deep_get("requestParams", "principal")
            or event.deep_get("requestParams", "targetUserName"),
        },
    )

Detection rules belong to the projects that publish them and remain under their own licenses. This site indexes and links to them; it claims no rights in them.