virli/tutorial/4/namespaces-recap.md

16 KiB

\newpage

Récapitulatif des namespaces

Nous venons d'explorer en détail les huit types d'espaces de noms disponibles dans le noyau Linux. Avant de conclure cette partie, récapitulons les concepts clés et les meilleures pratiques pour utiliser efficacement ces mécanismes d'isolation.

Tableau comparatif des namespaces

Le tableau suivant résume les caractéristiques principales de chaque type d'espace de noms :

Namespace Flag clone() Depuis Isole Privilèges requis*
mount CLONE_NEWNS 2.4.19 Points de montage Oui
UTS CLONE_NEWUTS 2.6.19 Hostname, domaine NIS Oui
IPC CLONE_NEWIPC 2.6.19 Objets IPC System V et POSIX Oui
PID CLONE_NEWPID 2.6.24 Arbre de processus Oui
network CLONE_NEWNET 2.6.29 Interfaces, routes, ports Oui
user CLONE_NEWUSER 3.8 UIDs, GIDs, capabilities Non
cgroup CLONE_NEWCGROUP 4.6 Vue arborescence cgroup Oui
time CLONE_NEWTIME 5.6 Horloges monotones Oui

* Sauf si combiné avec un namespace user

Ce que chaque namespace vous permet de faire

mount -- Systèmes de fichiers isolés

Fonctionnalité : Isole l'arborescence des points de montage.

Permet de :

  • Créer un système de fichiers racine différent (pivot_root, switch_root)
  • Monter/démonter des partitions sans affecter l'hôte
  • Implémenter un chroot sécurisé (impossible de s'échapper)
  • Utiliser des systèmes de fichiers en couches (OverlayFS)

Cas d'usage typiques :

  • Conteneurs avec leur propre filesystem
  • Environnements de build isolés
  • Systèmes d'installation et de récupération

UTS -- Identité système

Fonctionnalité : Isole le nom d'hôte et le domaine NIS.

Permet de :

  • Donner un nom unique à chaque conteneur
  • Éviter les conflits de nommage
  • Faciliter l'identification des conteneurs

Cas d'usage typiques :

  • Conteneurs avec des noms de machine distincts
  • Environnements multi-tenants
  • Tests de configurations réseau

IPC -- Communication inter-processus

Fonctionnalité : Isole les objets IPC (files de messages, sémaphores, mémoire partagée).

Permet de :

  • Empêcher la communication IPC entre conteneurs
  • Isoler les applications utilisant IPC System V ou POSIX
  • Protéger contre les fuites d'informations via IPC

Cas d'usage typiques :

  • Isolation de sécurité entre conteneurs
  • Applications legacy utilisant IPC System V
  • Environnements de test pour applications IPC

PID -- Arbre de processus virtualisé

Fonctionnalité : Isole l'arbre des processus avec renumérotation.

Permet de :

  • Avoir un processus init (PID 1) par conteneur
  • Masquer les processus de l'hôte et des autres conteneurs
  • Gérer le cycle de vie des processus indépendamment
  • Récolter les processus orphelins proprement

Cas d'usage typiques :

  • Conteneurs avec gestion complète du cycle de vie
  • Isolation de sécurité (masquage des processus)
  • Environnements avec plusieurs niveaux d'init

Particularité : Le processus doit forker après unshare(CLONE_NEWPID) pour que l'isolation soit effective.

network -- Pile réseau dédiée

Fonctionnalité : Isole les interfaces réseau, routes, règles de pare-feu et ports.

Permet de :

  • Donner une pile réseau complète à chaque conteneur
  • Réutiliser les mêmes ports dans différents conteneurs
  • Configurer des routes et pare-feu indépendants
  • Créer des topologies réseau complexes (bridges, VLAN, MACVLAN)

Cas d'usage typiques :

  • Conteneurs avec leur propre IP
  • Tests réseau isolés
  • Micro-services avec ports identiques
  • Simulations de topologies réseau

Note : Nécessite généralement des interfaces virtuelles (veth, macvlan, etc.) pour connecter les conteneurs.

user -- Privilèges virtualisés

Fonctionnalité : Isole les UIDs, GIDs et les capabilities.

Permet de :

  • Être root dans le conteneur sans être root sur l'hôte
  • Lancer des conteneurs sans privilèges (rootless containers)
  • Mapper des plages d'UIDs entre conteneur et hôte
  • Déléguer des capacités limitées

Cas d'usage typiques :

  • Conteneurs rootless (podman, systemd-nspawn)
  • Environnements multi-utilisateurs sécurisés
  • Délégation contrôlée de privilèges

Particularité : Seul namespace créable sans privilèges. Permet ensuite de créer tous les autres types de namespaces.

Attention : Historiquement source de vulnérabilités ; à utiliser avec précaution.

cgroup -- Vue filtrée des control groups

Fonctionnalité : Virtualise la vue de l'arborescence des cgroups.

Permet de :

  • Masquer l'organisation des cgroups de l'hôte
  • Faciliter la migration de conteneurs
  • Empêcher la fuite d'informations système via /sys/fs/cgroup
  • Déléguer la gestion de sous-arbres de cgroups

Cas d'usage typiques :

  • Renforcement de l'isolation de sécurité
  • Migration de conteneurs (CRIU)
  • Systèmes multi-tenants

Note : Souvent combiné avec un namespace mount pour remonter /sys/fs/cgroup.

time -- Horloges virtualisées

Fonctionnalité : Virtualise CLOCK_MONOTONIC et CLOCK_BOOTTIME.

Permet de :

  • Décaler les horloges monotones pour un conteneur
  • Préserver l'état temporel lors de migrations
  • Accélérer le temps pour les tests

Cas d'usage typiques :

  • Migration de conteneurs avec CRIU
  • Tests d'applications sensibles au temps
  • Simulations temporelles

Limitation : Ne virtualise pas l'heure système (CLOCK_REALTIME).

Particularité : Les offsets doivent être configurés avant de créer le premier processus enfant.

Combinaisons recommandées

Les namespaces sont rarement utilisés seuls. Voici les combinaisons courantes selon les besoins d'isolation :

Isolation minimale (développement)

Pour un environnement de développement simple avec un filesystem isolé :

```bash unshare --mount --pid --fork --mount-proc /bin/bash ```

Isolation : Filesystem et processus Avantages : Rapide, simple, suffisant pour tester des installations Limitations : Partage le réseau, les utilisateurs, IPC avec l'hôte

Conteneur standard (production light)

Pour une isolation raisonnable sans réseau séparé :

```bash unshare --mount --uts --ipc --pid --fork --mount-proc /bin/bash ```

Isolation : Filesystem, processus, IPC, hostname Avantages : Bonne isolation, partage le réseau de l'hôte Cas d'usage : Services système, environnements de build

Conteneur avec réseau isolé

Pour une isolation complète incluant le réseau :

```bash unshare --mount --uts --ipc --net --pid --fork --mount-proc /bin/bash ```

Isolation : Filesystem, processus, IPC, hostname, réseau Avantages : Isolation réseau complète Note : Nécessite configuration réseau supplémentaire (veth, bridge, etc.)

Conteneur rootless (sans privilèges)

Pour lancer un conteneur en tant qu'utilisateur normal :

```bash unshare --user --map-root-user \ --mount --uts --ipc --net --pid \ --fork --mount-proc /bin/bash ```

Isolation : Complète + virtualisation des privilèges Avantages : Aucun privilège requis, sécurité renforcée Cas d'usage : Environnements multi-utilisateurs, CI/CD non-privilégiée

Conteneur type Docker (isolation maximale)

Pour une isolation complète similaire à Docker :

```bash unshare --user --map-root-user \ --mount --uts --ipc --net --pid --cgroup \ --fork --mount-proc /bin/bash ```

Isolation : Tous les namespaces (sauf time) Avantages : Isolation maximale Note : Équivalent approximatif de docker run --rm -it

Ordre de création des namespaces

L'ordre dans lequel les namespaces sont créés peut être important :

  1. user en premier : Si vous voulez créer des namespaces sans privilèges, commencez toujours par le namespace user.

  2. mount avant pid : Pour pouvoir remonter /proc correctement avec l'option --mount-proc.

  3. pid avec --fork : N'oubliez jamais l'option --fork avec le namespace pid, sinon le processus actuel ne sera pas réellement isolé.

  4. time et cgroup avant le fork : Ces deux namespaces nécessitent des configurations avant la création du premier processus enfant.

Commandes essentielles

Voici un récapitulatif des commandes les plus utiles pour travailler avec les namespaces :

Création et entrée dans des namespaces

```bash # Créer de nouveaux namespaces et exécuter une commande unshare [options] [commande]

Principales options :

-m, --mount Namespace mount

-u, --uts Namespace UTS

-i, --ipc Namespace IPC

-n, --net Namespace network

-p, --pid Namespace PID

-U, --user Namespace user

-C, --cgroup Namespace cgroup

-T, --time Namespace time

-f, --fork Fork avant d'exécuter la commande (requis avec --pid)

--mount-proc Monter /proc après création du namespace

Entrer dans les namespaces d'un processus existant

nsenter [options] [commande] nsenter --target --all [commande]

</div>

### Inspection des *namespaces*

<div lang="en-US">
```bash
# Lister tous les namespaces du système
lsns

# Lister les namespaces d'un processus spécifique
lsns -p <PID>

# Voir les namespaces d'un processus
ls -l /proc/<PID>/ns/

# Comparer les namespaces de deux processus
readlink /proc/<PID1>/ns/net
readlink /proc/<PID2>/ns/net

Gestion réseau (namespace network)

```bash # Créer un namespace network nommé ip netns add

Lister les namespaces network

ip netns list

Exécuter une commande dans un namespace network

ip netns exec

Créer une paire veth

ip link add veth0 type veth peer name veth1

Déplacer une interface dans un namespace

ip link set veth1 netns

</div>


## Appels système

Pour les développeurs, voici les appels système principaux :

<div lang="en-US">
```c
// Créer un nouveau processus dans de nouveaux namespaces
pid_t clone(int (*fn)(void *), void *stack, int flags, void *arg);
// flags: CLONE_NEWNS, CLONE_NEWUTS, CLONE_NEWIPC, CLONE_NEWPID,
//        CLONE_NEWNET, CLONE_NEWUSER, CLONE_NEWCGROUP, CLONE_NEWTIME

// Se dissocier de namespaces actuels
int unshare(int flags);

// Rejoindre les namespaces d'un autre processus
int setns(int fd, int nstype);
// fd: file descriptor de /proc/<PID>/ns/<type>
// nstype: 0 ou CLONE_NEW* pour vérification de type

// Obtenir un file descriptor vers un processus (pour setns)
int pidfd_open(pid_t pid, unsigned int flags);

Bonnes pratiques

Sécurité

  1. Privilèges minimaux : Utilisez le namespace user quand possible pour éviter d'exécuter des conteneurs en tant que root.

  2. Combinaison d'isolations : Un seul namespace ne suffit généralement pas pour une isolation sécurisée. Combinez plusieurs namespaces.

  3. User namespace avec précaution : Bien que pratique, le namespace user a été source de nombreuses vulnérabilités. Assurez-vous d'utiliser un noyau récent et correctement patché.

  4. Nettoyage des ressources : Les namespaces persistent tant qu'ils sont référencés. Utilisez umount pour les bind mounts qui maintiennent des namespaces actifs.

  5. Capabilities : Même dans un namespace user, les capabilities sont limitées à l'intérieur du namespace. Ne comptez pas sur elles pour des actions hors namespace.

Performance

  1. Coût minimal : La création de namespaces a un coût négligeable en termes de performance. N'hésitez pas à les utiliser.

  2. Réseau : Le type d'interface virtuelle utilisé (veth, macvlan, ipvlan) peut avoir un impact significatif sur les performances réseau.

  3. OverlayFS vs device-mapper : Pour le stockage, OverlayFS est généralement plus performant que les snapshots LVM (device-mapper).

Débogage

  1. lsns est votre ami : Utilisez lsns pour comprendre rapidement l'organisation des namespaces sur votre système.

  2. Inspecter /proc : Les fichiers dans /proc/<PID>/ns/ sont essentiels pour comprendre dans quels namespaces se trouve un processus.

  3. Bind mounts pour persistence : Utilisez mount --bind sur les fichiers de /proc/<PID>/ns/ pour maintenir un namespace actif même après la terminaison du processus.

  4. Logs et strace : En cas de problème, strace peut vous montrer exactement quels appels système échouent et pourquoi.

Limitations et pièges courants

Namespace PID

  • Oubli du --fork : Sans fork, le processus actuel reste dans l'ancien namespace PID.
  • Bash et PID 1 : Bash peut avoir des comportements inattendus en tant que PID 1 (voir pidns.md pour les détails).
  • /proc doit être remonté : Sinon ps, top montrent tous les processus du système.

Namespace mount

  • Propagation des montages : Attention aux politiques shared, slave, private. Par défaut, utilisez mount --make-rslave / pour éviter les fuites.
  • pivot_root vs chroot : pivot_root est plus sûr mais plus complexe à mettre en œuvre.

Namespace network

  • Pas d'interface par défaut : Un nouveau namespace network ne contient qu'une interface loopback désactivée. Il faut configurer le réseau manuellement.
  • Complexité de la configuration : Bridges, veth, routes, NAT... la configuration réseau peut devenir complexe rapidement.

Namespace user

  • MappingUID/GID limité : Sans privilèges, vous ne pouvez mapper qu'un seul UID (le vôtre vers root).
  • Fichiers setuid : Ne fonctionnent pas correctement dans un namespace user.
  • Restrictions par distribution : Certaines distributions désactivent le namespace user par défaut (voir setup.md).

Namespace time

  • Configuration unique : Les offsets ne peuvent être configurés qu'une fois, avant le premier fork.
  • Pas d'heure réelle : Ne virtualise pas CLOCK_REALTIME, seulement les horloges monotones.

Pour aller plus loin

Documentation officielle

Articles de référence

Projets utilisant les namespaces

  • Docker/Podman/containerd : Containerisation d'applications
  • systemd-nspawn : Conteneurs légers pour systemd
  • LXC/LXD : Conteneurs système complets
  • Flatpak/Snap : Sandboxing d'applications
  • Chrome/Firefox : Sandboxing de processus de rendu
  • bubblewrap : Outil de sandboxing générique

Conclusion

Les namespaces Linux constituent une brique fondamentale de la virtualisation légère moderne. Leur conception modulaire permet de créer des niveaux d'isolation sur mesure, depuis un simple environnement de développement isolé jusqu'à des conteneurs de production complets.

La maîtrise des namespaces nécessite de comprendre :

  1. Ce que chaque type isole et dans quel contexte l'utiliser
  2. Comment les combiner pour atteindre le niveau d'isolation souhaité
  3. Leurs interactions et dépendances mutuelles
  4. Leurs limitations et les cas particuliers à gérer

Combinés avec les cgroups (pour la limitation de ressources) et les security modules (AppArmor, SELinux pour les politiques de sécurité), les namespaces permettent de construire des environnements d'exécution sûrs, isolés et performants.

Que vous développiez des outils de containerisation, construisiez des plateformes cloud, ou cherchiez simplement à mieux isoler vos applications, les namespaces sont un outil incontournable de l'écosystème Linux moderne.