New to Kestra?
Use blueprints to kickstart your first workflows.
Audit Databricks Unity Catalog grants on a schedule, alert Slack on over-privileged principals, and optionally revoke and verify the fix.
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.
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"}]}.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.log_summary (io.kestra.plugin.core.log.Log) logs the violation count.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):log_compliant logs it, nothing else happens.SlackIncomingWebhook task alerts that the probe itself did not
return.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.log_audit_summary always runs last and logs the final state of the gate.errors block posts to Slack if the flow itself fails outside the gate logic above.GRANT was the last one needed.dry_run: true ships enabled, so nothing is ever changed
until you explicitly turn both auto_remediate on and dry_run off.cli.DatabricksCLI driving the Databricks CLI's own grants get and grants update
commands, captured back into Kestra via outputFiles and read()/fromJson().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.
DatabricksCLI pulls
the official ghcr.io/databricks/cli:latest image automatically, no manual setup needed
for the CLI itself.MANAGE on the securable,
so the flow can both read (grants get) and, if auto_remediate is enabled, revoke
(grants update) privileges.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.
| 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 |
MANAGE on the securable you want to
audit.DATABRICKS_HOST, DATABRICKS_TOKEN, and SLACK_WEBHOOK_URL secrets.log_audit_summary for the result.VIOLATION you expect, set auto_remediate: true and dry_run: false
and run it again to revoke and verify.schedule_every_6_hours trigger, which always ships in safe mode.full_name at a CATALOG and widen allowed_principals to run the same audit one
level up the Unity Catalog hierarchy.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.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.COMPLIANT that writes the clean audit result to a Kestra
KV entry, to track how long the securable has stayed compliant.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.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.allowed_principals against every consumer of the
securable before enabling auto_remediate.