How-to guide
Secure data access
Create roles and permissions, restrict rows per user or group, and mask sensitive columns.
Prerequisites
- Admin access to Kiwi Fabric
- The tables you want to protect are registered as capabilities
Access control in Kiwi Fabric has three layers that you configure once and that apply on REST, the PostgreSQL wire protocol and Arrow Flight alike.
- Role-based access control (RBAC): which tables and operations a user may use.
- Row-level security (RLS): which rows of a permitted table a user may see.
- Column-level security (CLS): which columns are hidden or masked.
Users belong to groups; users and groups are granted roles; roles hold permissions.
1. Create a role and grant permissions#
kiwi fabric role-add --name sales-analyst --desc "Read access to sales data"
kiwi fabric perm-add --role <role-id> --operation read --resource "datasource:sales"
--operation is read, write, execute or *. --resource is a name or pattern such as datasource:sales, capability:* or *, and wildcards are allowed on both. --effect is ALLOW (default) or DENY.

Important
Deny wins. If an explicit deny applies anywhere in the chain of user, group and role, it overrides any allow.
2. Assign users and groups#
kiwi fabric user-add --user alice --password "<initial-password>"
kiwi fabric group-add --name emea-analysts
kiwi fabric group-member-add --id <group-id> --user alice
kiwi fabric group-role-assign --id <group-id> --role <role-id> # every member inherits the role
kiwi fabric user-role-assign --user alice --role <role-id> # or assign directly to one user
See the CLI reference for every user, group and role command.
In the Web UI, Users has a Directory tab to create users, an Activity tab with request counts and latency over the last 30 days, and a Keys tab to manage a user's API keys. Groups and Roles have their own pages, and User Access shows and edits the roles assigned directly to one user.




3. Restrict rows#
A row filter is a JSON predicate attached to a role and a table. The placeholders {"$user": "id"} and {"$user": "groups"} resolve to the calling user at query time:
kiwi fabric row-filter-add --role <role-id> --table orders \
--filter '{"type":"eq","column":"tenant_id","value":{"$user":"id"}}'
A user in this role sees only rows whose tenant_id equals their own user id, regardless of what SQL they submit. The filter uses the same predicate grammar as saga update and delete filters.
In the Web UI, build the predicate visually (conditions are ANDed within a group and groups are ORed, and Current user compares against the querying user's id), or switch to Raw JSON.


4. Mask columns#
kiwi fabric column-mask-add --role <role-id> --table customers --column account_number \
--strategy mask_partial --keep-suffix 4
| Strategy | Effect |
|---|---|
deny (default) |
The column is not available to the role |
mask_null |
The column is returned as null |
mask_redact |
The value is replaced by fixed text (--replacement, default ***) |
mask_partial |
Part of the value is masked, with --keep-prefix and --keep-suffix characters left visible |
Why enforcement is safe#
Row filters and column rules are applied before the in-process engine sees the fetched rows. That closes a side channel where a permitted aggregation could otherwise reveal denied source data. The same rules apply to AI-generated queries, because an assistant runs as the asking user.
Authentication options#
Users can sign in with a password, with an API key, or with Kerberos/SPNEGO (kiwi fabric login --kerberos). Passwords and keys are managed with user-add, password-change, key-add and key-revoke. In the Web UI, enter a user id on the Keys tab to load and manage that user's keys.

Expected result
- Users see only the rows and columns their roles allow, on every network surface