TessariDBDocs
  • 0.34.2-betalatest
  • 0.34.1-beta
  • 0.34.0-beta
  • 0.33.4-beta
  • 0.33.3-beta
  • 0.33.2-beta
  • 0.33.1-beta
  • 0.33.0-beta
  • 0.32.0-beta

Authority

A kind and a reach. Because a rank can only say more or less, and the rules an operator actually has are not ranked.

Three roles are a rank, and a rank can only say more or less. The rules an operator actually has are not ranked:

  • the person who runs the cluster has no business reading the records;
  • the identity that ingests events writes, and must not be able to drop a table;
  • and — the case this exists for — reading or writing inside a namespace must not confer creating and dropping databases in it.

No position on a ladder of three says any of those, because each one is some of a rung and none of the next.

So an authority is a pair: a kind, and the reach it is held over.

The five kinds

kindwhat it is
readread records
writewrite records
managecreate and drop the container's children — databases in a namespace, tables in a database — and define structure on them
governdeclare users and move authority around
operatetopology, replicas and the backup file: running the thing rather than using it
replicatecollect the log as a peer — store-wide only, never at namespace reach

replicate is the one kind that cannot be granted at a narrower reach, and the reason is what it would let somebody do. A subscription hands a machine the log inside its reach, users and credential hashes included; a namespace owner who could grant it would be able to admit a follower of their own choosing. So the kind is store-wide or it is refused, and which records a peer actually collects is decided by the REPLICATES clause on its membership row rather than by the grant. See Adding a node.

Nothing in that table implies anything else in it. write over a namespace does not confer manage over it, which is the sentence the whole model exists to make true: writing records where databases live does not confer creating or dropping them.

The three reaches

STORE, NAMESPACE <name>, DATABASE <namespace>.<name>. A kind held at a container is held over everything inside it and over nothing outside — the one implication in the model, and it runs downward only.

Every reach is led by a keyword, so that a table name can never be read as a reach. STORE is a reserved word for exactly that reason: before it was reserved, GRANT read ON store TO ada was a statement about the table named store, and a reach spelled as a bare word would have silently widened it.

DEFINE TABLE store;

Refused at the token. That is what reserving it cost, and it is the cheaper half of the trade.

Saying it

A user can be declared with the set directly, instead of with a role:

DEFINE USER ops AUTHORITIES operate PASSWORD 'a long one';
DEFINE USER ingest ON prod.shop AUTHORITIES write PASSWORD 'a long one';
DEFINE USER nadia ON NAMESPACE prod AUTHORITIES manage PASSWORD 'a long one';

ops runs the node and reads no records. ingest writes into one database and cannot define a table there. nadia creates and drops databases in prod and reads nothing in them — the headline rule, in one statement.

Authority moves with the same two verbs a grant uses, over a reach instead of a table:

GRANT manage ON DATABASE prod.shop TO kim;
GRANT read ON NAMESPACE prod TO kim;
REVOKE manage ON DATABASE prod.shop FROM kim;
REVOKE operate ON STORE FROM kim;

A kind the language does not have is refused where it is written, and so is a reach that names nothing:

GRANT scribble ON STORE TO nobody;

NoSuchAuthority.

Nobody hands out what they do not hold

GRANT is refused when either half exceeds the granter's own — a wider kind, or a wider reach. An owner of one database cannot mint an authority over the store, and cannot move somebody sideways into a kind they do not hold themselves.

Without that rule every other rule on this page would be one statement away from being decoration: the escalation refused at the front door would simply walk in through the act of granting.

The three roles still mean what they meant

A role is one spelling of a set, and both spellings are kept.

rolethe set it stands for
viewerread
editorread, write, manage
ownerread, write, manage, govern, operate

Each at the reach the user was declared at.

That mapping is deliberately unchanged for users who already exist — including editor, which bundles write with manage and is therefore exactly the combination this model was built to make refusable. Narrowing it on an upgrade would be an outage delivered as a migration. What the model changes is what can now be said; it does not reach back and re-decide what was already promised.

A declared tenancy is asked first

The ON is not a default a grant overrides — it is the boundary the session is inside, a second and independent confinement asked before the held set is consulted. Otherwise ON would be decoration, and the escalation refused at the declaring side would simply move to the granting side.

So GRANT read ON NAMESPACE staging TO nina, where nina was declared ON NAMESPACE prod, is refused. The two tenancies miss each other, so the holding could never be consulted — and a statement that returns ok and has no effect is worse than either honest answer, because the operator's only evidence that a grant landed is the statement not complaining, and the next person reads the holding back out of INFO FOR USER and believes it.

The test is overlap in either direction, not containment in one. manage ON STORE granted to a user of prod is perfectly usable inside prod, since containment runs downward, and refusing it would be refusing a working grant. REVOKE is not refused this way either: taking away a holding that could never be used is exactly how one stored before this rule existed gets cleaned up.

The confinement is enforced where a session selects a container, which means USE is the first thing that has to succeed:

USE NAMESPACE staging;

OutsideTenancy, for a user of prod — before any table is named, and without saying whether staging exists, because a refusal that answers that has answered the question it declined.

Taking it away reaches a connection that is already open

This is the property a permission system is least often asked about and can least afford to get wrong, so it is stated as a number rather than as a reassurance.

whatwhen it takes effect
ALTER USER, DROP USER, REVOKEthat session's next statement
a running subscriptionwithin one poll round — at most 250 ms

Neither waits for the connection to close. A session re-reads its own user from the catalog on every statement, and a feed re-asks on every round, so a revocation does not stop at the edge of whoever happened to be connected when it was issued.

Reading who has what

Two questions, and the store answers both:

INFO FOR USER kim;
INFO FOR ACCESS TO TABLE orders;

The first is what does this person reach. The second is who reaches this object, which is the question an incident actually starts from, since the thing you are holding is the table.

Both answer from the same check the statements themselves pass through. The second is worth saying out loud about: for every user, the store signs a throwaway session in as them and puts a real USE, a real SELECT and a real DELETE to the ordinary authorization path. It does not work reachability out from grants and roles a second way — two opinions about one rule agree until they do not, and when they stop nothing fails: the report simply becomes fiction, read by the one person who has no way to check it.

Authority — TessariDB