5.0 The RS2 security model

This section is the map for all of Part 5. Read it first: it names the three tiers of authority, the one invariant they enforce, and where each later section fits.

The invariant

Authority originates only from configuration. Authored content can exercise authority that configuration already granted — it can never mint new authority.

Configuration is the operator-/installer-controlled surface: a mount's access, a pipeline spec's access, capability grants, elevation roles, operatorRoles, and quotas. Content is what authors write: pipeline logic, custom code, data. A request, a pipeline, or a code bundle can only ever do what configuration has already permitted — it can never grant itself more. Every rule below is a consequence of holding this line.

Three tiers

RS2 separates who may act (roles) from who may define the rules (the operator and installer tiers). These are orthogonal: a role is meaningful only where config references it; operator/installer status is about changing config.

Tier Scope Controls Rooted in
Installer the server / host tenancy & domains, per-tenant quotas, which capabilities a tenant may use at all the deployment (config file / process), never any tenant's API
Operator one tenant authorization config: mount & spec access, capability grants, elevation roles, role assignment a role listed in the tenant's operatorRoles (bootstrapped by the installer)
Roles one application nothing on their own — they gain meaning only when an access spec references them (A, U, editor, …) records in the users dataset (5.2)

Installer — the cohabitation envelope

The installer sets the envelope every tenant lives inside: its resource quotas (concurrency, body size, wall-clock, outbound-call budget) and which capabilities exist for it (outbound HTTP, the JS engine, named stores). These come from server config, not from any tenant's config — so an operator cannot raise their own quotas or grant a capability the installer withheld. Want isolation between teams? Give them separate tenants; that boundary is the installer's, not something a tenant operator can cross.

Operator — the only authority over authorization

An operator is any principal holding a role named in the tenant's operatorRoles (a space-separated list). Operators alone may change anything that defines authorization:

  • a mount's access (via the /services config API or the on-disk config),
  • a pipeline spec's inline access field (5.4, Part 7),
  • capability and elevation grants on a mount,
  • assignment of operator roles to users.

Because roles have no inherent ordering, RS2 does not try to let non-operators delegate scoped slices of authority — that is a notorious source of privilege-escalation bugs. The line is bright: only operators define authority.

Bootstrap / root of trust. operatorRoles and the first operator credential cannot come from the API (you would need to already be an operator). The installer seeds them in the on-disk tenant config; operators then self-manage via /services. Secure default: no operatorRoles ⇒ no API operator — the authorization config is editable only from the file until an installer seeds one.

How requests are authorized

Every request is gated at its mount by the action its HTTP method maps to (5.4): read (GET/HEAD/OPTIONS), write (PUT/PATCH), delete (DELETE), invoke (POST and other non-idempotent verbs). The mount's access object names the roles each action requires.

  • No ambient trust. A call is authorized by the principal it carries. An internal call (a pipeline step, a granted capability, a guest fetch) is not trusted just for being internal — it propagates the originating principal and is checked exactly like an external call. A logged-in user's pipeline can never reach past that user's own access.
  • System calls. Runtime-originated calls the operator configured (a scheduler tick on a mount's schedule) are trusted — they cannot be forged from the wire and exist only by operator config.

Elevation — the one way to cross a boundary, bounded by config

A pipeline can deliberately reach a mount its caller could not, via the gateway pattern: the pipeline mount is configured (by an operator) with an elevate role, and a step marked elevate adds that role to the call's principal — keeping the caller's identity (audit, path-scoped grants) intact. An anonymous caller is given a synthetic principal carrying just that role (the login gateway). The authority is the mount config, never the spec flag: without a configured role the flag is inert, and an elevate role may not be an operator role. Elevation is transitive (the added role rides along nested hops), so keep an elevate-mount's authoring surface operator-locked.

What each section covers

  • 5.1 the auth service — turning credentials into tokens.
  • 5.2 users, password hashes, and roles — where roles live.
  • 5.3 tokens, cookies, and bearer headers — how identity travels.
  • 5.4 role specs on mounts — the read/write/delete/invoke vocabulary, path-scoped grants, and inline per-spec pipeline access.
  • 5.5 CORS and the CSRF guard — the external-only concerns.

Manual home · Next: 5.1 The auth service →