Row- and column-level security, enforced adversarially.
Rowfence is a policy-driven proxy that sits in front of any VGI worker and decides, on every single query, which rows, columns, and functions a caller is allowed to touch — without asking the worker to police itself. Part of the VGI suite; a Query Farm product.
A dedicated hop between DuckDB and the worker
A VGI worker doesn’t have to implement access control itself to get it. Point
ATTACH at Rowfence instead of the worker directly, and every
query — every row, every column, every function call — passes through Cedar policy
evaluation before the worker ever sees it. There’s no passthrough mode: enforcement is
always on.
It’s sold as part of the VGI suite, not bundled into it — a standalone Query Farm product, hosted for you or run entirely on your own infrastructure. It isn’t open source, and there’s no repository to self-host from.
Rowfence enforces policy on top of VGI — it isn’t useful on its own. If you haven’t
met the protocol yet, start with VGI to see what a
worker is and how ATTACH reaches one.
policies.cedar
permit(
principal in Vgi::Group::"analysts",
action == Vgi::Action::"Read",
resource in Vgi::Table::"main.customers"
);
forbid(
principal,
action == Vgi::Action::"Read",
resource
)
when { resource.pii == true }
unless { principal in Vgi::Group::"compliance" };
Not just tables — rows, columns, and functions
Everything below is the same Cedar model, applied at a different grain. Full detail on each of these — including how row rules can pull a live boundary from another VGI worker and cache it — is in the technical docs.
Cedar policies
Access control in Cedar — the same open policy language AWS built for Verified Permissions — against an entity model that mirrors your catalog: servers, schemas, tables, columns, functions.
Row-level filtering
Ordered branches inject a WHERE clause built from the caller’s own identity. Entitlements can resolve from a static list or a live query against another VGI worker — a subscriber list, a geographic boundary, anything.
Column-level enforcement
A forbidden column is removed from the schema DuckDB is told about, not just filtered from results — there’s no column to select. Column-level statistics are denied outright under a column policy.
Function-level access
VGI workers expose functions as well as tables — an LLM call, a scoring model, a metered API. The same permit/forbid model gates Execute on a function exactly like it gates Read on a table.
Doesn’t trust the worker
The proxy discovers the real schema itself and enforces against that discovery, not whatever the worker advertises. Every error path denies by default — none of them fall through to “allow.”
Audit logging
JSONL, one line per event — every row filter injected, every column denied, every entitlement resolved. An optional decision journal makes past decisions replayable offline.
The moment more than one person can query it, someone has to decide who sees what
“The worker will just be careful” isn’t a policy. These are the situations that come up almost immediately once real customers or colleagues start attaching to something you built — and the actual policy that handles each one.
Selling the same table to different customers
A subscriber in California doesn’t need Alaska’s rows, and shouldn’t be able to query outside what they bought — same schema, same SQL, different rows per caller.
# row-filters.yaml
branches:
- scope: "earthquakes"
when: 'context.claim.region == "california"'
expr: "region = ${claim.region}"
- scope: "*"
grant: none # fail closed — no match, zero rows
Keeping PII out of reach by default
Give analysts the table, not the personally identifiable columns — unless they’re on the compliance team.
forbid(
principal,
action == Vgi::Action::"Read",
resource
)
when { resource.pii == true }
unless { principal in Vgi::Group::"compliance" };
Splitting finance and sales by role, not by table
One unified schema — what a person can see still depends on their department, not which table they happened to query.
forbid(principal, action, resource)
when { context.schema == "finance" }
unless { principal in Vgi::Group::"finance-managers" };
Gating an expensive function call
A geocoder or LLM-backed function that costs real money per call shouldn’t be open to every caller — meter it the same way you’d meter a table.
forbid(
principal,
action == Vgi::Action::"Execute",
resource in Vgi::Function::"geocode"
)
unless { principal in Vgi::Group::"premium-tier" };
All four are real syntax, shown in full (with the row-level mechanism explained in depth) in the technical docs →
Hosted or on-prem
Query Farm sells Rowfence two ways — running it for you, or running entirely inside your own network so the proxy never leaves your infrastructure.
Hosted
Query Farm runs Rowfence for you, in front of a worker you already run yourself or one hosted on Orchard.
On-prem
Run it inside your own network, in front of a worker that never has to leave your infrastructure either.
Both shapes support a single worker behind stateless, load-balanced replicas, and a multi-tenant gateway mode for routing many different backends behind one proxy — the shape for a vendor brokering access to more than one downstream source. A compliance bundle — canned access-review reports and decision-replay summaries built on the audit log — is on the roadmap, not shipped yet.
How this compares
Row- and column-level security itself isn’t the differentiator — Immuta, Satori, and others in that category already do it well. What’s different is what it’s enforced in front of, and how it’s deployed.
Warehouse-native governance platforms
Immuta, Satori, and similar tools connect to a fixed list of warehouses and databases — Snowflake, Databricks, BigQuery, and the like — through native integrations, and are primarily sold as SaaS.
Rowfence
Sits in front of any VGI worker — a live API, a custom service, a warehouse, anything the protocol reaches — because enforcement happens at the protocol layer, not against a connector list. Hosted or fully on-prem, your choice.
A proprietary policy builder
Most platforms in this category express rules through their own UI-driven builder or a vendor-specific rule format, portable only within that product.
Cedar
The same open policy language AWS built for Verified Permissions — not invented for this page. permit/forbid over principals, actions, and resources, not a bespoke syntax.
Rowfence and the rest of the data farm
Rowfence doesn’t stand alone — it enforces policy on top of VGI, using the same identity VGI’s own authentication support carries.
VGI
The protocol Rowfence enforces policy on top of — any worker, any language, reachable through one proxy.
Authentication
Bearer tokens and OAuth — how a caller’s identity reaches Rowfence in the first place.
Data-as-a-Service
The broader case for full SQL access instead of a copy of your data — Rowfence is how you keep it governed.
Get Rowfence in front of a real worker
Hosted or on-prem — tell us about your worker and your policy needs, and we’ll get you set up.