DatabricksCLI icon
OutputValues icon
Log icon
Switch icon
SlackIncomingWebhook icon
If icon
Loop icon
Fail icon
Schedule icon

Databricks Unity Catalog Grant Compliance Gate

Audit Databricks Unity Catalog grants on a schedule, alert Slack on over-privileged principals, and optionally revoke and verify the fix.

Categories
DataInfrastructure

Unity Catalog access is granted one GRANT statement at a time, often months apart, by different people, with no single place that shows who currently holds ALL_PRIVILEGES or MODIFY on a given catalog, schema or table. A grant given for a one-off migration and never revoked is exactly how an unrelated team ends up able to drop a production schema. This blueprint turns a Unity Catalog permission check into a Day 2 governance gate: it reads the real privilege assignments on a securable, flags any principal outside your allow list holding a high-risk privilege, alerts Slack, and can revoke the excess privilege itself, then re-checks to prove the revoke actually took.

The plugin-databricks tasks this blueprint runs on top of (io.kestra.plugin.databricks.cli.DatabricksCLI) wrap the official Databricks CLI's own grants get and grants update commands, rather than a dedicated Unity Catalog grant task, since the plugin does not ship one as a released, published task today.

How it works

  1. probe_grants (io.kestra.plugin.databricks.cli.DatabricksCLI) runs databricks grants get <securable_type> <full_name> --output json, redirected to grants.json and declared via outputFiles so downstream tasks can read it, with allowFailure: true so an auth or not-found error does not stop the flow before it can be classified and alerted on. The command's JSON is the Unity Catalog Grants REST API response verbatim: {"privilege_assignments": [{"principal", "privileges"}]}.
  2. audit_grants (io.kestra.plugin.core.output.OutputValues) reads that file with read() and fromJson(), then compares each {principal, privileges} entry against allowed_principals and high_risk_privileges with a jq filter, returning the list of violations: principals outside the allow list holding at least one high-risk privilege. If probe_grants produced no output at all, this returns an empty list rather than failing, so the flow can still classify the run as PROBE_FAILED downstream instead of crashing.
  3. log_summary (io.kestra.plugin.core.log.Log) logs the violation count.
  4. route_compliance (io.kestra.plugin.core.flow.Switch) branches on outputs.probe_grants is not defined (classified PROBE_FAILED) or the violation count (classified VIOLATION or COMPLIANT):
    • COMPLIANT: log_compliant logs it, nothing else happens.
    • PROBE_FAILED: a SlackIncomingWebhook task alerts that the probe itself did not return.
    • VIOLATION: a SlackIncomingWebhook task alerts with the exact principal and privileges found, built only from audit_grants' own output. remediate_gate (io.kestra.plugin.core.flow.If) then runs only when auto_remediate is true and dry_run is false:
      • revoke_violations (io.kestra.plugin.core.flow.Loop, concurrencyLimit: 1) calls databricks grants update <securable_type> <full_name> --json '...' once per violation, with a body shaped exactly like the Grants REST API's update endpoint ({"changes": [{"principal", "remove": [...]}]}), revoking only the privileges that caused the violation.
      • reprobe_grants runs the same grants get command again, reaudit_grants re-runs the same jq filter, and verify_remediation (io.kestra.plugin.core.flow.If) fails the flow with io.kestra.plugin.core.execution.Fail if a violation still remains, so a partially-applied revoke is never silently reported as fixed.
  5. log_audit_summary always runs last and logs the final state of the gate.
  6. The errors block posts to Slack if the flow itself fails outside the gate logic above.

What you get

  • A point-in-time answer to "who can do what" on a Unity Catalog securable, instead of trusting that the last GRANT was the last one needed.
  • A Slack alert that names the exact principal and the exact privileges that triggered it, never an invented number.
  • A safe-by-default revoke path: dry_run: true ships enabled, so nothing is ever changed until you explicitly turn both auto_remediate on and dry_run off.
  • A verified remediation: the flow re-reads the grants after revoking and fails loudly if the violation is still there.

Who it's for

  • Data platform and data governance teams who own Unity Catalog access control and need to prove, on a schedule, that only approved principals hold high-risk privileges.
  • Security and compliance teams who need an audit trail of access reviews on sensitive catalogs or schemas, beyond a point-in-time manual review.
  • Teams evaluating the Databricks plugin who want a working example of cli.DatabricksCLI driving the Databricks CLI's own grants get and grants update commands, captured back into Kestra via outputFiles and read()/fromJson().

Why orchestrate this with Kestra

Unity Catalog's own GRANT/REVOKE statements have no concept of a schedule, an allow list, or an alert, they just apply the change you ask for. Kestra adds the recurring audit, the allow-list comparison, the Slack alert carrying the exact violation, the gated revoke behind auto_remediate and dry_run, and the verification step that proves the revoke worked, all as one declarative YAML file you can version and review like code.

Prerequisites

  • A Databricks workspace with Unity Catalog enabled and a securable (catalog, schema or table) to audit. Databricks is a managed service with no self-hostable open-source Docker image, there is no local container to start for Databricks itself. DatabricksCLI pulls the official ghcr.io/databricks/cli:latest image automatically, no manual setup needed for the CLI itself.
  • A personal access token (or OAuth M2M service principal) with MANAGE on the securable, so the flow can both read (grants get) and, if auto_remediate is enabled, revoke (grants update) privileges.
  • A Slack incoming webhook for alerts.

Secrets

  • DATABRICKS_HOST: your workspace URL, for example https://<workspace>.cloud.databricks.com.

  • DATABRICKS_TOKEN: a personal access token with MANAGE on the securable.

  • SLACK_WEBHOOK_URL: Slack incoming webhook URL used by the alert tasks and the errors block.

    In Kestra OSS, set all three as base64-encoded environment variables: SECRET_DATABRICKS_HOST, SECRET_DATABRICKS_TOKEN, SECRET_SLACK_WEBHOOK_URL.

Inputs

Input Type Default Purpose
securable_type SELECT SCHEMA Unity Catalog securable type (CATALOG, SCHEMA, TABLE)
full_name STRING main.landing_zone Full name of the securable object
allowed_principals JSON ["data-platform-admins"] JSON array of approved principal names
high_risk_privileges JSON ["ALL_PRIVILEGES", "MODIFY"] JSON array of high-risk privileges to audit
auto_remediate BOOL false When true with dry_run: false, revokes violating grants
dry_run BOOL true Must be false to apply grant revocations

Quick start

  1. Create a Databricks personal access token with MANAGE on the securable you want to audit.
  2. Add the DATABRICKS_HOST, DATABRICKS_TOKEN, and SLACK_WEBHOOK_URL secrets.
  3. Run this flow manually with the defaults and read log_audit_summary for the result.
  4. If it reports a VIOLATION you expect, set auto_remediate: true and dry_run: false and run it again to revoke and verify.
  5. Enable the schedule_every_6_hours trigger, which always ships in safe mode.

How to extend

  • Point full_name at a CATALOG and widen allowed_principals to run the same audit one level up the Unity Catalog hierarchy.
  • Add a second high_risk_privileges tier (for example SELECT on a PII-tagged schema) with its own allow list, and run a second probe_grants/audit_grants pair against it.
  • Read principal from an identity provider's group export instead of a static allowed_principals list, to catch access that is technically allow-listed but the group membership itself has drifted.
  • Chain a downstream task after COMPLIANT that writes the clean audit result to a Kestra KV entry, to track how long the securable has stayed compliant.

Pitfalls

  • databricks grants get only returns privileges granted directly on the securable, inherited privileges from a parent catalog or schema are not included, a principal can still have effective access through inheritance even when this audit reports zero direct grants.
  • The token used for grants update needs MANAGE on the securable, a token scoped only to read access will pass probe_grants but fail the revoke with a permission error.
  • securable_type is case-insensitive on the Databricks API side but must be one of CATALOG, SCHEMA, TABLE, VOLUME, EXTERNAL_LOCATION or STORAGE_CREDENTIAL, anything else is rejected before the API call is made.
  • revoke_grant's --json argument is built with a Pebble map literal and shell single-quoted; a principal name or privilege string containing a literal single quote would break the shell quoting. Unity Catalog principal names (emails, group names, service principal IDs) and privilege names are not expected to contain one in practice.
  • Revoking a privilege a principal needs for a job that runs outside this flow's schedule breaks that job at its next run, review allowed_principals against every consumer of the securable before enabling auto_remediate.

Links

See How

New to Kestra?

Use blueprints to kickstart your first workflows.