ClickHouse access governance — every statement reviewed before it runs
Last updated
AccessFlow governs ClickHouse as a full query proxy: your team connects to AccessFlow, not to the database, and every statement is parsed, checked against a schema allow-list, risk-scored, routed to an approver, and only then executed — under column masking, row-level security and a row cap. The pipeline itself — parse, risk-score, route, approve, execute, audit — is the same for every relational engine and is described in full on the database access governance page. What follows is what is specific to ClickHouse.
- Family
- Relational
- Query language
- SQL
- Runs as
- In-process pooled JDBC
- Default port
8123- Default SSL mode
REQUIRE- Install
- One-click from the connector catalog
The driver and the connection
ClickHouse is a built-in catalog connector on the generic JDBC lane rather than one of the five first-class dialects. Its driver, com.clickhouse:clickhouse-jdbc, is pinned in the catalog and installed in one click, and it loads under a connector-scoped classloader of its own.
That generic lane is the same mechanism any other JDBC-compatible engine can use: upload a driver JAR with its SHA-256, and AccessFlow will govern it the same way. ClickHouse is simply a driver that ships pre-declared in the catalog so you do not have to.
The datasource takes host, port (8123 by default for the HTTP interface), database, username and password, AES-256-GCM encrypted at rest. SSL defaults to DISABLE, reflecting the common in-cluster deployment — set it to REQUIRE or a verifying mode for anything crossing a network boundary.
AccessFlow builds the connection string from the datasource fields using the template the connector manifest declares, so what actually reaches the driver is predictable and reviewable:
jdbc:ch://{host}:{port}/{database_name}
com.clickhouse.jdbc.ClickHouseDriver
Drivers are resolved on demand — the first time a datasource of this type is created or tested — and each one gets its own classloader. Two datasources pointing at different driver versions, even two ClickHouse datasources, load disjoint copies and cannot interfere with each other through static state.
What AccessFlow parses
Statements are parsed to a syntax tree and the schema allow-list is enforced against that tree. Because ClickHouse runs on the generic dialect, the parse is the standard SQL grammar rather than a ClickHouse-aware one — a statement using syntax outside that grammar is refused with HTTP 422 rather than passed through unparsed, which is the fail-closed direction.
What it refuses
Multi-statement input is refused, as is anything the parser cannot read. The rejection happens before a connection is taken from the pool.
Row-level security and masking
A policy is spliced into the WHERE clause as a bound predicate, and shapes that cannot be provably narrowed are refused. Masking is applied to the fetched result by the same masker every engine shares.
What the rewrite actually does
A policy restricting events to the caller's tenant narrows the read before ClickHouse receives it:
-- submitted SELECT event_type, count() FROM events WHERE day >= '2026-08-01' GROUP BY event_type; -- executed (policy: events.tenant = the caller's tenant) SELECT event_type, count() FROM events WHERE (day >= '2026-08-01') AND events.tenant = ? GROUP BY event_type;
The predicate is added before the GROUP BY, so the aggregate is computed over the rows the caller is allowed to see. Filtering afterwards would produce a different — and wrong — number, which is why the rewriter works on the parsed statement rather than on its text.
Introspection, dry-run and cost estimates
ClickHouse has no dialect-specific plan reader, so a dry-run reports itself unsupported with a localized reason rather than guessing at a plan. Everything else in the pre-flight path still runs — the statement is parsed, the allow-list checked, row security resolved, and the automatic submission estimate persisted with that unsupported state recorded — so a reviewer always sees a definitive answer rather than a blank panel.