Skip to main content

0005: IAM Multi-Tenancy Mapping Strategy

Date: 2025-08-04

Status: Accepted

Context

The Citadel platform must be flexible enough to support various customer deployment scenarios. These range from a high-density public SaaS offering to private deployments for large enterprises. A key consideration is that even a private, self-hosted deployment may need to be multi-tenant (e.g., a holding company managing multiple subsidiary companies, where each subsidiary is a distinct Tenant). Therefore, the iam-service needs a flexible strategy for mapping a logical Citadel Tenant to the concepts in the underlying Identity Provider (IdP), such as R-Auth or Keycloak. This decision has significant implications for scalability, administrative overhead, and the ability to support enterprise user federation.

Options Considered

  1. Tenant-per-Realm/Organization: Each Citadel Tenant is mapped to a dedicated, isolated "Realm" or "Organization" within the IdP.

    • Pros: Provides the strongest possible data isolation at the IdP level. Allows for per-tenant branding, user federation, and identity policies.
    • Cons: High operational overhead. Creating a new realm can be a slow, resource-intensive process. This model may not scale to thousands of tenants and can make cross-tenant administration difficult.
  2. Shared Realm with Group/Attribute-Based Tenancy: All Citadel Tenants and their users exist within a single, shared IdP realm. Tenancy is enforced by assigning each user a tenant_id attribute/claim.

    • Pros: Extremely scalable and performant. Creating a new "tenant" is a simple metadata operation. Low administrative overhead.
    • Cons: Relies on the application layer (API Gateway, services) to enforce tenancy based on token claims. Weaker isolation within the IdP itself.

Decision

We will adopt a flexible, hybrid strategy that supports two distinct tenancy isolation models. The choice of model is a configuration decision for each Citadel installation, independent of whether it is a public SaaS or a private self-hosted deployment.

  1. Model A: High-Density Multi-Tenancy (Shared Realm). This is the default and recommended model. All Citadel Tenants and their users exist within a single, shared IdP realm. Tenancy is enforced by assigning each user a tenant_id attribute/claim. This model is ideal for our public SaaS and for private deployments managing multiple related entities (e.g., a holding company's subsidiaries) due to its scalability and low operational overhead.

  2. Model B: High-Isolation Multi-Tenancy (Realm-per-Tenant). This is an optional, high-isolation model. Each Citadel Tenant is mapped to a dedicated, isolated "Realm" or "Organization" within the IdP. This model is for enterprise customers who have stringent isolation requirements between their business units or need to configure per-tenant identity federation (e.g., connecting each subsidiary to a different corporate IdP).

The IdPAdapter abstraction within the iam-service is responsible for hiding this complexity from the rest of the application. The service's use cases (e.g., CreateTenantCommand) will interact with the adapter, which will then execute the appropriate strategy based on the deployment model or tenant tier.

Security Implications for Claims Enrichment

The choice of the Shared Realm model (Model A) has a direct and critical impact on the claims enrichment architecture. In a shared realm, a malicious tenant could create a role with the same name as a global role (e.g., "Super Admin").

To mitigate this privilege escalation risk, the iam-service's claims enrichment endpoint must generate scoped role names for all tenant-specific roles. As defined in ADR-0023, tenant roles are returned in the format tenant_id:role_name, while global roles are returned unscoped. This ensures that downstream services can safely distinguish between tenant-level and global-level permissions.

Consequences

Positive:

  • Deployment Flexibility: The architecture can cater to both high-density and high-isolation tenancy models, supporting a wide range of customer needs from public SaaS to private enterprise deployments.
  • Scalability: The default shared-realm model scales to hundreds of thousands of tenants with minimal overhead on the IdP.
  • Performance: In the shared-realm model, tenant creation is nearly instantaneous, improving the user onboarding experience.
  • Enterprise Integration: The realm-per-tenant model provides a clear path for deep enterprise integration, including user federation (SSO) and custom security policies, which are often key requirements for large customers.

Negative:

  • Implementation Complexity: The IdPAdapter and the iam-service application logic must be able to handle both tenancy models. This adds branching logic and increases the complexity of implementation and testing. For example, creating a tenant becomes a conditional operation.
  • Application-Level Enforcement: The security of this model is critically dependent on the API Gateway and all downstream services correctly inspecting the tenant_id claim in the JWT and using it in every single data query. There is no IdP-level safeguard preventing a developer from forgetting a WHERE tenant_id = ? clause.
  • Mitigation: This risk will be mitigated through a combination of:
    1. A standardized, shared authorization client library that makes tenant-scoped data access the default.
    2. Mandatory peer reviews for all data-accessing code.
    3. Automated tests that specifically check for multi-tenancy data leaks.