Connector

Snowflake access governance — every statement reviewed before it runs

Last updated

AccessFlow governs Snowflake through the same submit, analyse, approve, execute pipeline as any other engine — but Snowflake gets its own AccessFlow engine rather than a database driver, because its connection and authentication model does not fit host, port, username and password. Warehouse sessions are billed while a warehouse is resumed, so the shape of the connection is itself a governance decision.

Family
Cloud data warehouse
Query language
Snowflake SQL
Connects via
AccessFlow engine
Default port
443
Default SSL mode
REQUIRE
Install
One click — checksum-verified download

How AccessFlow connects

Snowflake's engine is one checksum-pinned download that AccessFlow verifies before loading, and it brings Snowflake's own client with it — there is nothing to install on the host and no vendor package to keep current separately. How an install works →

The host is the account host, the database name is the Snowflake database, and the stored credential is either a password or a PKCS#8 private-key PEM — detected by its header and used for the driver's key-pair JWT authentication. Passphrase-protected keys work too: the passphrase goes in its own field, is encrypted at rest alongside the key, and a missing passphrase and a wrong one are reported as two distinct errors rather than failing obscurely. A full connection URL can be supplied instead, carrying warehouse, role and schema parameters.

Nothing is held open between requests. Each request opens a short-lived connection and closes it. That is deliberate: warehouse sessions are billed while the warehouse is resumed, governance traffic is sparse rather than continuous, and per-request connections also rule out session-state leaking between two users' queries.

What AccessFlow understands

The parser is a keyword classifier over a tokenizer that understands Snowflake's quoting rules — single-quoted strings, double-quoted identifiers and $$…$$ blocks — plus comments. It accepts SELECT, INSERT, 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 distinct HTTP 422 messages: CALL, EXECUTE IMMEDIATE, scripting blocks (BEGIN, DECLARE), PUT and GET, COPY INTO, USE, SHOW, DESCRIBE, GRANT and REVOKE, and procedure, function, task, stream, pipe and stage DDL.

Multi-statement input is refused, and so are user-supplied ? placeholders — binds are reserved for row security, so a statement cannot arrive with its own parameter markers and collide with the ones the rewriter is about to add.

Row-level security and masking

Matching policies are ANDed into the WHERE clause, or a WHERE is inserted before GROUP BY, HAVING, QUALIFY, ORDER BY or LIMIT, with values bound as positional parameters. CTEs, subqueries, joins, set operators, MERGE and multi-table shapes all fail closed rather than execute unfiltered, and an INSERT into a policied table is rejected outright.

A policy with an empty value list is a deny-all that the executor short-circuits without opening a connection at all — so a misconfigured policy costs nothing and exposes nothing. Masking is applied after fetch by the same masker every engine shares.

What the rewrite actually does

A policy restricting orders to the caller's region narrows the statement before it is compiled — and before a single byte is billed:

Snowflake SQL
-- 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 = ?;
--                                                                       ^ bound, never concatenated

The value is a positional bind. A deny-all policy never reaches Snowflake at all: the executor short-circuits to an empty result without opening a connection, so a misconfigured policy costs nothing to run.

Dry-run and the scan-byte estimate

Snowflake bills by bytes scanned, so the dry-run is a cost control as much as a correctness one. AccessFlow plans the governed statement — row security already spliced in — behind an EXPLAIN USING TABULAR prefix, compiled by Snowflake and never executed, and reads the result defensively by column label so a release changing the output degrades rather than errors.

The aggregate post-pruning bytes become an estimated scan size shown to the reviewer before they approve, and the per-operator rows become a plan tree with partition pruning visible. A deny-all short-circuits to a zero-row, zero-byte estimate with no Snowflake call at all. DDL reports itself unsupported rather than guessing.