Databricks SQL access governance — every statement reviewed before it runs
Last updated
AccessFlow governs Databricks SQL through the same submit, analyse, approve, execute pipeline as any other engine — and does it with no vendor driver or SDK at all. The plugin talks to the SQL Statement Execution API over the JDK HTTP client, which is why it is the smallest engine AccessFlow ships.
- Family
- Cloud data warehouse
- Query language
- Databricks SQL
- Runs as
- Engine plugin (SHA-256 pinned)
- Default port
443- Default SSL mode
REQUIRE- Install
- One-click from the connector catalog
How AccessFlow connects
It is an engine plugin rather than an in-process JDBC datasource: a standalone shaded JAR, pinned in the connector catalog by URL and SHA-256, downloaded on first use, hash-verified, and loaded into an isolated classloader. If the hash does not match, it does not load. In an air-gapped install the JAR can be pre-seeded into the driver cache and the runtime told never to reach the network. In this case the only bundled dependency is a relocated JSON library: there is no Databricks driver, no vendor SDK, and no connection pool to manage.
The host is the workspace host and the stored credential is a personal access token, sent as a bearer token and AES-256-GCM encrypted at rest. The URL override field is required here — the one connector where that is true — because it carries the SQL warehouse HTTP path, whose last segment is the warehouse id the API needs. The database name optionally selects a Unity Catalog catalog.
What AccessFlow understands
Databricks SQL is in the Spark SQL family, with backtick identifiers. The classifier accepts SELECT, INSERT (both INTO and OVERWRITE), UPDATE, DELETE, MERGE and table, view and schema DDL including TRUNCATE.
Operations map onto the same query types the SQL engines use, so the per-user read, write and DDL capabilities, the routing-policy engine and the multi-stage approval chains apply completely unchanged.
What it refuses
Rejected with HTTP 422: USE, SET, CACHE and UNCACHE, COPY INTO, CALL, MSCK, ANALYZE, REFRESH, DESCRIBE, SHOW, EXPLAIN, GRANT and REVOKE, scripting, and function, volume, catalog and share DDL.
OPTIMIZE and VACUUM are refused too, on the grounds that table maintenance is not a governable query — it has no rows to review, no blast radius a reviewer could reason about, and no meaningful audit shape.
Multi-statement input is refused, as are user-supplied ? and :name markers. The :: cast shorthand is correctly not treated as a marker.
Row-level security and masking
The same fail-closed WHERE splice as the other warehouses — CTEs, subqueries, joins, set operations, LATERAL VIEW and multi-table shapes all refuse rather than widen, and an INSERT into a policied table is rejected. Values ride along as the API's named parameters under a collision-resistant prefix, and a statement that already contains that prefix literally fails closed rather than risking a clash.
A deny-all policy short-circuits with zero HTTP calls. Masking is applied after fetch by the shared masker over the result manifest's columns.
What the rewrite actually does
A policy restricting orders to the caller's region narrows the statement before it is submitted to the warehouse:
-- submitted SELECT id, email FROM orders WHERE status = 'OPEN'; -- executed (row-security policy: orders.region = the caller's region) SELECT id, email FROM orders WHERE (status = 'OPEN') AND orders.region = :afp_1; -- ^ named API parameter
The prefix is collision-resistant, and a statement that already contains it literally fails closed rather than risking a clash with the rewriter's own parameters. A deny-all costs zero HTTP calls.
Dry-run and cost estimates
A dry-run submits the governed statement behind an EXPLAIN COST prefix through the same submit-and-poll path, so Catalyst plans it and nothing executes. Databricks returns the plan as text rather than a structured tree, and AccessFlow treats that text as non-contractual: a never-throwing parser pulls the optimised plan's top-level statistics out of it — size in bytes, normalised from binary-unit suffixes, and row count — and degrades to nulls if the format drifts, rather than failing the estimate.
Statements are submitted with a wait timeout and then polled to a terminal state, bounded by the host-computed statement timeout; on deadline the engine issues a best-effort cancel. Introspection reads the information schema through that same API, scoped to the catalog when one is set.