Une API expose GET /invoices/{id}. Un utilisateur du tenant bleu remplace l’identifiant par celui d’une facture du tenant vert et reçoit un document valide, car le repository cherche seulement la clé primaire. L’authentification a réussi ; l’isolation a échoué.
Le problème et le risque se cachent derrière un code fonctionnel. Un premier signal faible est une méthode find(id) accessible sans contexte ; un second signal faible est un cache dont la clé contient l’identifiant métier mais jamais le tenant.
Le vrai enjeu consiste à rendre tout accès incomplet sans identité locataire vérifiée. Contre-intuitivement, un UUID imprévisible réduit l’énumération mais ne constitue aucune autorisation : une fuite de logs ou un lien partagé suffit à révéler l’identifiant.
Vous allez comprendre comment propager cette frontière depuis le token jusqu’aux lignes SQL, objets, caches, messages et fichiers, puis comment prouver les refus. Une intégration API gouvernée transforme cette frontière en invariant multi-tenant vérifiable.
Dans quels cas l’isolation tenant devient critique
Toute plateforme SaaS, API partenaire ou back-office partagé qui héberge plusieurs organisations doit isoler leurs ressources. La frontière concerne lecture, écriture, calcul, export, événement et métadonnées, pas seulement les tables principales.
Reconnaître la surface réellement partagée
Base, cache, moteur de recherche, stockage objet, data warehouse, queue et logs peuvent mutualiser l’infrastructure. Chacun nécessite une clé de partition et une politique cohérente avec le domaine.
Une architecture avec base dédiée par tenant réduit certains risques SQL sans protéger automatiquement token, cache ou URL signée. L’isolation reste une propriété de chaîne.
Qualifier les équipes concernées
Le protocole vise équipes API, sécurité, plateforme, data et support qui exploitent un produit multi-tenant. Il demande un owner de politique et un inventaire des composants consommateurs.
Les entrées sont identité, tenant, ressource, action et contexte ; les sorties sont autorisation ou refus. Chaque service applique la décision, tandis que l’audit conserve une preuve non ambiguë.
Écrire le modèle de menace
Le scénario principal n’est pas seulement un attaquant externe. Utilisateur légitime, intégration compromise, opérateur support, job mal routé ou bug de projection peuvent tous franchir une frontière pourtant invisible à leurs permissions globales.
Lister les chemins de confusion
Manipulation d’identifiant, header falsifié, cache collisionné, message sans contexte, jointure non filtrée et export global sont testés. Les chemins de lecture comme de modification reçoivent une gravité.
OWASP nomme Broken Object Level Authorization le défaut où une API ne vérifie pas que le sujet peut agir sur l’objet demandé. Ce risque reste distinct de l’authentification.
Définir l’impact métier
Divulgation, modification, suppression, agrégat latéral et existence d’un objet peuvent violer la frontière. Un code 404 versus 403 peut lui-même confirmer qu’une référence existe.
Le registre associe type de donnée, volume, obligations, détectabilité et geste de réponse. La priorité va aux chemins capables d’extraire ou modifier plusieurs ressources en une requête.
Établir l’identité du tenant
Le tenant actif doit provenir d’une relation approuvée entre principal authentifié et organisation. Un header, paramètre ou sous-domaine proposé par le client peut sélectionner un contexte, mais jamais l’autoriser seul.
Distinguer appartenance et contexte actif
Un utilisateur peut appartenir à plusieurs organisations. Le token ou la session indique tenant actif, tandis que le serveur vérifie l’appartenance et les droits à l’émission ou au changement.
Une identité machine reçoit elle aussi une relation explicite. Les comptes techniques globaux sont réservés aux opérations justifiées et protégés par une politique plus stricte.
Utiliser un identifiant stable
Le tenant possède une clé interne immuable distincte du slug, domaine ou nom commercial. Les renommages et domaines personnalisés ne modifient ainsi aucune partition de données.
Les références externes sont mappées avec namespace. Une même chaîne venant de deux partenaires ne doit jamais sélectionner accidentellement le mauvais tenant dans le contexte interne.
Construire un contexte tenant immuable
Après authentification, un composant crée un objet de contexte contenant tenant vérifié, principal, client, audience, scopes, corrélation et décision d’élévation éventuelle. Les couches aval le reçoivent sans le reconstruire depuis la requête brute.
Interdire le contexte optionnel
Les méthodes accédant à des données locataires exigent un type non nullable. L’absence de tenant échoue avant le repository, sauf interface d’administration globale distincte et auditée.
Un thread local ou une variable globale implicite facilite les fuites entre requêtes et workers. La dépendance explicite rend les tests et le passage asynchrone vérifiables.
Empêcher les substitutions tardives
Le contexte est immuable pendant la transaction. Changer de tenant exige une nouvelle décision d’autorisation et une nouvelle portée de trace, jamais une affectation au milieu du service.
Les entrées sont claims vérifiés et sélection ; les sorties sont contexte signé ou interne. L’auth middleware porte validation, journalisation, monitoring et refus par défaut.
Borner token et audience
Le token peut porter un tenant, une audience et des capacités. Le resource server valide signature, issuer, expiration, audience et contexte avant de considérer la ressource demandée.
Émettre un token spécifique au contexte
Une organisation active par token simplifie la décision et limite les dégâts d’un bearer volé. Changer d’organisation déclenche un échange ou une nouvelle autorisation contrôlée.
La RFC 8707 décrit les resource indicators et souligne qu’une ressource multi-tenant peut inclure la partie identifiant le tenant afin de restreindre l’audience plus précisément.
Combiner tenant, audience et scopes
Le tenant dit où, l’audience dit quel service, le scope dit quelle capacité. Aucun de ces axes ne remplace l’autorisation d’objet ou les contraintes métier.
La conception des scopes OAuth au moindre privilège complète directement l’isolation en bornant les opérations métier possibles dans le tenant déjà validé par le serveur.
Refuser le tenant fourni par le client
Une route comme /tenants/{tenantId}/orders reste utile pour adresser la ressource, mais le paramètre doit correspondre au contexte autorisé. Le serveur ne doit jamais le copier directement dans un filtre SQL.
Comparer sélection et autorisation
Le middleware résout le tenant de route, vérifie l’accès du principal puis construit le contexte. Une divergence retourne une réponse constante sans révéler l’existence ou le nom de l’organisation.
Pour une route sans tenant visible, la sélection vient exclusivement du token vérifié. Les deux styles partagent ensuite exactement la même interface de repository contextualisée.
Traiter sous-domaines et domaines personnalisés
Le host est normalisé, validé et mappé à une clé interne. L’en-tête transféré n’est accepté que depuis un proxy de confiance correctement configuré.
Une collision DNS ou un domaine expiré ne doit pas réattribuer les données. Le cycle de vie du mapping possède vérification de propriété, retrait et délai de sécurité.
Autoriser chaque objet demandé
Une ressource porte toujours son tenant d’appartenance. Toute lecture, mutation ou transition vérifie simultanément identité de l’objet, tenant du contexte et capacité métier demandée.
Rechercher dans la partition
Le repository expose findByTenantAndId(context, id) plutôt que find(id). L’objet d’un autre tenant devient systématiquement introuvable dans ce contexte avant même l’évaluation de la politique métier.
L’autorisation vérifie ensuite rôle, relation et état. Une facture du bon tenant peut rester interdite à un utilisateur sans droit comptable ou à un connecteur de lecture commandes.
Protéger les collections et agrégats
Liste, compteur, somme, export et recherche doivent intégrer le même prédicat. Une réponse vide correcte sur la fiche ne compense pas un total global qui révèle l’activité d’autres tenants.
Pagination et curseur incluent toujours partition ou signature vérifiable. Un curseur obtenu dans le tenant bleu ne peut jamais continuer une collection appartenant au tenant vert.
Appliquer la frontière en SQL
Chaque table locataire possède tenant_id non nul, indexé et inclus dans les clés uniques pertinentes. Les jointures propagent la contrainte depuis la racine jusqu’aux enfants.
Concevoir les clés et contraintes
Une clé étrangère composite peut imposer que l’enfant référence un parent du même tenant. Cette défense empêche une écriture applicative fautive de créer une relation croisée.
Les unicités métier deviennent souvent (tenant_id, external_id). Une contrainte globale involontaire peut sinon bloquer deux organisations légitimes utilisant exactement la même référence dans leurs systèmes externes.
Rendre le filtre difficile à oublier
Query builders et repositories contextualisés ajoutent le prédicat systématiquement. Toutes les requêtes SQL brutes passent une revue spécifique et des tests dédiés de mutation du tenant.
Le plan d’exécution doit utiliser un index commençant par tenant lorsque la distribution le justifie. La sécurité ne doit pas dégrader silencieusement chaque requête en scan global.
Renforcer avec la Row-Level Security
La Row-Level Security PostgreSQL peut ajouter une barrière au niveau base pour sélectionner et modifier seulement les lignes correspondant au contexte de session. Elle complète le domaine applicatif sans remplacer son autorisation.
Appliquer default deny
PostgreSQL indique qu’une table avec RLS activée et sans politique applicable adopte un refus par défaut. Les politiques USING filtrent les lignes visibles et WITH CHECK contrôle les nouvelles valeurs.
La connexion fixe le tenant dans une variable de transaction après authentification, puis le nettoie obligatoirement. Le pool ne doit jamais réutiliser une session avec ancien contexte.
Traiter les rôles de contournement
Superusers, propriétaires et rôles BYPASSRLS peuvent contourner les politiques selon configuration. L’application n’utilise donc jamais ces rôles privilégiés pour traiter le trafic locataire normal.
Les migrations et jobs globaux reçoivent identité dédiée, approbation et journalisation. Une facilité opérationnelle ne doit pas transformer toutes les connexions en compte maître.
Protéger créations et mutations
L’insertion doit dériver le tenant du contexte, jamais du payload. Une mise à jour ne peut modifier tenant_id comme un champ ordinaire, même avec un scope d’écriture large.
Forcer l’affectation serveur
Le DTO public ne contient pas tenant interne ou sa valeur est ignorée. La factory de domaine attache le contexte et les contraintes SQL vérifient la relation.
Les imports en masse partitionnent les lignes avant validation. Une seule ligne adressée à un autre tenant bloque le lot ou rejoint une quarantaine sans mutation partielle ambiguë.
Encadrer les transferts légitimes
Déplacer une ressource entre organisations est une opération métier exceptionnelle : copie, anonymisation, consentement ou transfert contractuel. Elle possède un workflow dédié, une double validation et une preuve durable.
Une simple mise à jour de clé casse historique, références et audit. Le modèle privilégie événements explicites et conserve la provenance avant comme après la transition.
Partitionner les caches
Le cache contourne facilement les filtres de repository. Chaque clé contenant une donnée locataire intègre tenant immuable, ressource, paramètres, version de politique et éventuellement principal lorsque la réponse varie par droit.
Définir un namespace obligatoire
Une bibliothèque construit les clés depuis le contexte ; le code métier ne concatène pas librement. Les caches HTTP utilisent private ou un Vary approprié selon le modèle.
Les clés génériques comme invoice:42 sont interdites par test ou lint interne. Le tenant apparaît avant l’identifiant afin de faciliter purge et inspection ciblées.
Invalider dans la même partition
L’événement d’invalidation porte le tenant et la version concernée. Un message incomplet échoue sans purger globalement ni laisser survivre une valeur mise en cache potentiellement incorrecte.
Un test chauffe une réponse bleue puis demande le même identifiant sous le tenant vert. Aucun hit ni timing distinctif ne doit révéler la valeur précédemment mémorisée.
Isoler files et jobs asynchrones
Un job quitte la requête HTTP ; il doit emporter tenant, principal technique, capacité, corrélation et version de politique nécessaires. Le worker ne déduit jamais le contexte depuis l’objet seul.
Signer l’enveloppe de message
L’enveloppe contient tenant interne et type de tâche, produits par un service autorisé. Un message externe traverse validation et mapping avant d’entrer dans la queue de domaine.
Le worker reconstruit un contexte borné puis appelle les mêmes services contextualisés que l’API. Il ne reçoit pas un rôle global simplement parce qu’il s’exécute en arrière-plan.
Partitionner concurrence et reprise
Les clés d’idempotence incluent tenant. Dead-letter queue, retry et outil de rejeu affichent le contexte et empêchent de relancer un message dans une autre organisation.
La méthode sur les événements webhook reçus dans le désordre complète cette défense pour ordonner, dédupliquer et réconcilier durablement les flux asynchrones dans chaque partition locataire.
Borner fichiers et URLs signées
Les objets de stockage appartiennent à un tenant même si leur bucket est partagé. Le chemin, les métadonnées et la base conservent cette propriété ; l’API vérifie avant toute signature.
Générer depuis une ressource autorisée
Le client demande un document métier, pas une clé arbitraire de bucket. Le serveur charge le document dans le tenant, puis produit une URL courte pour cette clé exacte.
Durée, méthode, content type et taille sont bornés. Une URL de téléchargement ne doit pas pouvoir devenir une autorisation d’upload ou de parcours de préfixe.
Isoler traitement et antivirus
Les pipelines de conversion, OCR ou scan conservent tenant dans leurs messages et sorties. Le fichier temporaire ne rejoint jamais un répertoire global adressable par nom fourni.
Les résultats dérivés héritent du tenant de la source. Une étape échouée nettoie uniquement les objets de sa partition et garde les preuves nécessaires à l’enquête.
Filtrer index et moteur de recherche
Un index partagé peut révéler documents, facettes ou suggestions d’autres organisations. Le tenant doit être un filtre obligatoire appliqué serveur, pas une clause facultative envoyée par l’interface.
Choisir index dédié ou partition logique
Un index dédié simplifie la preuve mais augmente coûts et opérations ; un filtre logique mutualise l’infrastructure. Le choix dépend du volume, des exigences et des capacités du moteur.
Dans les deux cas, la couche d’accès refuse une requête sans contexte. Les templates de query intègrent le filtre avant texte, facettes, agrégations et suggestions.
Sécuriser l’indexation elle-même
Chaque document reçoit tenant depuis la source autoritative. Un événement sans tenant reste en quarantaine au lieu d’être ajouté dans un index global par défaut.
La réconciliation compare périodiquement base et index par tenant. Les documents orphelins, erreurs de partition et différences de compte déclenchent suppression ou reconstruction contrôlée de la projection.
Tracer sans exposer les tenants
Les traces doivent prouver contexte et décision, tout en limitant la diffusion de données sensibles. Un identifiant tenant pseudonymisé ou interne suffit souvent pour segmenter les contrôles.
Journaliser la décision d’accès
Route, ressource, action, principal, tenant, politique, verdict et cause forment un événement structuré. Les identifiants d’objet sont masqués ou hachés selon les besoins d’enquête.
Un refus croisé reçoit une alerte de sécurité distincte d’un rôle insuffisant dans le bon tenant. Le seuil tient compte répétition, diversité d’objets et client appelant.
Détecter l’absence de contexte
Le monitoring compte requêtes, jobs, queries et cache keys sans tenant vérifié. Le seuil admissible reste strictement zéro sur tous les chemins locataires après migration complète.
Les dashboards globaux restent agrégés sans exposer noms ou volumes individuels à des opérateurs non autorisés. Toute descente au tenant exige une élévation auditée.
Encadrer le support inter-tenant
Le support peut devoir consulter une organisation différente. Cette capacité ne doit pas reposer sur un token maître permanent ni un paramètre caché capable de contourner les politiques ordinaires.
Utiliser une élévation just-in-time
L’opérateur choisit tenant, motif, ticket et durée ; une politique vérifie rôle et éventuelle double approbation. Le contexte élevé est visible dans l’interface et les traces.
Les opérations les plus sensibles restent interdites ou demandent une seconde étape indépendante. L’élévation expire automatiquement et ne peut pas être réutilisée par un job asynchrone ultérieur.
Réduire les données visibles
Le support reçoit champs et actions nécessaires au dossier, avec masquage par défaut. Export global, recherche multi-tenant et accès direct à la base restent séparés.
Le tenant peut recevoir une trace d’intervention selon la politique contractuelle. L’audit rapproche ticket, opérateur, ressources consultées, actions exécutées et fin effective de l’élévation temporaire.
Construire des tests négatifs
Un test heureux prouve qu’un tenant lit ses données ; il ne prouve pas qu’il ne peut pas lire celles des autres. Chaque endpoint reçoit une matrice sujet, tenant, objet et action avec attentes négatives.
Réutiliser les mêmes identifiants entre fixtures
Les tenants bleu et vert possèdent des objets aux external IDs identiques. Cette construction détecte un filtre manquant que des identifiants globalement uniques pourraient masquer.
Les tests couvrent GET, liste, compteur, mutation, bulk, export, cache chaud et job asynchrone. Ils vérifient aussi l’absence d’existence révélée par le statut ou le corps.
Muter les frontières
Un outil remplace le tenant de route, claim, message, curseur et fichier. Chaque mutation malveillante doit être refusée ou rester strictement enfermée dans le contexte déjà vérifié.
OWASP recommande de tester l’autorisation d’objet sur chaque fonction utilisant un identifiant fourni par le client. La CI bloque toute nouvelle route sans cas négatif explicitement enregistré.
Injecter des fautes de contexte
Les tests unitaires ne couvrent pas toujours pool de connexions, retry, cache distribué ou batch. Des expériences ciblées retirent ou corrompent le contexte dans un environnement isolé pour vérifier le fail closed.
Simuler les ruptures de propagation
Un message sans tenant, une session SQL réutilisée et une cache key incomplète sont injectés. Le système doit refuser, alerter et ne produire aucun effet secondaire.
Par exemple, si 1 job sur une cohorte de 10 000 perd son contexte, alors le seuil de données touchées reste zéro et la file entière est suspendue jusqu’au diagnostic.
Vérifier la reprise
Après correction, les messages quarantinés sont rejoués avec contexte restauré et preuve. Le rollback d’une politique ne réactive jamais une configuration autorisant l’accès global.
Les entrées sont scénarios et injecteurs ; les sorties sont refus, alertes et preuves. L’équipe sécurité possède cadence, monitoring, arrêt et compte rendu de chaque expérience.
Migrer une API existante
Ajouter un tenant_id à toutes les méthodes en une release est risqué. La migration inventorie accès, introduit contexte et observabilité, puis ferme progressivement les chemins non conformes.
Cartographier avant de bloquer
Repositories, SQL bruts, caches, index, jobs, exports et outils admin sont recensés. Un mode shadow calcule le tenant attendu et signale les divergences sans modifier la réponse.
Les données existantes sont backfillées avec leur provenance vérifiable. Toute ligne ambiguë rejoint une quarantaine ; attribuer un tenant par défaut créerait immédiatement une fuite structurelle durable.
Fermer par cohorte de ressources
Une ressource passe successivement en observation, contexte obligatoire, filtre applicatif, contraintes SQL et tests négatifs complets. Les caches concernés sont intégralement purgés au changement de format de clé.
Le déploiement conserve métriques de refus et erreurs fonctionnelles par cohorte. Une hausse de réponses 403 attendue est distinguée d’un défaut d’appartenance dans les données effectivement migrées.
Éviter les erreurs fréquentes
Les fuites multi-tenant naissent souvent de raccourcis cohérents localement mais incomplets dans la chaîne. Ces erreurs doivent être interdites par API interne, contraintes et tests plutôt que par convention orale.
- Faire confiance au header : le client choisit librement son organisation et le serveur transforme cette sélection non vérifiée en filtre de données.
- Utiliser seulement un UUID : l’identifiant imprévisible ralentit l’énumération, mais toute valeur divulguée donne accès faute d’autorisation d’objet.
- Filtrer uniquement le repository principal : cache, compteur, export ou recherche révèlent encore les ressources d’autres tenants par un chemin secondaire.
- Oublier les écritures : les lectures sont filtrées, tandis qu’un payload peut créer ou rattacher un enfant sous une organisation étrangère.
- Donner un rôle global aux workers : le job perd son contexte et traite la première ressource correspondant à un identifiant non partitionné.
- Activer RLS avec un propriétaire : la connexion applicative contourne la politique et donne une fausse impression de défense en profondeur.
- Tester seulement le succès : chaque fixture possède des clés différentes et ne révèle jamais l’absence du prédicat tenant.
Le signal d’arrêt est tout accès locataire sans contexte non nullable ou toute divergence entre tenant du contexte et de la ressource. Aucun contournement temporaire n’est autorisé sur le trafic normal.
Matrice de décision d’isolation
La matrice qualifie chaque chemin avant production. Elle force l’équipe à nommer identité, partition, enforcement, test et preuve plutôt que de déclarer génériquement une route « authentifiée ».
Attribuer un verdict actionnable
- À valider : tenant vient d’une relation autorisée, le contexte est obligatoire et chaque ressource, collection ou effet vérifie sa partition.
- À renforcer : le filtre applicatif existe, mais contrainte SQL, RLS, clé composite ou partition de cache peut réduire l’impact d’un oubli.
- À tester : le chemin heureux est couvert, tandis que substitution d’objet, cache chaud, job, export et mutation croisée manquent encore.
- À isoler : une opération support ou plateforme nécessite plusieurs tenants et doit quitter les credentials, routes et interfaces du trafic ordinaire.
- À bloquer : tenant vient du payload, contexte reste optionnel, rôle contourne les politiques ou une ressource étrangère produit une réponse exploitable.
Chaque verdict conserve route, données, owner, preuve, date et prochaine action. Les exceptions expirent et ne deviennent jamais une seconde architecture d’administration non auditée.
Cas concret sur un export de factures
Une route crée un export CSV de factures puis renvoie une URL signée. Le filtre HTTP est correct, mais le job asynchrone reçoit seulement un user ID et requête toutes les factures accessibles à ce compte multi-organisation.
Propager une capacité bornée
La commande d’export porte tenant, principal, scope, filtres et corrélation. Le worker reconstruit le contexte, interroge un repository partitionné et écrit dans un préfixe appartenant au même tenant.
La base applique aussi RLS avec le tenant de transaction. Le manifest enregistre nombre de lignes et hash ; une réconciliation compare l’export à la requête autorisée.
Signer après autorisation
L’API charge le manifest sous le contexte courant avant de générer l’URL de téléchargement. La clé de stockage n’est jamais acceptée directement depuis le client.
Un test demande l’export vert avec le token bleu, chauffe le cache puis réessaie. Les deux réponses restent indistinguables d’une ressource inexistante et aucune URL n’est créée.
Plan d’action en dix semaines
Le chantier commence par une ressource sensible et traverse toute sa chaîne. Chaque semaine ajoute une barrière et une preuve avant de généraliser le patron aux autres domaines.
Le manifeste du pilote nomme tenants témoins, ressources, consommateurs synchrones et asynchrones, caches, index et fichiers concernés. Il conserve aussi les chemins administratifs légitimes afin de tester leur élévation sans créer une autorisation globale permanente.
La décision de passage compare les mêmes identifiants dans le token, la politique, la requête, le stockage et la trace. Une incohérence, un contexte nullable ou un refus non attribuable bloque l’extension, même si les scénarios fonctionnels nominaux restent verts.
- Semaine 1 : inventorier tenants, principaux, ressources, routes, bases, caches, index, files, stockages, exports et opérations administratives globales.
- Semaine 2 : écrire menaces, impacts, frontière, identifiant interne et relation d’appartenance qui autorise la sélection d’un contexte actif.
- Semaine 3 : créer contexte immuable, validation de token, audience, scopes et résolution de route avec refus constant de toute divergence.
- Semaine 4 : contextualiser repositories, listes, agrégats et mutations, puis ajouter clés composites et contraintes de filiation tenant en base.
- Semaine 5 : déployer RLS sur une cohorte, configurer rôles sans bypass, variables de transaction et nettoyage fiable des connexions en pool.
- Semaine 6 : partitionner cache, index, stockage, URLs signées, queues et clés d’idempotence sans contexte déduit depuis les payloads externes.
- Semaine 7 : encadrer jobs, support, élévation just-in-time, traces et logs avec droits, masquage, expiration puis audit des interventions.
- Semaine 8 : construire matrice négative par endpoint, fixtures aux identifiants communs, tests de mutation, cache chaud, export et ordre asynchrone.
- Semaine 9 : injecter contexte manquant, session SQL contaminée et message corrompu dans un environnement isolé, puis vérifier refus, alertes et reprise.
- Semaine 10 : fermer la cohorte, analyser métriques, corriger les accès shadow divergents et étendre seulement après zéro fuite et rollback testé.
Portes de recette avant extension
La ressource suivante reste fermée tant que les quatre garanties ci-dessous ne disposent pas chacune d’une preuve automatique, d’une trace exploitable et d’un propriétaire opérationnel.
- Contexte vérifié : tenant vient d’une relation autorisée, reste immuable, non nullable et ne peut jamais être remplacé par un paramètre client tardif.
- Enforcement complet : objets, collections, agrégats, écritures, caches, index, messages, fichiers et exports appliquent la même frontière locataire.
- Refus prouvé : substitutions de tenant, objet, curseur, cache key et message échouent dans les tests avec une réponse qui ne révèle aucune existence.
- Run maîtrisé : journalisation, monitoring, seuil zéro, dépendances, élévation, réconciliation et rollback des politiques sont testés avant montée en charge.
Contenus complémentaires et sources officielles
Ces références décrivent autorisation d’objet, zero trust, audience OAuth et politiques de ligne. Elles fournissent des principes et mécanismes ; l’organisation reste responsable de sa frontière, de ses données et de ses preuves.
- OWASP API Security — Broken Object Level Authorization exige un contrôle d’autorisation pour chaque endpoint utilisant un identifiant afin d’accéder à un objet.
- NIST SP 800-207 — Zero Trust Architecture recentre les décisions sur sujets, actifs et ressources plutôt que sur une confiance implicite liée au réseau.
- RFC 8707 — Resource Indicators for OAuth 2.0 encadre audiences spécifiques et cite explicitement la restriction par tenant pour les ressources multi-tenant.
- PostgreSQL — Row Security Policies documente politiques par ligne, refus par défaut, expressions de lecture et modification ainsi que rôles capables de les contourner.
- PostgreSQL — CREATE POLICY précise les clauses
USING,WITH CHECKet la combinaison de politiques permissives ou restrictives.
Aucune défense unique ne suffit. L’autorisation métier, les repositories contextualisés, les contraintes de données et les tests négatifs doivent converger vers le même refus pour rendre la frontière crédible.
Relier permissions et scénarios d’abus
Les scopes OAuth au moindre privilège bornent les opérations possibles après sélection d’un tenant autorisé.
Le threat model d’une API partenaire transforme les substitutions, exports et contournements administratifs en scénarios de refus reproductibles.
Conclusion : prouver l’impossibilité de franchir la frontière
L’isolation tenant ne se résume ni à un claim ni à une colonne. Elle commence par une identité autorisée et se propage dans chaque objet, requête, cache, message, fichier et trace.
Les défenses applicatives et de données réduisent l’impact d’un oubli ; les tests négatifs démontrent que le mauvais tenant reste inaccessible, y compris sur les chemins asynchrones et administratifs.
Pour construire cette preuve de bout en bout, notre expertise en intégration API relie OAuth, application des politiques, architecture multi-tenant, données, observabilité et migration progressive sans ouvrir de fenêtre d’accès croisé.