Les plateformes SaaS modernes doivent souvent héberger des centaines, voire des milliers de clients sur une infrastructure commune. Cette approche permet de mutualiser les ressources et de réduire les coûts d'exploitation, mais elle introduit également un problème majeur : comment garantir l'isolation entre les différents clients ?

Kubernetes est devenu l'une des plateformes privilégiées pour construire ce type d'infrastructure. Grâce à ses mécanismes de namespaces, RBAC, NetworkPolicies, quotas de ressources et gestion déclarative des déploiements, Kubernetes fournit les primitives nécessaires pour construire une architecture Multi-Tenant moderne.

Cependant, utiliser plusieurs namespaces ne suffit pas à garantir une isolation complète. Une véritable architecture Multi-Tenant doit prendre en compte plusieurs couches : calcul, réseau, identité, stockage, données, secrets, observabilité et sécurité.

1. Qu'est-ce que le Multi-Tenancy ?

Le terme Multi-Tenant désigne une architecture dans laquelle plusieurs clients utilisent une même plateforme ou infrastructure tout en conservant une séparation logique entre leurs environnements.

Prenons l'exemple d'une plateforme SaaS proposant une application de monitoring.

Trois entreprises utilisent la même plateforme :

  • Tenant A : entreprise Alpha
  • Tenant B : entreprise Beta
  • Tenant C : entreprise Gamma

Les trois entreprises peuvent utiliser la même infrastructure Kubernetes, mais elles ne doivent pas pouvoir accéder aux ressources ou aux données appartenant aux autres clients.


                         Kubernetes Cluster
                                |
             +------------------+------------------+
             |                  |                  |
        Tenant A            Tenant B            Tenant C
             |                  |                  |
        Namespace A        Namespace B        Namespace C
             |                  |                  |
        +----+----+        +----+----+        +----+----+
        |         |        |         |        |         |
      App       DB       App       DB       App       DB
  

Le cluster est partagé, mais chaque tenant possède un environnement logique distinct.

2. Pourquoi utiliser Kubernetes pour le Multi-Tenant ?

Kubernetes fournit plusieurs fonctionnalités particulièrement adaptées à ce modèle.

  • Namespaces
  • RBAC
  • NetworkPolicies
  • ResourceQuotas
  • LimitRanges
  • Secrets
  • ServiceAccounts
  • Pod Security
  • PersistentVolumes

Ces mécanismes peuvent être combinés afin de créer plusieurs niveaux d'isolation.

L'objectif est de construire une architecture basée sur le principe de Defense in Depth : si une couche est mal configurée, d'autres couches doivent continuer à limiter l'impact.

3. Les différents niveaux d'isolation

Il existe plusieurs stratégies permettant d'isoler les tenants dans Kubernetes.

Isolation au niveau du Namespace

Chaque tenant possède son propre namespace.


cluster
 |
 +-- tenant-a
 |
 +-- tenant-b
 |
 +-- tenant-c
  

Isolation au niveau des Pods

Chaque tenant peut disposer de ses propres pods applicatifs.

Isolation au niveau des Nodes

Pour des environnements nécessitant une isolation plus forte, les workloads de certains tenants peuvent être placés sur des nodes dédiés.


Node Pool A
  |
  +-- Tenant A

Node Pool B
  |
  +-- Tenant B

Node Pool C
  |
  +-- Tenant C
  

Cette stratégie augmente cependant les coûts et la complexité opérationnelle.

4. Namespaces : première couche d'isolation

Le Namespace est généralement le premier mécanisme utilisé pour organiser un environnement Multi-Tenant.


kubectl create namespace tenant-a
kubectl create namespace tenant-b
kubectl create namespace tenant-c
  

On peut ensuite ajouter des labels permettant d'identifier les tenants.


kubectl label namespace tenant-a tenant=tenant-a
kubectl label namespace tenant-b tenant=tenant-b
kubectl label namespace tenant-c tenant=tenant-c
  

Ces labels peuvent ensuite être utilisés par les NetworkPolicies et différents contrôleurs Kubernetes.

5. Pourquoi un Namespace ne suffit pas ?

Une erreur fréquente consiste à considérer qu'un namespace constitue une frontière de sécurité absolue.

Ce n'est pas le cas.

Un namespace fournit principalement une séparation logique des ressources. Il faut ajouter d'autres mécanismes pour contrôler les accès et les communications.

Une architecture réellement sécurisée doit donc combiner :


Namespace
    |
    +-- RBAC
    |
    +-- NetworkPolicy
    |
    +-- ResourceQuota
    |
    +-- Pod Security
    |
    +-- Secrets
    |
    +-- Database Isolation
  

6. RBAC : contrôler les accès

RBAC, ou Role-Based Access Control, permet de définir précisément quelles actions un utilisateur ou un service peut effectuer dans Kubernetes.

Imaginons que le tenant A possède un utilisateur chargé de superviser son application.

Cet utilisateur doit pouvoir consulter les pods de son environnement mais ne doit pas pouvoir accéder aux ressources du tenant B.


apiVersion: rbac.authorization.k8s.io/v1
kind: Role

metadata:
  name: tenant-reader
  namespace: tenant-a

rules:
  - apiGroups: [""]
    resources:
      - pods
      - services
    verbs:
      - get
      - list
      - watch
  

On peut ensuite associer ce rôle à un utilisateur ou à un ServiceAccount avec un RoleBinding.


apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding

metadata:
  name: tenant-reader-binding
  namespace: tenant-a

subjects:
  - kind: User
    name: tenant-a-user

roleRef:
  kind: Role
  name: tenant-reader
  apiGroup: rbac.authorization.k8s.io
  

L'utilisation du principe de Least Privilege est essentielle : un utilisateur ne doit recevoir que les permissions dont il a réellement besoin.

7. NetworkPolicies : isoler les communications

L'isolation des accès Kubernetes ne suffit pas. Il faut également contrôler le trafic réseau.

Sans politique réseau adaptée, un pod appartenant au tenant A pourrait potentiellement communiquer avec des services appartenant à un autre environnement.

Les NetworkPolicies permettent de réduire ce risque.


apiVersion: networking.k8s.io/v1
kind: NetworkPolicy

metadata:
  name: tenant-a-isolation
  namespace: tenant-a

spec:
  podSelector: {}

  policyTypes:
    - Ingress
    - Egress

  ingress:
    - from:
        - namespaceSelector:
            matchLabels:
              tenant: tenant-a
  

Cette politique limite les communications entrantes aux ressources provenant d'un namespace identifié comme appartenant au tenant A.

Une architecture plus avancée peut également définir précisément les communications nécessaires entre frontend, backend et base de données.


Internet
   |
   v
Ingress
   |
   v
Frontend
   |
   v
Backend
   |
   v
Database
  

Au lieu d'autoriser tous les flux réseau, on applique le principe : deny by default, allow explicitly.

8. ResourceQuota : contrôler la consommation

Dans un environnement partagé, un tenant ne doit pas pouvoir consommer toutes les ressources disponibles.

Kubernetes permet d'utiliser les ResourceQuotas.


apiVersion: v1
kind: ResourceQuota

metadata:
  name: tenant-a-quota
  namespace: tenant-a

spec:
  hard:
    requests.cpu: "4"
    requests.memory: 8Gi
    limits.cpu: "8"
    limits.memory: 16Gi
    pods: "20"
  

Cette configuration limite notamment le nombre de pods et la quantité de CPU et de mémoire pouvant être demandée par le tenant.

Cela protège la stabilité globale du cluster.

9. LimitRange : contrôler les ressources des conteneurs

Les ResourceQuotas peuvent être complétés par des LimitRanges.

Ils permettent de définir des valeurs par défaut ou des limites pour les conteneurs d'un namespace.


apiVersion: v1
kind: LimitRange

metadata:
  name: tenant-limits
  namespace: tenant-a

spec:
  limits:
    - type: Container

      default:
        cpu: "500m"
        memory: "512Mi"

      defaultRequest:
        cpu: "100m"
        memory: "128Mi"
  

Cela permet d'éviter qu'un workload soit déployé sans aucune définition raisonnable de ses ressources.

10. Sécurité des Pods

Une autre couche importante concerne la sécurité des workloads eux-mêmes.

Les applications doivent être exécutées avec le minimum de privilèges nécessaire.

Parmi les bonnes pratiques :

  • Éviter les conteneurs privilégiés.
  • Éviter l'utilisation inutile de root.
  • Limiter les capabilities Linux.
  • Utiliser des images minimales et vérifiées.
  • Scanner les images avant leur déploiement.

L'objectif est de réduire le risque qu'une compromission d'un workload permette ensuite d'atteindre d'autres composants de l'infrastructure.

11. Isolation des Secrets

Chaque tenant peut posséder des informations sensibles :

  • Credentials de base de données
  • API keys
  • Tokens
  • Certificats
  • Secrets applicatifs

Ces informations doivent être isolées autant que possible.


tenant-a
 |
 +-- secret: database-credentials

tenant-b
 |
 +-- secret: database-credentials
  

Il faut également contrôler précisément les ServiceAccounts capables de lire ces secrets.

12. Le problème de la base de données

La base de données représente souvent la partie la plus sensible d'une plateforme Multi-Tenant.

Trois architectures principales sont possibles.

Modèle 1 : base partagée


Tenant A ─┐
Tenant B ─┼──> PostgreSQL
Tenant C ─┘
  

Tous les tenants utilisent la même base.

Cette architecture est économique mais demande une excellente isolation logique des données.

Modèle 2 : une base par tenant


Tenant A ──> PostgreSQL A
Tenant B ──> PostgreSQL B
Tenant C ──> PostgreSQL C
  

Cette approche offre une isolation plus forte, notamment pour les données, mais augmente les coûts et le nombre de composants à administrer.

Modèle 3 : PostgreSQL partagé avec plusieurs bases


                PostgreSQL
                    |
        +-----------+-----------+
        |           |           |
      DB-A        DB-B        DB-C
        |           |           |
    Tenant A    Tenant B    Tenant C
  

Cette solution peut constituer un compromis intéressant entre isolation et mutualisation.

13. Isolation des Persistent Volumes

Lorsque les applications utilisent du stockage persistant, il faut également réfléchir à l'isolation des volumes.

Un tenant ne doit jamais pouvoir monter ou accéder au stockage appartenant à un autre tenant.

Une architecture peut par exemple associer un PersistentVolumeClaim à chaque environnement.


tenant-a
 |
 +-- PVC
      |
      +-- PersistentVolume

tenant-b
 |
 +-- PVC
      |
      +-- PersistentVolume
  

Les politiques de stockage et les permissions doivent être conçues avec le même principe d'isolation que les workloads.

14. Architecture complète

Une architecture Multi-Tenant Kubernetes peut finalement être représentée comme une succession de couches de sécurité.


                         Internet
                            |
                            v
                         Ingress
                            |
                +-----------+-----------+
                |                       |
            Tenant A                Tenant B
                |                       |
           Namespace A             Namespace B
                |                       |
        +-------+-------+       +-------+-------+
        |               |       |               |
      Frontend        Backend Frontend        Backend
        |               |       |               |
        +-------+-------+       +-------+-------+
                |                       |
           NetworkPolicy           NetworkPolicy
                |                       |
              RBAC                    RBAC
                |                       |
           ResourceQuota          ResourceQuota
                |                       |
            Database                Database
  

15. Automatiser la création d'un tenant

Dans une véritable plateforme SaaS, créer manuellement un namespace, un Role, une NetworkPolicy et une base de données pour chaque nouveau client n'est pas scalable.

Il devient donc nécessaire d'automatiser le provisioning.

Un workflow peut ressembler à ceci :


                New Customer
                     |
                     v
                 SaaS API
                     |
                     v
              Create Tenant
                     |
          +----------+----------+
          |          |          |
          v          v          v
      Namespace    RBAC    NetworkPolicy
          |          |          |
          +----------+----------+
                     |
                     v
               Deploy App
                     |
                     v
               Configure DB
                     |
                     v
               Tenant Ready
  

Cette automatisation peut être réalisée avec des controllers Kubernetes, Helm, Terraform, une API backend ou une combinaison de ces outils.

16. GitOps pour le Multi-Tenant

GitOps peut également être utilisé pour gérer les environnements des différents tenants.


Git Repository
      |
      +-- tenants/
      |     |
      |     +-- tenant-a/
      |     +-- tenant-b/
      |     +-- tenant-c/
      |
      v
    ArgoCD
      |
      v
 Kubernetes Cluster
  

Chaque changement d'infrastructure peut ainsi être versionné et audité.

Cette approche est particulièrement intéressante dans un contexte DevSecOps, car elle permet d'intégrer des contrôles de sécurité avant qu'une modification ne soit déployée.

17. Monitoring et observabilité

L'isolation ne concerne pas uniquement la sécurité.

Il faut également être capable de mesurer la consommation de chaque tenant.

On peut suivre :

  • CPU consommé
  • Mémoire utilisée
  • Nombre de pods
  • Trafic réseau
  • Erreurs applicatives
  • Latence
  • Disponibilité

Ces informations permettent de détecter rapidement les comportements anormaux et de mieux répartir les ressources.

18. Les principaux risques d'une architecture Multi-Tenant

Une mauvaise configuration peut provoquer plusieurs types de problèmes.

Accès inter-tenant

Une mauvaise configuration RBAC ou réseau peut permettre à un tenant d'accéder à des ressources appartenant à un autre tenant.

Data leakage

Une erreur dans l'application ou la base de données peut exposer les informations d'un client à un autre.

Resource exhaustion

Un tenant peut consommer trop de CPU, de mémoire ou de stockage et dégrader les performances des autres clients.

Privilege escalation

Des permissions excessives peuvent permettre à un utilisateur ou à une application d'obtenir des privilèges supplémentaires dans le cluster.

19. Defense in Depth

La meilleure stratégie consiste à ne jamais dépendre d'un seul mécanisme.


                 Multi-Tenant Security
                         |
        +----------------+----------------+
        |                |                |
      Identity         Network          Data
        |                |                |
       RBAC       NetworkPolicies    DB Isolation
        |                |                |
        +----------------+----------------+
                         |
                      Workload
                         |
                  Pod Security
                         |
                    Resources
                         |
                ResourceQuota
  

Chaque couche réduit la surface d'attaque et limite l'impact potentiel d'une compromission.

20. Conclusion

Construire une architecture Multi-Tenant avec Kubernetes ne consiste pas simplement à créer plusieurs namespaces.

Une architecture robuste doit considérer simultanément l'identité, le réseau, les workloads, les ressources, les secrets, le stockage et les données.

Les namespaces fournissent une première séparation logique. RBAC contrôle les permissions, les NetworkPolicies contrôlent les communications, ResourceQuota protège les ressources et l'isolation des bases de données protège les informations critiques.

En combinant ces mécanismes avec l'automatisation, GitOps et une observabilité adaptée, Kubernetes peut devenir une excellente base pour construire une plateforme SaaS Multi-Tenant moderne.

Le principe essentiel à retenir : dans une architecture Multi-Tenant, l'isolation doit être pensée comme une propriété globale du système, et non comme une simple fonctionnalité Kubernetes.