virli/tutorial/4/namespaces-recap.md

532 lines
16 KiB
Markdown

\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é :
<div lang="en-US">
```bash
unshare --mount --pid --fork --mount-proc /bin/bash
```
</div>
**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é :
<div lang="en-US">
```bash
unshare --mount --uts --ipc --pid --fork --mount-proc /bin/bash
```
</div>
**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 :
<div lang="en-US">
```bash
unshare --mount --uts --ipc --net --pid --fork --mount-proc /bin/bash
```
</div>
**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 :
<div lang="en-US">
```bash
unshare --user --map-root-user \
--mount --uts --ipc --net --pid \
--fork --mount-proc /bin/bash
```
</div>
**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 :
<div lang="en-US">
```bash
unshare --user --map-root-user \
--mount --uts --ipc --net --pid --cgroup \
--fork --mount-proc /bin/bash
```
</div>
**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*
<div lang="en-US">
```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 <PID> --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
```
</div>
### Gestion réseau (namespace network)
<div lang="en-US">
```bash
# Créer un namespace network nommé
ip netns add <nom>
# Lister les namespaces network
ip netns list
# Exécuter une commande dans un namespace network
ip netns exec <nom> <commande>
# 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 <nom>
```
</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);
```
</div>
## 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
- Pages de manuel : `namespaces(7)`, `pid_namespaces(7)`, `user_namespaces(7)`,
`mount_namespaces(7)`, `network_namespaces(7)`, `ipc_namespaces(7)`,
`uts_namespaces(7)`, `cgroup_namespaces(7)`, `time_namespaces(7)`
- Documentation du noyau :
<https://www.kernel.org/doc/Documentation/admin-guide/namespaces/>
### Articles de référence
- [Namespaces in operation (série LWN)](https://lwn.net/Articles/531114/) :
série d'articles exhaustive par Michael Kerrisk
<https://lwn.net/Articles/531114/>
- [Anatomy of a user namespaces vulnerability](https://lwn.net/Articles/543273/) :
pour comprendre les enjeux de sécurité
<https://lwn.net/Articles/543273/>
### 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.