Backends d’Isolation Tenant¶
Updo Backend supporte trois stratégies d’isolation des données tenant.
Le choix du backend est configuré via MULTITENANT['ISOLATION_BACKEND'].
Module : src.share_kernel.infrastructure.isolation
Factory¶
- src.share_kernel.infrastructure.isolation.get_isolation_backend() → TenantIsolationBackend¶
Retourne le singleton du backend d’isolation configuré. Lit
MULTITENANT['ISOLATION_BACKEND']et instancie le backend approprié.- Raises:
ConfigurationError – Si le type de backend est inconnu.
Schema Backend (schema)¶
Principe : Chaque tenant obtient un schéma PostgreSQL dédié
(tenant_<slug>). Le search_path est dynamiquement configuré
pour chaque requête.
Recommandé pour : Jusqu’à ~2 000 tenants.
- class src.share_kernel.infrastructure.isolation.schema_backend.SchemaIsolationBackend(TenantIsolationBackend)¶
- activate_tenant(tenant, connection) → None¶
Configure
search_pathvers le schéma du tenant + public. UtiliseSET LOCAL(transaction-scoped) pour la compatibilité PgBouncer. Utilisepsycopg.sql.Identifier()pour prévenir l’injection SQL.Applique aussi
statement_timeoutpour la protection contre les « noisy neighbors ».
- create_tenant_storage(tenant) → None¶
Crée le schéma PostgreSQL et exécute les migrations.
CREATE SCHEMA IF NOT EXISTS tenant_acme_corp;
- destroy_tenant_storage(tenant) → None¶
Supprime le schéma PostgreSQL. DESTRUCTIF.
DROP SCHEMA IF EXISTS tenant_acme_corp CASCADE;
Exemple :
# Configuration
MULTITENANT = {
'ISOLATION_BACKEND': 'schema',
'SHARED_SCHEMA_NAME': 'public',
'TENANT_SCHEMA_PREFIX': 'tenant_',
}
# Le middleware active automatiquement le schéma
# SQL généré : SET LOCAL search_path TO "tenant_acme_corp", "public"
RLS Backend (rls)¶
Principe : Schéma unique avec des politiques RLS PostgreSQL.
Le tenant courant est défini via SET app.current_tenant.
Recommandé pour : 2 000+ tenants ou PgBouncer en mode transaction pooling.
Prérequis : Toutes les tables tenant-specific doivent avoir une colonne tenant_id.
- class src.share_kernel.infrastructure.isolation.rls_backend.RLSIsolationBackend(TenantIsolationBackend)¶
- activate_tenant(tenant, connection) → None¶
Exécute
SET LOCAL app.current_tenant = '<tenant_id>'.SET LOCALest transaction-scoped (compatible PgBouncer).
- deactivate_tenant(connection) → None¶
Efface
app.current_tenantavecSET LOCAL app.current_tenant = ''.
- create_tenant_storage(tenant) → None¶
Active RLS et crée les politiques d’isolation pour toutes les tables ayant une colonne
tenant_id.Politique créée :
ALTER TABLE <table> ENABLE ROW LEVEL SECURITY; ALTER TABLE <table> FORCE ROW LEVEL SECURITY; CREATE POLICY tenant_isolation_<table> ON <table> USING (tenant_id = current_setting('app.current_tenant', true)::uuid) WITH CHECK (tenant_id = current_setting('app.current_tenant', true)::uuid);
- destroy_tenant_storage(tenant) → None¶
Supprime toutes les lignes du tenant (
DELETE WHERE tenant_id = ?). UtiliseSET CONSTRAINTS ALL DEFERREDpour éviter les problèmes d’ordre FK.
Shared FK Backend (shared_fk)¶
Principe : Schéma unique, filtrage au niveau applicatif via tenant_id FK.
Aucune garantie au niveau base de données.
Recommandé pour : Prototypage et petits déploiements.
- class src.share_kernel.infrastructure.isolation.shared_fk_backend.SharedFKIsolationBackend(TenantIsolationBackend)¶
- activate_tenant(tenant, connection) → None¶
No-op. Le filtrage est géré par les managers et querysets Django.
Comparaison des backends¶
Critère |
Schema |
RLS |
Shared FK |
|---|---|---|---|
Isolation DB |
Forte (schéma dédié) |
Forte (politique PostgreSQL) |
Faible (applicatif) |
Tenants max |
~2 000 |
Illimité |
Illimité |
PgBouncer |
Oui (SET LOCAL) |
Oui (SET LOCAL) |
Oui |
Migrations |
Par tenant |
Partagées |
Partagées |
Performance |
Haute (index séparés) |
Haute (RLS natif) |
Moyenne |
Complexité |
Élevée |
Moyenne |
Faible |