Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Tenancy & isolation

RuleFlow is multi-tenant by default. Every control-plane operation is scoped to the caller’s verified tenant claim — there is no request in the API where tenant is inferred from a URL path, a query string, or a body field.

The whole model reduces to one sentence: every operation acts only as the tenant in the verified token. Its strength depends on exactly two things: the token cannot lie about the tenant, and no code path can forget the filter. Both are structurally enforced — see below.

The tenant boundary is the token, never the request

A request with no tenant claim (or an empty one) is rejected 403 on every tenant-scoped route — there is no default tenant and no god-tenant. A caller cannot ask for another tenant’s data by changing a path parameter; the only tenant they can act as is the one in their token.

project is a label within a tenant, taken from the path — not a security boundary. There is no isolation between two projects of the same tenant; any of that tenant’s members can read any of its projects. Two tenants may both use project=lending without collision (the tenant is the partition).

Three enforcement layers

  1. Identity (Keycloak). The tenant claim’s provenance: admin-provisioned for direct users, hardcoded per-IdP at SAML brokering onboarding time for federated users (the SAML assertion’s own tenant attribute is ignored — an IdP cannot assert a tenant other than the one it was onboarded for). Service-account (machine) tokens carry no tenant claim at all, and are therefore rejected on every tenant-scoped route by construction.
  2. Contract (the Store). Every store method takes tenant as a required parameter — the persistence interface documents “all methods are scoped to a tenant,” and both the Postgres and in-memory implementations filter by it. No method exists that reads across tenants: a handler physically cannot express a cross-tenant query.
  3. Infrastructure. Tenant is the leading dimension everywhere data rests — the DynamoDB partition key is TENANT#<t>#PROJ#<p> for executions/human tasks/connector bindings, search queries carry a mandatory tenant filter, and relational indexes lead with tenant.

Cross-tenant access is “not found,” not “forbidden”

Fetching another tenant’s artifact or release by id returns a typed not-found error → HTTP 404, the same response whether the id doesn’t exist at all or belongs to someone else. This means the existence of another tenant’s objects is never revealed to a caller who doesn’t have access to them.

RBAC is orthogonal to tenancy

Realm roles (approver, admin, …) gate what an authenticated caller may do; tenancy gates whose data they can do it to. A role never widens tenant scope — a privileged deploy still resolves the release within the caller’s own tenant.

Isolation tiers

TierWhat is sharedStatus
PooledShared services + database; row/partition-level scoping by tenant claimThe only tier that runs today; default for all tenants
BridgeShared services; per-tenant schema/databaseTooling exists; no app-level routing yet
SiloDedicated stack per tenantDeployment tooling exists; nothing deployed yet

Because authorization is always “act as the token’s tenant,” moving a specific tenant from pooled to bridge/silo is a data-placement change, not an authorization-model change — the API surface and authored rules are unaffected either way. Pooled is the only tier live in production today; bridge and silo are a committed escalation path for a customer that needs stronger isolation, not a flag you flip per tenant yet.

Dev/insecure mode

A local development mode exists that parses a JWT without verifying its signature, but it still requires the tenant claim — local runs behave identically with respect to scoping. It must never run in a shared or production context; it trusts any unsigned token’s tenant claim.

See Security § Isolation model for the deeper security-review writeup (shared blast surface, mitigations, and what remains open).