Multi-Tenancy¶
Cresco supports multiple mutually-distrusting tenants sharing one physical fabric — the same brokers,
the same inter-broker bridges — with end-to-end isolation. It builds directly on the
security model (the tenant is cryptographically bound into each node's certificate DN as
O=<tenant>).
Everything here is gated by tenant_namespacing (default off → the fabric is unchanged). The full design
and threat model live in the tenant-isolation design doc; see Design Docs.
The principle: one global invariant, enforced locally¶
A message stamped tenant T only ever lives on destinations prefixed
T.<tenant>., and is reachable only by a connection authenticated as T.
Because the tenant is both cert-bound (identity) and name-carried (a destination prefix), every broker enforces the invariant with a purely local string check — no coordination — so it holds across bridges and across globals.
Destination namespacing¶
Both controlled channels are qualified with the owning tenant:
| Channel | Raw | Namespaced |
|---|---|---|
| MsgEvent inbox queue | region_agent |
T.<tenant>.region_agent |
| Data plane topics | agent.event … |
T.<tenant>.agent.event … |
- Producers stamp the origin tenant onto the message (
cresco_tenant, preserved across relays) and qualify the forward destination with the message's tenant, so every relay produces the identical queue name. - Leaf agents (network clients) consume only their own
T.<tenant>.inbox. - Infra controllers (on
vm://, multi-tenant relays) consume theT.*.wildcard inbox, so they relay every tenant.
A cross-tenant send therefore lands in a queue nobody consumes and is denied by the ACL — isolation is enforced twice over.
Role-based authorization¶
Enforced at every broker by TenantPolicy via CrescoAuthorizationBroker:
| Role | Can touch |
|---|---|
TENANT |
only its own T.<tenant>. subtree — cross-tenant subscribe/publish is denied |
SUPERUSER |
every tenant (god view) — for the infrastructure and for admin/dashboard clients whose tenant is in broker_superuser_tenants |
This closes a real hole in the flat-name scheme: previously a tenant could write into a same-region
peer's region_agent inbox; with tenant-scoped inboxes that is denied.
What is and isn't guaranteed¶
Guaranteed (with mutual TLS + broker_security_enabled + tenant_namespacing): a tenant client cannot
subscribe to or publish into another tenant's subtree at any broker in the mesh; identity is
non-spoofable.
Not guaranteed by this layer (documented, with tiered mitigations): a compromised broker is trusted infrastructure and can see all tenants (mitigation: dedicated per-tenant bridges + payload encryption); payloads at rest inside a transit broker are readable by that broker (mitigation: payload encryption); advisory topics can leak destination names (not contents). See the design doc's threat-model section.
Enabling it¶
Turn on the security stack first, then namespacing, staged region-by-region:
-Dsecurity_regional_ca=true
-Dbroker_require_client_auth=true
-Dbroker_security_enabled=true
-Dtenant_namespacing=true
-Dtenant_id=<tenant>
-Dbroker_superuser_tenants=cresco-system # for admin/god-view clients
Proven by tenant_namespacing_test (federation forms + zero self-denial under namespacing; TENANT
confined; SUPERUSER god view) with no regression across the security/isolation suites.