Teams, roles and per-index access for Elasticsearch
One set of cluster credentials, stored once, used by the whole team. Each person sees only the index patterns they were granted, and FlatQL checks that on every request.
The model in one paragraph#
A workspace has connections and members. An owner or admin adds a connection with the cluster's credentials; the credentials are encrypted on FlatQL's servers and are never shown again, to anyone. Members get grants: a connection, a list of index patterns, and whether writes are allowed. When a member runs anything, FlatQL resolves the indices the request touches and refuses it unless every one of them is covered by a grant. The cluster sees a single identity; the per-person rules live in FlatQL.
System roles#
| Role | Access | Can manage |
|---|---|---|
| Owner | Every connection, read and write | Users, roles, billing; cannot be removed |
| Admin | Every connection, read and write | Users, roles, grants, audit log |
| Member | Only what roles and direct grants allow | Nothing |
Every workspace has exactly one owner. Admins can promote a member to admin or back. Owners and admins always have full access, so grants cannot be set on them; to restrict someone, make them a member first.
Named roles#
A named role is a reusable bundle of grants, for example Log readers with logs-* read-only on the production connection, or Catalogue editors with organizations, suppliers and writes allowed on staging. Create roles under Users & roles → Roles, give each a name and description, and tick the connections it covers with the patterns and the write switch for each.
Assign any number of roles to a member. On top of roles you can add direct grants to one person for a connection the roles do not cover. A member's effective access on a connection is the union of every pattern from their roles and direct grants; writes are allowed if any of them allows writes.
Patterns use * and ?, as in logs-2026-* or orders. Separate several with commas. A connection with no grant at all is not just read-only for that member: it does not appear in their connection list.
What a member can and cannot do#
A member with logs-* read-only on production:
SELECT service, COUNT(*) AS errors
FROM "logs-*"
WHERE level = 'ERROR'
GROUP BY service
ORDER BY errors DESC
LIMIT 20;
This runs. These do not:
SELECT * FROM orders LIMIT 10;→ Index not allowed: you have no access to orders.- A query over
*orlog*→ Index not allowed: your access does not cover the pattern. A pattern in a statement is accepted only when a grant covers everything it could match, so a wildcard cannot widen a grant. - A bulk delete, a document edit or a data load → Read-only access.
The same checks apply to the Browse page, the Console, exports, data loading and Ask FlatQL. Ask FlatQL only sees the mappings of indices the member may query.
Enforcement#
FlatQL enforces grants on its own backend, on every request, before anything is sent to the cluster:
- The request names a connection. FlatQL checks the member may see it and loads their scope (patterns and write flag).
- For SQL, the tables are extracted from the statement; for the Browse page, Console and loader, the index in the request is used. Each index or pattern is matched against the scope.
- Writes are refused when the scope is read-only. The read-only check recognises the Elasticsearch read APIs by method and path, so
_search,_count,_sql,_mappingand_catpass while_bulk,_delete_by_queryorPUT /indexdo not.
Nothing is created on the cluster: no users, roles or API keys per person. The cluster only ever sees the credentials stored on the connection. If you later rotate those credentials, you change them in one place and no member notices.
Production connections and read-only mode#
Each connection has an environment: production, staging or local. A connection can be marked read-only; FlatQL then rejects any request that is not a read, for every role, including the owner. Writes can be turned on for one session from the connection switcher by someone whose role allows it.
Under Settings → Guard-rails, Production connections start read-only makes every new production connection read-only from the moment it is created. The same page controls the confirmation step for destructive requests (deleting an index, _delete_by_query, reindex, cluster settings) and the block on wildcard deletes such as DELETE /logs-*.
Audit log#
Owners and admins see Users & roles → Audit log, a list of who did what, when, on which connection. Recorded actions include sign-ins and registrations, connection create, update and delete, write-mode changes, exports (with the statement text and format), data loads (file name and size, or API URL), document creates, edits and deletes, index creates, deletes, mapping and settings changes, reindexes, console requests, every Ask FlatQL question with the statement it produced, invitations, role and grant changes, and billing events. The log shows up to 1,000 recent entries.
Access graph#
The Graph tab draws the system roles and the named roles on top and the users below, with a line from each role to each person who holds it. It answers "who can touch production?" at a glance and is the quickest way to spot a member who has collected roles they no longer need.
Inviting members#
Users & roles → User asks for an email and a role, admin or member. The person receives an email with a link that works for 7 days; if they already have a FlatQL account they join with it, otherwise they create one on the way in. Pending invitations are listed with a revoke action.
An account belongs to one team. Someone who already belongs to another workspace cannot be invited; they need a separate account with another email. Removing a member ends their access immediately; they keep their account and get an empty workspace of their own. A member can also be disabled without being removed.
Plan requirements#
Shared connections and the roles described here need a Team workspace, which has no member limit and includes named roles, per-index grants and the audit log. The Free and Pro plans are single-user. See pricing and licensing and the index-level access use case.