Guides

Add your first datasource.

Last updated

What you are building

A database AccessFlow can put queries in front of — connected, introspected, and then narrowed down so that even an approved query cannot reach more than it should. The connecting part takes a few minutes. The narrowing part is the work that matters, and it is the second half of this guide.

What do I need before adding a datasource?

A reachable host, and a database account for AccessFlow to use. Scope that account deliberately: AccessFlow governs who may ask for what, but the credentials you hand it still bound what is physically possible. A read-only account for a read-only datasource is the cheapest control you will ever apply.

1. Connect it

Sidebar → Datasources → add one. The wizard is four steps: Database type, Connection details, Connection test, Configuration.

The type picker is grouped into Bundled drivers, Connectors and Custom drivers, and each tile carries a badge telling you what will happen when you save:

  • Bundled — ships inside the image. Only PostgreSQL.
  • Downloaded — already fetched and cached on this deployment.
  • Will download — fetched on first use, checksum-verified, then cached. Expect a slower first save, not a failure.
  • Unavailable — the deployment is in offline driver mode or the cache is not writable.
You do not have to visit the connector catalog first. Saving the datasource resolves and verifies whatever it needs. Installing ahead of time from Connectors in the admin section just moves the wait earlier. Every download is checked against a pinned SHA-256 — and re-checked every time it is resolved, not only at install.
The datasource creation wizard showing the database type step with engine tiles grouped into bundled drivers, connectors and custom drivers.
Step 1 — pick the engine. The badge on each tile says whether its driver is bundled, cached, or will be downloaded on save.

Connection details adapts to the engine. Most ask for host, port, database name, username and password. Some do not:

EngineWhat it asks for instead
BigQueryA GCP project and a service-account key in JSON. No host, port or username.
DatabricksWorkspace host, a required warehouse HTTP path, and a personal access token. No username.
SnowflakeAn account host and either a password or an unencrypted private key for key-pair auth. No port.
DynamoDBAn AWS region in place of the database name, plus an access key id and secret.
Elasticsearch / OpenSearchEither a username and password, or an API key.
Cassandra / ScyllaDBA local datacenter name, which is required.

SSL mode is pre-filled from the engine's own default rather than one global default — PostgreSQL starts at full verification, while several others (ClickHouse and a number of the NoSQL engines) start disabled. Check it rather than assuming it.

Run the Connection test. It opens a real connection and runs a trivial probe — the plugin's own equivalent for non-JDBC engines. You can skip it, but a datasource that cannot connect is a datasource nobody can query.

A connection-shape mistake can report a confusing error. Per-engine requirements — a missing warehouse path, a JDBC URL a custom driver needs — are checked when you save, and the message you get back is currently a generic one about datasource permissions rather than the specific field. If a save is rejected and the message does not seem to fit, re-check the engine-specific fields in the table above.

Finally, Configuration: connection pool size, max rows per query, the review plan, whether reads and writes each require review, and the AI switches. Turning on AI analysis or text-to-SQL requires choosing an AI configuration in the same step — see turn on AI risk analysis.

Credentials are encrypted before storage and are never returned by any endpoint. If you keep secrets elsewhere, the password field also accepts a reference into HashiCorp Vault, AWS Secrets Manager or Azure Key Vault instead of a literal value.

2. Look at what you just connected

Open the datasource's settings. The Schema tab shows the introspected objects as a searchable tree; clicking a table previews sample rows — through the governed path, so masked columns show masked values, never the raw ones. The ER diagram tab renders the same schema as a graph, which is often the faster way to spot the tables you did not know were there.

This is worth doing before you write any policy. The next three sections all reference specific tables and columns, and the schema tab is where you find their real names.

3. Limit which tables can be queried

The table allow-list lives on the grant, not on the datasource. On the Permissions tab, a grant carries Allowed schemas and Allowed tables, both fed by the introspected schema.

AccessFlow enforces this by walking the parsed query and collecting every table it actually touches, then checking each one against the list. It is not a text match on the SQL, so aliases, comments and formatting cannot slip past it.

Empty means unrestricted. A grant with both lists empty can reach every table the database account can. That is the default when you create a grant, so narrowing it is a thing you do, not a thing that happens.

Two matching details worth knowing. Names are compared case-insensitively with quoting stripped, so "Orders" and orders are the same entry. But qualification is significant: an unqualified orders in the list matches an unqualified FROM orders, so list the form your users actually write — or allow the schema instead, which covers both.

4. Mask the columns that should not be read

The Masking tab defines column-level policies applied to results. Each policy names a column as schema.table.column, picks a strategy, and lists who may see through it.

  • Full mask — the value is replaced entirely.
  • Partial — keeps a number of trailing characters, for the last four digits of a card or an account.
  • Hash — a SHA-256 digest, so values remain comparable without being readable.
  • Email-preserving and format-preserving — keep the shape so downstream tools and eyeballs still recognise it.

Reveal to names the roles, groups or people who see the real value. Leave it empty and the column is masked for everyone, admins included — masking is opt-in for the reader, not opt-out.

The masking tab of a datasource settings page listing masking policies with their column, strategy, reveal-to list and enabled state.
Datasource settings → Masking — one policy per column, with the strategy and who may see through it.
Let AccessFlow find them for you. The Discovery tab samples column data through the governed path and proposes classifications — email addresses, card numbers, national ids, bank account numbers, phone numbers — which you confirm or dismiss. Confirming a proposal tags the column and can derive its masking policy for you. Raw sampled values are never stored, and never sent to an AI provider; the optional AI pass sees redacted samples only.

5. Limit which rows come back

The Row security tab filters rows rather than columns. A policy names a table and a column, an operator, and a value to compare against — either a literal, or a variable resolved per user such as their region attribute, their role, or their groups.

AccessFlow applies it by rewriting the query: a SELECT gets its table wrapped in a filtered subquery, an UPDATE or DELETE gets the predicate added to its WHERE clause. The comparison value is always bound as a parameter, never concatenated into the SQL.

Row security fails closed, in both directions. If the per-user value cannot be resolved — the attribute is missing, the list is empty — the policy matches nothing and the user sees zero rows rather than everything. And a query whose shape cannot be safely rewritten, such as one using set operations or common table expressions over a protected table, is rejected rather than run unfiltered. Expect some legitimate queries to be refused; that is the trade being made.

Non-relational engines each fail closed in their own way. Redis, for instance, cannot express row security at all, so a policy over it denies rather than degrades; Cassandra refuses policies on non-key columns instead of quietly scanning the whole table.

The row security tab of a datasource settings page listing policies with their table, predicate, applies-to scope and enabled state.
Datasource settings → Row security — a per-table predicate compared against a per-user value.

Unlike masking, row security applies to everyone by default: leaving Applies to empty means the policy is in force for all users. Narrow it to specific roles or groups if that is not what you want.

6. Keep an eye on it

Datasource health in the admin section shows connection-pool use, query volume, error counts and execution latency per datasource over the last day. It is the first place to look when queries start timing out — an exhausted pool looks very different from a slow database, and the page distinguishes them.

Field-by-field reference for every engine, the full policy options and the tuning env vars: Datasources. Engine-specific behaviour and install detail: Connectors.