2.3 KiB
2.3 KiB
Tenant Model and Row-Level Security
Global vs Tenant-Private
- Global objects: Public or shared data that can be read across tenants (e.g. BIC, LEI, BIN range metadata). Stored with
tenant_idnull or a dedicated "global" tenant. Used for cross-tenant lookup when the rail has a public identifier scheme. - Tenant-private objects: Participant-specific data, merchant IDs, terminal IDs, contractual endpoints. Always scoped by
tenant_id. Queries must supply tenant (from auth or request) so that only that tenant's rows are visible.
Enforcement
- Postgres Row Level Security (RLS): Enable RLS on
participants,identifiers,endpoints,capabilities,credentials,policies, and optionallyrouting_artifacts. Policies:tenant_id = current_setting('app.current_tenant_id')or equivalent. Global rows: allow whentenant_id IS NULLor when reading public identifiers. - Application layer: Resolver and Admin API must set tenant context (e.g. from JWT or request parameter) before querying. Never return rows from another tenant.
- Per-tenant encryption: For Tier 2+ data (see data-classification), use per-tenant encryption keys so that key compromise affects only one tenant.
Caching
- Cache key includes tenant: same request for different tenants must not share a cache entry.
- Optional per-tenant TTL or invalidation rules (e.g. shorter TTL for high-churn tenants).
- Negative cache: key includes tenant; invalidate on any change for that tenant.
RLS Policy Summary
| Table | Policy (conceptual) |
|---|---|
| participants | WHERE tenant_id = current_tenant OR tenant_id IS NULL |
| identifiers | JOIN participants; same tenant or global |
| endpoints | JOIN participants; same tenant |
| capabilities | JOIN participants; same tenant |
| credentials | JOIN participants; same tenant |
| policies | WHERE tenant_id = current_tenant |
| routing_artifacts | WHERE tenant_id = current_tenant OR tenant_id IS NULL |
Apply current_tenant from connection/session (e.g. set by API after auth).