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

Isolation model

RuleFlow runs pooled multi-tenant by default: shared services and a shared database, with every row/partition scoped by the caller’s verified tenant claim. The model, in 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 pinned structurally, not by convention. A conceptual introduction is in Tenancy & isolation; this page goes one layer deeper, into where the pooled model’s shared blast radius is mitigated and where it is still open.

Root of trust for the tenant claim

  • Direct userstenant is a per-user attribute mapped into the access token by a default client scope present on every client (studio, control-plane, CLI). It is admin-provisioned: self-service registration is disabled, so no user can choose their own tenant.
  • Federated (SAML) users — the critical case. When a tenant’s SAML IdP brokers in, the tenant claim is set by a mapper hardcoded at onboarding time to the tenant that IdP was onboarded for. The SAML assertion’s own tenant attribute is ignored — an IdP cannot assert a different tenant. Brokering additionally requires signed assertions (blocking XML signature wrapping) and disables email-based trust (blocking account takeover via a spoofed email claim).
  • Service accounts — the control plane’s own machine client has no user and therefore no tenant attribute; its tokens carry no tenant claim at all. This is safe only because of reject-on-missing: a tenant-less token is 403 on every tenant-scoped route. The standing rule: nothing may ever treat a missing tenant as a wildcard.

Three enforcement layers

  1. Identity — the claim’s provenance above.
  2. Contract — every persistence method takes tenant as a required parameter; there is no method that reads across tenants. This is the load-bearing layer: because tenancy is a parameter of the storage interface itself, a handler cannot even express a cross-tenant query — it’s a compile-time impossibility, not a code-review hope.
  3. Infrastructure — tenant is the leading dimension of physical data layout: partition keys, index leading columns, and mandatory search filters all lead with tenant.

Cross-tenant access looks like “not found”

Fetching another tenant’s object by id returns the same typed not-found error whether the id doesn’t exist or belongs to someone else — a 404, never a 403 that would reveal the object exists. Listings for another tenant are simply empty.

project is a label, not a boundary

project is an unvalidated grouping label within a tenant. There is no isolation between two projects belonging to the same tenant — any member of a tenant can read any of that tenant’s projects. If you need per-project confinement (e.g. contractors restricted to one project), that is a new control on top of this model, not something the platform enforces today.

The shared blast surface, and what mitigates it

Pooled tenancy means several resources are genuinely shared. Here is the honest inventory:

Shared resourceRiskStatus
One API gatewayone tenant’s traffic degrades othersPer-tenant rate quota — live
One relational database + one NoSQL tablenoisy queries, hot partitionsRow/partition-scoped by tenant; no per-tenant DB resource quota
One decision-execution compute poola high-fanout tenant can starve others’ decision callsUnaddressed — no reserved/provisioned concurrency per tenant yet
One encryption keyshared request quotaPer-tenant context is bound into every envelope (see Encryption); key-level caching deferred
No resource quotas on stored executions/artifactsunbounded growthArtifact storage is quota-capped; execution/task retention is not yet bounded

Isolation tiers

Pooled is the only tier that runs in production today. Bridge (per-tenant schema/database, shared services) and silo (a fully dedicated stack per tenant) exist as deployment tooling for a customer that contractually needs stronger separation, but there is no app-level routing that switches a live tenant between tiers yet — moving a tenant is a data-placement operation the platform doesn’t automate today, not a flag you flip. Because authorization is always “act as the token’s tenant” regardless of tier, the API surface and authored rules are identical across all three — the tier only changes where the bytes physically live.

What this model does not (yet) cover

  • Per-tenant compute isolation (decision-execution concurrency) — open; a candidate mitigation is reserved/provisioned concurrency per environment, escalating to silo for a tenant that needs a dedicated compute envelope.
  • Data residency / region pinning — open.
  • Retention on execution/human-task data — no automatic expiry yet; accumulates until a retention policy is added.

These are documented gaps, not silent ones — see the platform’s design records for the sprint that will close each.