Skip to main content

0036: Permissions Multi-Tenancy & Scoping Strategy

Date: 2025-11-08

Status: Proposed

Context

The permissions-service uses a single, shared ReBAC engine instance (SpiceDB) for all tenants. A naive implementation where object identifiers are simple strings (e.g., document:123) would create a massive security hole, as there would be no way to distinguish document:123 for tenant-A from document:123 for tenant-B.

We need a robust strategy to enforce data isolation at the application layer, as the underlying engine is not tenant-aware by default. The permissions-service itself must act as the gatekeeper.

Decision

We will use Namespaced Object Identifiers for all resources managed by the permissions-service.

  1. Format: The standard format for an object identifier will be object_type:tenant_id/object_id. For example: document:acme-corp/report-xyz.

  2. API Enforcement: The permissions-service API layer is responsible for enforcing this strategy. When a request comes in (e.g., to write a relationship), the service will: a. Extract the tenant_id from the caller's authenticated JWT. b. For every object identifier in the request payload, parse it and verify that its tenant_id matches the tenant_id from the JWT. c. If there is any mismatch, the request will be rejected with a 403 Forbidden error.

  3. System-Level Objects: For objects that are not tenant-specific (e.g., a global role_template), a special reserved namespace like system will be used. For example, role_template:system/super_admin. Only trusted internal services (identified via S2S auth) will be permitted to write relationships involving the system namespace.

Consequences

Positive

  • Strong Data Isolation: This application-layer enforcement provides a strong guarantee of multi-tenancy, preventing tenants from accessing or modifying each other's permissions.
  • Engine Agnostic: This strategy works regardless of the underlying ReBAC engine, as the logic resides in our adapter layer.
  • Clarity: The object identifiers become self-describing, making them easier to debug and audit.

Negative

  • Increased Identifier Length: Object IDs are longer and more complex.
  • Application Layer Responsibility: The responsibility for tenancy enforcement lies entirely within our permissions-service code. Any bug in this parsing and validation logic could compromise data isolation. This is an accepted responsibility.
  • Client Complexity: All client services must be aware of this namespacing convention when constructing object IDs to send to the permissions-service. This logic should be encapsulated in a shared library where possible.