Tuto 4 ready
This commit is contained in:
parent
fb994050db
commit
c960136430
Binary file not shown.
@ -1,6 +1,6 @@
|
|||||||
include ../pandoc-opts.mk
|
include ../pandoc-opts.mk
|
||||||
|
|
||||||
SOURCES_TUTO = tutorial.md setup.md mount.md namespaces.md cmpns.md docker-exec.md networkns.md pidns.md mountns.md userns.md rendu.md
|
SOURCES_TUTO = tutorial.md mount.md intro.md setup.md howto.md setns.md setns-samples.md cmpns.md lifetime.md namespaces_more.md networkns.md pidns.md mountns.md userns.md docker-exec.md rendu.md
|
||||||
|
|
||||||
|
|
||||||
all: tutorial.pdf
|
all: tutorial.pdf
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
## Exercice : comparaison de *namespace*
|
\newpage
|
||||||
|
|
||||||
|
### Exercice : comparaison de *namespace* -- `cmpns.sh`
|
||||||
|
|
||||||
Les *namespaces* d'un programme sont exposés sous forme de liens symboliques
|
Les *namespaces* d'un programme sont exposés sous forme de liens symboliques
|
||||||
dans le répertoire `/proc/<PID>/ns/`.
|
dans le répertoire `/proc/<PID>/ns/`.
|
||||||
@ -7,10 +9,12 @@ Deux programmes qui partagent un même *namespace* auront un lien vers la même
|
|||||||
structure de données.
|
structure de données.
|
||||||
|
|
||||||
Écrivons un script ou un programme, `cmpns`, permettant de déterminer si deux
|
Écrivons un script ou un programme, `cmpns`, permettant de déterminer si deux
|
||||||
programmes s'exécutent dans les mêmes *namespaces*.
|
programmes s'exécutent dans les mêmes *namespaces*. On ignorera les
|
||||||
|
*namespace*s `*_for_children`, car ils ne font pas partie du cycle d'exécution
|
||||||
|
que l'on cherche à comparer.
|
||||||
|
|
||||||
|
|
||||||
### Exemples {.unnumbered}
|
#### Exemples {.unnumbered}
|
||||||
|
|
||||||
<div lang="en-US">
|
<div lang="en-US">
|
||||||
```
|
```
|
||||||
@ -20,6 +24,7 @@ programmes s'exécutent dans les mêmes *namespaces*.
|
|||||||
- mnt: differ
|
- mnt: differ
|
||||||
- net: differ
|
- net: differ
|
||||||
- pid: differ
|
- pid: differ
|
||||||
|
- time: same
|
||||||
- user: same
|
- user: same
|
||||||
- uts: same
|
- uts: same
|
||||||
```
|
```
|
||||||
@ -33,6 +38,7 @@ programmes s'exécutent dans les mêmes *namespaces*.
|
|||||||
- mnt: same
|
- mnt: same
|
||||||
- net: same
|
- net: same
|
||||||
- pid: same
|
- pid: same
|
||||||
|
- time: same
|
||||||
- user: same
|
- user: same
|
||||||
- uts: same
|
- uts: same
|
||||||
```
|
```
|
||||||
@ -52,6 +58,7 @@ Et pourquoi pas :
|
|||||||
- mnt: differ
|
- mnt: differ
|
||||||
- net: same
|
- net: same
|
||||||
- pid: same
|
- pid: same
|
||||||
|
- time: same
|
||||||
- user: same
|
- user: same
|
||||||
- uts: same
|
- uts: same
|
||||||
```
|
```
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
\newpage
|
||||||
|
|
||||||
Exercice : `docker exec`
|
Exercice : `docker exec`
|
||||||
------------------------
|
------------------------
|
||||||
|
|
||||||
|
@ -1,142 +1,28 @@
|
|||||||
\newpage
|
\newpage
|
||||||
|
|
||||||
Les espaces de noms -- *namespaces* {#namespaces}
|
Utiliser les *namespace*s
|
||||||
===================================
|
-------------------------
|
||||||
|
|
||||||
## Introduction
|
### S'isoler dans un nouveau *namespace*
|
||||||
|
|
||||||
Les espaces de noms du noyau, les *namespaces*, permettent de
|
Si l'on voit l'isolation procurée par les *namespace*s en parallèle avec les
|
||||||
dupliquer certaines structures, habituellement considérées uniques
|
machines virtuelle, on peut se dire qu'il suffit d'exécuter un appel système
|
||||||
pour le noyau, dans le but de les isoler d'un groupe de processus à un
|
pour arriver dans un conteneur bien isolé. Cependant, le choix fait par les
|
||||||
autre.
|
développeurs de Linux a été de laisser le choix des espaces de noms dont on veut
|
||||||
|
se dissocier.
|
||||||
|
|
||||||
On en dénombre sept (le dernier ayant été ajouté dans Linux 4.6) : `cgroup`,
|
L'intérêt principal de cette approche, exploitée bien après la mise en avant du
|
||||||
`IPC`, `network`, `mount`, `PID`, `user` et `UTS`.
|
concept, est que l'utilisation des *namespace*s ne se limite pas seulement à
|
||||||
|
des machines virtuelles légères. On retrouve ainsi dans Google Chrome de
|
||||||
|
nombreuses utilisations des *namespace*s dans le simple but d'accroître la
|
||||||
|
sécurité de leur navigateur. Ainsi, les threads de rendu n'ont pas accès au
|
||||||
|
réseau et sont cloisonnés de manière transparente pour l'utilisateur.
|
||||||
|
|
||||||
La notion d'espace de noms est relativement nouvelle et a été intégrée
|
Nous allons voir dans cette partie plusieurs méthodes pour utiliser ces espaces
|
||||||
progressivement au sein du noyau Linux. Aussi, toutes les structures
|
de noms.
|
||||||
ne sont pas encore *containerisables* :
|
|
||||||
[le document fondateur](https://www.kernel.org/doc/ols/2006/ols2006v1-pages-101-112.pdf)
|
|
||||||
parle ainsi d'isoler les périphériques, ou encore l'horloge. Pour ce
|
|
||||||
dernier,
|
|
||||||
[un patch a même déjà été proposé](https://lwn.net/Articles/766089/).
|
|
||||||
|
|
||||||
### L'espace de noms `mount` {#mount-ns}
|
|
||||||
|
|
||||||
Depuis Linux 2.4.19.
|
|
||||||
|
|
||||||
Cet espace de noms isole la liste des points de montage.
|
|
||||||
|
|
||||||
Chaque processus appartenant à un *namespace mount* différent peut monter,
|
|
||||||
démonter et réorganiser à sa guise les points de montage, sans que cela n'ait
|
|
||||||
d'impact sur les processus hors de cet espace de noms. Une partition ne sera
|
|
||||||
donc pas nécessairement démontée après un appel à `umount(2)`, elle le sera
|
|
||||||
lorsqu'elle aura effectivement été démontée de chaque *namespace mount* dans
|
|
||||||
lequel elle était montée.
|
|
||||||
|
|
||||||
Attention il convient cependant de prendre garde aux types de liaison existant
|
|
||||||
entre vos points de montage (voir la partie sur
|
|
||||||
[les particularités des points de montage](#mount)), car les montages et
|
|
||||||
démontages pourraient alors être répercutés dans l'espace de noms parent.
|
|
||||||
|
|
||||||
Une manière rapide pour s'assurer que nos modifications ne sortiront pas de
|
|
||||||
notre *namespace* est d'appliquer le type esclave à l'ensemble de nos points de
|
|
||||||
montage, récursivement, dès que l'on est entré dans notre nouvel espace de
|
|
||||||
noms.
|
|
||||||
|
|
||||||
<div lang="en-US">
|
|
||||||
```bash
|
|
||||||
mount --make-rslave /
|
|
||||||
```
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
### L'espace de noms `UTS` {#uts-ns}
|
#### Avec son coquillage\
|
||||||
|
|
||||||
Depuis Linux 2.6.19.
|
|
||||||
|
|
||||||
Cet espace de noms isole le nom de machine et son domaine NIS.
|
|
||||||
|
|
||||||
|
|
||||||
### L'espace de noms `IPC` {#ipc-ns}
|
|
||||||
|
|
||||||
Depuis Linux 2.6.19.
|
|
||||||
|
|
||||||
Cet espace de noms isole les objets IPC et les files de messages POSIX.
|
|
||||||
|
|
||||||
Une fois le *namespace* attaché à un processus, il ne peut alors plus parler
|
|
||||||
qu'avec les autres processus de son espace de noms (lorsque ceux-ci passent par
|
|
||||||
l'API IPC du noyau).
|
|
||||||
|
|
||||||
|
|
||||||
### L'espace de noms `PID`
|
|
||||||
|
|
||||||
Depuis Linux 2.6.24.
|
|
||||||
|
|
||||||
Cet espace de noms isole la liste des processus et virtualise leurs numéros.
|
|
||||||
|
|
||||||
Une fois dans un espace, le processus ne voit que le sous-arbre de processus
|
|
||||||
également attachés à son espace. Il s'agit d'un sous-ensemble de l'arbre global
|
|
||||||
de PID : les processus de tous les PID *namespaces* apparaissent donc dans
|
|
||||||
l'arbre initial.
|
|
||||||
|
|
||||||
Pour chaque nouvel espace de noms de processus, une nouvelle numérotation est
|
|
||||||
initiée. Ainsi, le premier processus de cet espace porte le numéro 1 et aura
|
|
||||||
les mêmes propriétés que le processus `init` usuel\ ; entre autre, si un
|
|
||||||
processus est rendu orphelin dans ce *namespace*, il devient un fils de ce
|
|
||||||
processus, et non un fils de l'`init` de l'arbre global.
|
|
||||||
|
|
||||||
|
|
||||||
### L'espace de nom `network`
|
|
||||||
|
|
||||||
Depuis Linux 2.6.29.
|
|
||||||
|
|
||||||
Cet espace de noms fournit une isolation pour toutes les ressources associées
|
|
||||||
aux réseaux : les interfaces, les piles protocolaires IPv4 et IPv6, les tables
|
|
||||||
de routage, règles pare-feu, ports numérotés, etc.
|
|
||||||
|
|
||||||
Une interface réseau (`eth0`, `wlan0`, ...) ne peut se trouver que dans un seul
|
|
||||||
espace de noms à la fois. Il est par contre possible de les déplacer.
|
|
||||||
|
|
||||||
Lorsque le *namespace* est libéré (généralement lorsque le dernier processus
|
|
||||||
attaché à cet espace de noms se termine), les interfaces qui le composent sont
|
|
||||||
ramenées dans l'espace initial/racine (et non pas dans l'espace parent, en cas
|
|
||||||
d'imbrication).
|
|
||||||
|
|
||||||
|
|
||||||
### L'espace de noms `user`
|
|
||||||
|
|
||||||
Depuis Linux 3.8.
|
|
||||||
|
|
||||||
Cet espace de noms isole la liste des utilisateurs, des groupes, leurs
|
|
||||||
identifiants, les *capabilities*, la racine et le trousseau de clefs du noyau.
|
|
||||||
|
|
||||||
La principale caractéristique est que les identifiants d'utilisateur et de
|
|
||||||
groupe pour un processus peuvent être différents entre l'intérieur et
|
|
||||||
l'extérieur de l'espace de noms. Il est donc possible, alors que l'on est un
|
|
||||||
simple utilisateur à l'extérieur du *namespace*, d'avoir l'UID 0 dans le
|
|
||||||
conteneur.
|
|
||||||
|
|
||||||
|
|
||||||
### L'espace de noms `cgroup` {#cgroup-ns}
|
|
||||||
|
|
||||||
Depuis Linux 4.6.
|
|
||||||
|
|
||||||
Cet espace de noms filtre l'arborescence des *Control Group* en changeant la
|
|
||||||
racine de l'arborescence des cgroups. Au sein d'un *namespace*, la racine vue
|
|
||||||
correspond en fait à un sous-groupe de l'arborescence globale.
|
|
||||||
|
|
||||||
Ainsi, un processus dans un `CGroup` *namespace* ne peut pas voir le contenu
|
|
||||||
des sous-groupes parents (pouvant laisser fuiter des informations sur le reste
|
|
||||||
du système). Cela peut également permettre de faciliter la migration de
|
|
||||||
processus (d'un système à un autre) : l'arborescence des cgroups n'a alors
|
|
||||||
plus d'importance car le processus ne voit que son groupe.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## S'isoler dans un nouveau *namespace*
|
|
||||||
|
|
||||||
### Avec son coquillage
|
|
||||||
|
|
||||||
De la même manière que l'on peut utiliser l'appel système `chroot(2)` depuis un
|
De la même manière que l'on peut utiliser l'appel système `chroot(2)` depuis un
|
||||||
shell via la commande `chroot(1)`, la commande `unshare(1)` permet de faire le
|
shell via la commande `chroot(1)`, la commande `unshare(1)` permet de faire le
|
||||||
@ -169,13 +55,16 @@ Nous avons pu ici modifier le nom de la machine, sans que cela n'affecte notre
|
|||||||
machine hôte.
|
machine hôte.
|
||||||
|
|
||||||
|
|
||||||
### Les appels systèmes
|
#### Les appels systèmes\
|
||||||
|
|
||||||
L'appel système par excellence pour contrôler l'isolation d'un nouveau
|
L'appel système par excellence pour contrôler l'isolation d'un nouveau
|
||||||
processus est `clone(2)`.
|
processus est `clone(2)`.
|
||||||
|
|
||||||
L'isolement ou non du processus est faite en fonction des `flags` qui sont
|
Ce *syscall*, propre à Linux, crée habituellement un nouveau processus (mais
|
||||||
passés à la fonction :
|
aussi des threads) enfant de notre processus courant, comme `fork(2)` (qui lui
|
||||||
|
est un appel système POSIX) mais prend en plus de nombreux
|
||||||
|
paramètres. L'isolement ou non du processus se fait en fonction des *flags* qui
|
||||||
|
sont passés :
|
||||||
|
|
||||||
* `CLONE_NEWNS`,
|
* `CLONE_NEWNS`,
|
||||||
* `CLONE_NEWUTS`,
|
* `CLONE_NEWUTS`,
|
||||||
@ -183,16 +72,18 @@ passés à la fonction :
|
|||||||
* `CLONE_NEWPID`,
|
* `CLONE_NEWPID`,
|
||||||
* `CLONE_NEWNET`,
|
* `CLONE_NEWNET`,
|
||||||
* `CLONE_NEWUSER`,
|
* `CLONE_NEWUSER`,
|
||||||
* `CLONE_NEWCGROUP`.
|
* `CLONE_NEWCGROUP`,
|
||||||
|
* `CLONE_NEWTIME`.
|
||||||
|
|
||||||
On peut bien entendu cumuler un ou plusieurs de ces `flags`, et les combiner
|
On peut bien entendu cumuler un ou plusieurs de ces *flags*, et les combiner
|
||||||
avec d'autres `flags` attendu par la fonction.
|
avec d'autres attendus par `clone(2)`.
|
||||||
|
|
||||||
Les mêmes `flags` sont utilisés lors des appels à `unshare(2)` ou `setns(2)`.
|
Ces mêmes *flags* sont utilisés lors des appels à `unshare(2)` ou `setns(2)`,
|
||||||
|
que nous verrons plus tard.
|
||||||
|
|
||||||
Pour créer un nouveau processus qui sera à la fois dans un nouvel espace de
|
Pour créer un nouveau processus qui sera à la fois dans un nouvel espace de
|
||||||
noms réseau et dans un nouveau *namespace* `cgroup`, on écrirait un code
|
noms réseau et dans un nouveau *namespace* `cgroup`, on écrirait un code C
|
||||||
similaire à :
|
semblable à :
|
||||||
|
|
||||||
<div lang="en-US">
|
<div lang="en-US">
|
||||||
```c
|
```c
|
||||||
@ -217,102 +108,30 @@ Un exemple complet d'utilisation de `clone(2)` et du *namespace* `UTS` est
|
|||||||
donné dans le `man` de l'appel système.
|
donné dans le `man` de l'appel système.
|
||||||
|
|
||||||
|
|
||||||
## Rejoindre un *namespace*
|
##### `unshare`\
|
||||||
|
|
||||||
Rejoindre un espace de noms se fait en utilisant l'appel système `setns(2)`,
|
L'appel système `clone(2)` va créer un nouveau processus, ou un nouveau
|
||||||
auquel on passe le *file descriptor* d'un des liens du dossier
|
thread. Parfois, on souhaite faire entrer notre processus ou thread en cours
|
||||||
`/proc/<PID>/ns/` :
|
dans un nouvel espace de noms. Dans ce cas, on utilisera l'appel système
|
||||||
|
`unshare(2)`. Celui-ci prend uniquement en argument une liste de *flags* des
|
||||||
|
*namespace*s dont on souhaite se dissocier.
|
||||||
|
|
||||||
<div lang="en-US">
|
::::: {.warning}
|
||||||
```c
|
Le comportement de `unshare(2)` (ou `unshare(3)`) avec les *namespace*s *PID*
|
||||||
#define _GNU_SOURCE
|
et *Time* n'est pas celui que l'on peut attendre !
|
||||||
#include <fcntl.h>
|
|
||||||
#include <sched.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
// ./a.out /proc/PID/ns/FILE cmd args...
|
En effet, après avoir appelé `unshare`, le processus reste tout de même dans
|
||||||
|
son *namespace* *Time* ou *PID* d'origine, seuls ses enfants (après un appel à
|
||||||
|
`fork(2)` ou `clone(2)` par exemple) seront dans le nouveau *namespace*.
|
||||||
|
|
||||||
int
|
Cela poserait trop de problème de faire changer le PID d'un processus en cours
|
||||||
main(int argc, char *argv[])
|
d'exécution, de même qu'il serait impensable que la `CLOCK_MONOTONIC` puisse
|
||||||
{
|
faire un saut en avant ou en arrière. Alors le choix qui a été fait est que
|
||||||
int fd = open(argv[1], O_RDONLY);
|
seuls les fils créés après l'appel à `unshare(2)` seront concrètement dans le
|
||||||
if (fd == -1)
|
nouveau *namespace*. C'est dans cette situation que `pid` et `pid_for_children`
|
||||||
{
|
peuvent être différents dans le dossier `/proc/<PID>/ns`.
|
||||||
perror("open");
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (setns(fd, 0) == -1)
|
On ne remarque pas cette bizarrerie avec `clone(2)`, car il crée déjà un
|
||||||
{
|
nouveau processus, son PID et sa `CLOCK_MONOTONIC` sont directement à la bonne
|
||||||
perror("setns");
|
valeur dès l'exécution de la fonction `fn`.
|
||||||
return EXIT_FAILURE;
|
:::::
|
||||||
}
|
|
||||||
|
|
||||||
execvp(argv[2], &argv[2]);
|
|
||||||
|
|
||||||
perror("execve");
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
</div>
|
|
||||||
|
|
||||||
Dans un shell, on utilisera la commande `nsenter(1)` :
|
|
||||||
|
|
||||||
<div lang="en-US">
|
|
||||||
```bash
|
|
||||||
42sh# nsenter --uts=/proc/42/ns/uts /bin/bash
|
|
||||||
```
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
## Durée de vie d'un *namespace* {#ns-lifetime}
|
|
||||||
|
|
||||||
Le noyau tient à jour un compteur de références pour chaque *namespace*. Dès
|
|
||||||
qu'une référence tombe à 0, l'espace de noms est automatiquement libéré, les
|
|
||||||
points de montage sont démontés, les interfaces réseaux sont réattribués à
|
|
||||||
l'espace de noms initial, ...
|
|
||||||
|
|
||||||
Ce compteur évolue selon plusieurs critères, et principalement selon le nombre
|
|
||||||
de processus qui l'utilise. C'est-à-dire que, la plupart du temps, le
|
|
||||||
*namespace* est libéré lorsque le dernier processus s'exécutant dedans se
|
|
||||||
termine.
|
|
||||||
|
|
||||||
Lorsque l'on a besoin de référencer un *namespace* (par exemple pour le faire
|
|
||||||
persister après le dernier processus), on peut utiliser un `mount bind` :
|
|
||||||
|
|
||||||
<div lang="en-US">
|
|
||||||
```bash
|
|
||||||
42sh# touch /tmp/ns/myrefns
|
|
||||||
42sh# mount --bind /proc/<PID>/ns/mount /tmp/ns/myrefns
|
|
||||||
```
|
|
||||||
</div>
|
|
||||||
|
|
||||||
De cette manière, même si le lien initial n'existe plus (si le `<PID>` s'est
|
|
||||||
terminé), `/tmp/ns/myrefns` pointera toujours au bon endroit.
|
|
||||||
|
|
||||||
On peut très bien utiliser directement ce fichier pour obtenir un descripteur
|
|
||||||
de fichier valide vers le *namespace* (pour passer à `setns(2)`).
|
|
||||||
|
|
||||||
### Faire persister un *namespace*
|
|
||||||
|
|
||||||
Il n'est pas possible de faire persister un espace de noms d'un reboot à
|
|
||||||
l'autre.
|
|
||||||
|
|
||||||
Même en étant attaché à un fichier du disque, il s'agit d'un pointeur vers une
|
|
||||||
structure du noyau, qui ne persistera pas au redémarrage.
|
|
||||||
|
|
||||||
|
|
||||||
## Aller plus loin {-}
|
|
||||||
|
|
||||||
Je vous recommande la lecture des *man* suivants :
|
|
||||||
|
|
||||||
* `namespaces(7)` : introduisant et énumérant les *namespaces* ;
|
|
||||||
|
|
||||||
Pour tout connaître en détails, [la série d'articles de Michael Kerrisk sur
|
|
||||||
les *namespaces*](https://lwn.net/Articles/531114/) est excellente ! Auquel il
|
|
||||||
faut ajouter [le petit dernier sur le `cgroup`
|
|
||||||
*namespace*](https://lwn.net/Articles/621006/).
|
|
||||||
|
|
||||||
[Cet article de Michael Crosby montrant l'utilisation de clone(2)](https://web.archive.org/web/20190206073558/http://crosbymichael.com/creating-containers-part-1.html)
|
|
||||||
est également des plus intéressants, pour ce qui concerne la programmation
|
|
||||||
plus bas-niveau.
|
|
||||||
|
159
tutorial/4/intro.md
Normal file
159
tutorial/4/intro.md
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
\newpage
|
||||||
|
|
||||||
|
Les espaces de noms -- *namespaces* {#namespaces}
|
||||||
|
===================================
|
||||||
|
|
||||||
|
Nous avons vu un certain nombre de fonctionnalités offertes par le noyau Linux
|
||||||
|
pour limiter, autoriser ou contraindre différents usages des ressources de
|
||||||
|
notre machine.
|
||||||
|
|
||||||
|
Ces fonctionnalités sont très utiles pour éviter les dénis de service, mais nos
|
||||||
|
processus ne sont pas particulièrement isolés du reste du système. On aimerait
|
||||||
|
maintenant que nos processus n'aient pas accès à l'ensemble des fichiers, ne
|
||||||
|
puissent pas interagir avec les autres processus, avoir sa propre pile
|
||||||
|
réseau, ... Voyons maintenant les *namespaces* qui vont nous permettre de faire
|
||||||
|
cela.
|
||||||
|
|
||||||
|
|
||||||
|
Initiation rapide
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
Les espaces de noms du noyau, que l'on appelle *namespaces*, permettent de
|
||||||
|
dupliquer certaines structures, habituellement considérées uniques pour le
|
||||||
|
noyau, dans le but de les isoler d'un groupe de processus à un autre.
|
||||||
|
|
||||||
|
On en dénombre huit (le dernier ayant été ajouté dans Linux 5.6) : `cgroup`,
|
||||||
|
`IPC`, `network`, `mount`, `PID`, `time`, `user` et `UTS`.
|
||||||
|
|
||||||
|
La notion d'espace de noms est relativement nouvelle et a été intégrée
|
||||||
|
progressivement au sein du noyau Linux. Aussi, toutes les structures ne sont
|
||||||
|
pas encore *containerisables* : le document fondateur[^NSDOC] parle ainsi
|
||||||
|
d'isoler les journaux d'événements ou encore les modules de sécurité (LSM, tels
|
||||||
|
que AppArmor, SELinux, Yama, ...).
|
||||||
|
|
||||||
|
[^NSDOC]: <https://www.kernel.org/doc/ols/2006/ols2006v1-pages-101-112.pdf>
|
||||||
|
|
||||||
|
|
||||||
|
#### L'espace de noms `mount` {.unnumbered #mount-ns}
|
||||||
|
|
||||||
|
Depuis Linux 2.4.19.
|
||||||
|
|
||||||
|
Cet espace de noms isole la liste des points de montage.
|
||||||
|
|
||||||
|
Chaque processus appartenant à un *namespace mount* différent peut monter,
|
||||||
|
démonter et réorganiser à sa guise les points de montage, sans que cela n'ait
|
||||||
|
d'impact sur les processus hors de cet espace de noms. Une partition ne sera
|
||||||
|
donc pas nécessairement démontée après un appel à `umount(2)`, elle le sera
|
||||||
|
lorsqu'elle aura effectivement été démontée de chaque *namespace mount* dans
|
||||||
|
lequel elle était montée.
|
||||||
|
|
||||||
|
|
||||||
|
#### L'espace de noms `UTS` {.unnumbered #uts-ns}
|
||||||
|
|
||||||
|
Depuis Linux 2.6.19.
|
||||||
|
|
||||||
|
Cet espace de noms isole le nom de machine et son domaine NIS.
|
||||||
|
|
||||||
|
|
||||||
|
#### L'espace de noms `IPC` {.unnumbered #ipc-ns}
|
||||||
|
|
||||||
|
Depuis Linux 2.6.19.
|
||||||
|
|
||||||
|
Cet espace de noms isole les objets IPC et les files de messages POSIX.
|
||||||
|
|
||||||
|
Une fois le *namespace* attaché à un processus, il ne peut alors plus parler
|
||||||
|
qu'avec les autres processus de son espace de noms (lorsque ceux-ci passent par
|
||||||
|
l'API IPC du noyau).
|
||||||
|
|
||||||
|
|
||||||
|
#### L'espace de noms `PID` {.unnumbered}
|
||||||
|
|
||||||
|
Depuis Linux 2.6.24.
|
||||||
|
|
||||||
|
Cet espace de noms isole la liste des processus et virtualise leurs numéros.
|
||||||
|
|
||||||
|
Une fois dans un espace, le processus ne voit que le sous-arbre de processus
|
||||||
|
également attachés à son espace. Il s'agit d'un sous-ensemble de l'arbre global
|
||||||
|
de PID : les processus de tous les PID *namespaces* apparaissent donc dans
|
||||||
|
l'arbre initial.
|
||||||
|
|
||||||
|
Pour chaque nouvel espace de noms de processus, une nouvelle numérotation est
|
||||||
|
initiée. Ainsi, le premier processus de cet espace porte le numéro 1 et aura
|
||||||
|
les mêmes propriétés que le processus `init` usuel\ ; entre autres, si un
|
||||||
|
processus est rendu orphelin dans ce *namespace*, il devient un fils de ce
|
||||||
|
processus, et non un fils de l'`init` de l'arbre global.
|
||||||
|
|
||||||
|
|
||||||
|
#### L'espace de nom `network` {.unnumbered}
|
||||||
|
|
||||||
|
Depuis Linux 2.6.29.
|
||||||
|
|
||||||
|
Cet espace de noms fournit une isolation pour toutes les ressources associées
|
||||||
|
aux réseaux : les interfaces, les piles protocolaires IPv4 et IPv6, les tables
|
||||||
|
de routage, règles pare-feu, ports numérotés, etc.
|
||||||
|
|
||||||
|
Une interface réseau (`eth0`, `wlan0`, ...) ne peut se trouver que dans un seul
|
||||||
|
espace de noms à la fois. Il est par contre possible de les déplacer.
|
||||||
|
|
||||||
|
Lorsque le *namespace* est libéré (généralement lorsque le dernier processus
|
||||||
|
attaché à cet espace de noms se termine), les interfaces qui le composent sont
|
||||||
|
ramenées dans l'espace initial/racine (et non pas dans l'espace parent, en cas
|
||||||
|
d'imbrication).
|
||||||
|
|
||||||
|
|
||||||
|
#### L'espace de noms `user` {.unnumbered}
|
||||||
|
|
||||||
|
Depuis Linux 3.8.
|
||||||
|
|
||||||
|
Cet espace de noms isole la liste des utilisateurs, des groupes, leurs
|
||||||
|
identifiants, les *capabilities*, la racine et le trousseau de clefs du noyau.
|
||||||
|
|
||||||
|
La principale caractéristique est que les identifiants d'utilisateur et de
|
||||||
|
groupe pour un processus peuvent être différents entre l'intérieur et
|
||||||
|
l'extérieur de l'espace de noms. Il est donc possible, alors que l'on est un
|
||||||
|
simple utilisateur à l'extérieur du *namespace*, d'avoir l'UID 0 dans le
|
||||||
|
conteneur.
|
||||||
|
|
||||||
|
|
||||||
|
#### L'espace de noms `cgroup` {.unnumbered #cgroup-ns}
|
||||||
|
|
||||||
|
Depuis Linux 4.6.
|
||||||
|
|
||||||
|
Cet espace de noms filtre l'arborescence des *Control Group* en changeant la
|
||||||
|
racine vue par le processus. Au sein d'un *namespace* `cgroup`, la racine vue
|
||||||
|
correspond en fait à un sous-groupe de l'arborescence globale.
|
||||||
|
|
||||||
|
Ainsi, un processus dans un *CGroup* *namespace* ne peut pas voir le contenu
|
||||||
|
des sous-groupes parents (pouvant laisser fuiter des informations sur le reste
|
||||||
|
du système). Cela peut également permettre de faciliter la migration de
|
||||||
|
processus (d'un système à un autre) : l'arborescence des *cgroups* n'a alors
|
||||||
|
plus d'importance car le processus ne voit que son groupe.
|
||||||
|
|
||||||
|
|
||||||
|
#### L'espace de noms `time` {.unnumbered #time-ns}
|
||||||
|
|
||||||
|
Depuis Linux 5.6.
|
||||||
|
|
||||||
|
Avec cet espace de noms, il n'est pas possible de virtualiser l'heure d'un de
|
||||||
|
nos conteneurs (on peut seulement changer le fuseau horaire, puisqu'ils sont
|
||||||
|
gérés par la `libc`). Les horloges virtualisations avec ce *namespace* sont les
|
||||||
|
compteurs `CLOCK_MONOTONIC` et `CLOCK_BOOTTIME`.
|
||||||
|
|
||||||
|
Lorsque l'on souhaite mesurer un écoulement de temps, la méthode naïve consiste
|
||||||
|
à enregistrer l'heure au départ de notre opération, puis à faire une
|
||||||
|
soustraction avec l'heure de fin. Cette technique fonctionne bien, à partir du
|
||||||
|
moment où l'on est sûr que l'horloge ne remontera pas dans le temps, parce
|
||||||
|
qu'elle se synchronise ou que le changement d'heure été/hiver
|
||||||
|
intervient, ... Pour palier ces situations imprévisibles, le noyau expose une
|
||||||
|
horloge dite monotone (`CLOCK_MONOTONIC`) : cette horloge démarre à un entier
|
||||||
|
abstrait et s'incrèmente chaque seconde qui passe, sans jamais sauter de
|
||||||
|
secondes, ni revenir en arrière. C'est une horloge fiable pour calculer des
|
||||||
|
intervalles de temps.
|
||||||
|
|
||||||
|
De la même manière `CLOCK_BOOTTIME` mesure le temps qui s'écoule, mais prend en
|
||||||
|
compte les moments où la machine est en veille (alors que `CLOCK_MONOTONIC` ne
|
||||||
|
compte que les moments où la machine est en éveil).
|
||||||
|
|
||||||
|
Étant donné l'usage de ces deux horloges, en cas de migration d'un processus
|
||||||
|
d'une machine à une autre, il convient de recopier l'état des horloges
|
||||||
|
monotones qu'il utilise, afin que ses calculs ne soient pas chamboulés.
|
40
tutorial/4/lifetime.md
Normal file
40
tutorial/4/lifetime.md
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
### Durée de vie d'un *namespace* {#ns-lifetime}
|
||||||
|
|
||||||
|
Le noyau tient à jour un compteur de références pour chaque *namespace*. Dès
|
||||||
|
qu'une référence tombe à 0, la structure de l'espace de noms est
|
||||||
|
automatiquement libérée, les points de montage sont démontés, les interfaces
|
||||||
|
réseaux sont réattribués à l'espace de noms initial, ...
|
||||||
|
|
||||||
|
Ce compteur évolue selon plusieurs critères, et principalement selon le nombre
|
||||||
|
de processus qui l'utilisent. C'est-à-dire que, la plupart du temps, le
|
||||||
|
*namespace* est libéré lorsque le dernier processus s'exécutant dedans se
|
||||||
|
termine.
|
||||||
|
|
||||||
|
Lorsque l'on a besoin de référencer un *namespace* (par exemple pour le faire
|
||||||
|
persister après le dernier processus), on peut utiliser un `mount bind` :
|
||||||
|
|
||||||
|
<div lang="en-US">
|
||||||
|
```bash
|
||||||
|
42sh# touch /tmp/ns/myrefns
|
||||||
|
42sh# mount --bind /proc/<PID>/ns/mount /tmp/ns/myrefns
|
||||||
|
```
|
||||||
|
</div>
|
||||||
|
|
||||||
|
De cette manière, même si le lien initial n'existe plus (si le `<PID>` s'est
|
||||||
|
terminé), `/tmp/ns/myrefns` pointera toujours au bon endroit.
|
||||||
|
|
||||||
|
Il est aussi tout à fait possible d'utiliser directement ce fichier pour
|
||||||
|
obtenir un descripteur de fichier valide vers le *namespace* (pour passer à
|
||||||
|
`setns(2)`).
|
||||||
|
|
||||||
|
|
||||||
|
::::: {.question}
|
||||||
|
#### Faire persister un *namespace* ? {-}
|
||||||
|
\
|
||||||
|
|
||||||
|
Il n'est pas possible de faire persister un espace de noms d'un reboot à
|
||||||
|
l'autre.\
|
||||||
|
|
||||||
|
Même en étant attaché à un fichier du disque, il s'agit d'un pointeur vers une
|
||||||
|
structure du noyau, qui ne persistera pas au redémarrage.
|
||||||
|
:::::
|
@ -3,7 +3,10 @@
|
|||||||
Des particularités de `mount` {#mount}
|
Des particularités de `mount` {#mount}
|
||||||
=============================
|
=============================
|
||||||
|
|
||||||
Petite parenthèse avant de parler des *namespaces* ...
|
Petite parenthèse avant de parler des *namespaces*, car nous avons encore
|
||||||
|
besoin d'appréhender un certain nombre de concepts relatifs aux montages de
|
||||||
|
systèmes de fichiers.
|
||||||
|
|
||||||
|
|
||||||
## Les points de montage
|
## Les points de montage
|
||||||
|
|
||||||
@ -19,7 +22,7 @@ deux endroits différents de votre arborescence ?
|
|||||||
Si pour plein de raisons on pouvait se dire que cela ne devrait pas être
|
Si pour plein de raisons on pouvait se dire que cela ne devrait pas être
|
||||||
autorisé, ce problème s'avère être à la base de beaucoup de fonctionnalités
|
autorisé, ce problème s'avère être à la base de beaucoup de fonctionnalités
|
||||||
intéressantes. Le noyau va finalement décorréler les notions de montage,
|
intéressantes. Le noyau va finalement décorréler les notions de montage,
|
||||||
d'accès et d'accroches dans l'arborescence : et par exemple, une partition ne
|
d'accès et d'accroche dans l'arborescence : et par exemple, une partition ne
|
||||||
sera plus forcément démontée après un appel à `umount(2)`, mais le sera
|
sera plus forcément démontée après un appel à `umount(2)`, mais le sera
|
||||||
seulement lorsque cette partition n'aura plus d'accroches dans aucune
|
seulement lorsque cette partition n'aura plus d'accroches dans aucune
|
||||||
arborescence.
|
arborescence.
|
||||||
@ -59,7 +62,7 @@ TARGET SOURCE FSTYPE OPTIONS
|
|||||||
```
|
```
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
## `bind`
|
## `bind` -- montage miroir
|
||||||
|
|
||||||
Lorsque l'on souhaite monter à un deuxième endroit (ou plus) une partition, on
|
Lorsque l'on souhaite monter à un deuxième endroit (ou plus) une partition, on
|
||||||
utilise le *bind mount* :
|
utilise le *bind mount* :
|
||||||
@ -115,9 +118,9 @@ mount --rbind /sys sys
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
## Les montages parfumés
|
## Les types de propagation des points de montage
|
||||||
|
|
||||||
On distingue quatre variétés de répercution des montages pour un sous-arbre :
|
On distingue quatre variétés de propagation des montages pour un sous-arbre :
|
||||||
partagé, esclave, privé et non-attachable.
|
partagé, esclave, privé et non-attachable.
|
||||||
|
|
||||||
Chacun va agir sur la manière dont seront propagées les nouvelles accroches au
|
Chacun va agir sur la manière dont seront propagées les nouvelles accroches au
|
||||||
@ -232,7 +235,7 @@ mount --bind /mnt/test-slave /mnt/test-unbindable
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
### Parfums récursifs
|
### Propagation récursive
|
||||||
|
|
||||||
Les options que nous venons de voir s'appliquent sur un point de montage. Il
|
Les options que nous venons de voir s'appliquent sur un point de montage. Il
|
||||||
existe les mêmes options pour les appliquer en cascade sur les points d'attache
|
existe les mêmes options pour les appliquer en cascade sur les points d'attache
|
||||||
@ -248,7 +251,7 @@ mount --make-runbindable mountpoint
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
## `bind` de dossiers et de fichiers
|
## Montage miroir de dossiers et de fichiers
|
||||||
|
|
||||||
Il n'est pas nécessaire que le point d'accroche que l'on cherche à dupliquer
|
Il n'est pas nécessaire que le point d'accroche que l'on cherche à dupliquer
|
||||||
pointe sur un point de montage (c'est-à-dire, dans la plupart des cas : une
|
pointe sur un point de montage (c'est-à-dire, dans la plupart des cas : une
|
||||||
@ -258,7 +261,7 @@ que l'on pourrait faire entre plusieurs partitions et qui ne persisterait pas
|
|||||||
au redémarrage (le *hardlink* persiste au redémarrage, mais doit se faire au
|
au redémarrage (le *hardlink* persiste au redémarrage, mais doit se faire au
|
||||||
sein d'une même partition).
|
sein d'une même partition).
|
||||||
|
|
||||||
Nous verrons dans la partie [*namespace* réseau](#net-ns), une utilisation
|
Nous verrons dans la partie [*namespace* réseau](#net-ns) une utilisation
|
||||||
d'attache sur un fichier.
|
d'attache sur un fichier.
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,17 +1,33 @@
|
|||||||
\newpage
|
\newpage
|
||||||
|
|
||||||
Le *namespace* `mount`
|
Le *namespace* `mount`
|
||||||
======================
|
----------------------
|
||||||
|
|
||||||
L'espace de noms `mount` permet d'isoler la vision du système de fichiers
|
L'espace de noms `mount` permet d'isoler la vision du système de fichiers
|
||||||
qu'ont un processus et ses fils.
|
qu'ont un processus et ses fils.
|
||||||
|
|
||||||
Peut-être que l'on peut trouver avec ça, un moyen de faire un `chroot` plus sûr ?
|
Peut-être que l'on peut trouver avec ça, un moyen de faire un `chroot` plus sûr ?
|
||||||
|
|
||||||
|
::::: {.warning}
|
||||||
|
Attention il convient de prendre garde aux types de liaison existant entre vos
|
||||||
|
points de montage (voir la partie sur [les particularités des points de
|
||||||
|
montage](#mount)), car les montages et démontages pourraient alors être
|
||||||
|
répercutés dans l'espace de noms parent.\
|
||||||
|
|
||||||
## Préparation du changement de racine
|
Une manière rapide pour s'assurer que nos modifications ne sortiront pas de
|
||||||
|
notre *namespace* est d'appliquer le type esclave à l'ensemble de nos points de
|
||||||
|
montage, récursivement, dès que l'on est entré dans notre nouvel espace de
|
||||||
|
noms.
|
||||||
|
|
||||||
### Avant propos
|
<div lang="en-US">
|
||||||
|
```bash
|
||||||
|
mount --make-rslave /
|
||||||
|
```
|
||||||
|
</div>
|
||||||
|
:::::
|
||||||
|
|
||||||
|
|
||||||
|
### Préparation du changement de racine
|
||||||
|
|
||||||
Nous allons essayer de changer la racine de notre système de fichier. À la
|
Nous allons essayer de changer la racine de notre système de fichier. À la
|
||||||
différence d'un `chroot(2)`, changer de racine est quelque chose d'un peu plus
|
différence d'un `chroot(2)`, changer de racine est quelque chose d'un peu plus
|
||||||
@ -29,7 +45,7 @@ montage virtuels. Le changement de racine sera donc effectif uniquement dans
|
|||||||
cet espace de noms.
|
cet espace de noms.
|
||||||
|
|
||||||
|
|
||||||
### L'environnement
|
#### L'environnement\
|
||||||
|
|
||||||
Pour pouvoir changer de racine, il est nécessaire que la nouvelle racine soit
|
Pour pouvoir changer de racine, il est nécessaire que la nouvelle racine soit
|
||||||
la racine d'un point de montage, comme l'explique `pivot_root(2)`. En effet, il
|
la racine d'un point de montage, comme l'explique `pivot_root(2)`. En effet, il
|
||||||
@ -49,7 +65,7 @@ Placez ensuite dans cette nouvelle racine le système de votre choix (cf. le TP
|
|||||||
précédent pour les différentes méthodes et liens).
|
précédent pour les différentes méthodes et liens).
|
||||||
|
|
||||||
|
|
||||||
## Changer de racine
|
### Exercice : Changer de racine -- `myswitch_root.sh`
|
||||||
|
|
||||||
Voici les grandes étapes du changement de racine :
|
Voici les grandes étapes du changement de racine :
|
||||||
|
|
||||||
@ -59,7 +75,7 @@ Voici les grandes étapes du changement de racine :
|
|||||||
3. `pivot_root` !
|
3. `pivot_root` !
|
||||||
|
|
||||||
|
|
||||||
### S'isoler
|
#### S'isoler\
|
||||||
|
|
||||||
Notre but étant de démonter toutes les partitions superflues, nous allons
|
Notre but étant de démonter toutes les partitions superflues, nous allons
|
||||||
devoir nous isoler sur :
|
devoir nous isoler sur :
|
||||||
@ -79,14 +95,14 @@ Isolons-nous :
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
### Dissocier la propagation des démontages
|
#### Dissocier la propagation des démontages\
|
||||||
|
|
||||||
Attention ! avant de pouvoir commencer à démonter les partitions, il faut
|
Attention ! avant de pouvoir commencer à démonter les partitions, il faut
|
||||||
s'assurer que les démontages ne se propagent pas via une politique de *shared
|
s'assurer que les démontages ne se propagent pas via une politique de *shared
|
||||||
mount*.
|
mount*.
|
||||||
|
|
||||||
Commençons donc par étiqueter tous nos points de montage (de ce *namespace*),
|
Commençons donc par étiqueter tous nos points de montage (de ce *namespace*),
|
||||||
comme esclave :
|
comme esclaves :
|
||||||
|
|
||||||
<div lang="en-US">
|
<div lang="en-US">
|
||||||
```bash
|
```bash
|
||||||
@ -95,26 +111,26 @@ comme esclave :
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
### Démonter tout !
|
#### Démonter tout !\
|
||||||
|
|
||||||
À vous maintenant de démonter vos points d'attache. Il ne devrait vous rester
|
À vous maintenant de démonter vos points d'attache. Il ne devrait vous rester
|
||||||
après cette étape que : `/`, `/dev`, `/sys`, `/proc`, `/run` et leurs fils.
|
après cette étape que : `/`, `/dev`, `/sys`, `/proc`, `/run` et leurs fils.
|
||||||
|
|
||||||
|
|
||||||
### Switch !
|
#### Switch !\
|
||||||
|
|
||||||
À ce stade, dans votre console, vous avez plusieurs solutions : utiliser
|
À ce stade, dans votre console, vous avez plusieurs solutions : utiliser
|
||||||
`switch_root(8)` ou `pivot_root(8)`. La première abstrait plus de choses que la
|
`switch_root(8)` ou `pivot_root(8)`. La première abstrait plus de choses que la
|
||||||
seconde.
|
seconde.
|
||||||
|
|
||||||
|
|
||||||
#### `switch_root`
|
##### `switch_root`\
|
||||||
|
|
||||||
Cette commande s'occupe de déplacer les partitions restantes pour vous, et lance
|
Cette commande s'occupe de déplacer les partitions restantes pour vous, et lance
|
||||||
la première commande (*init*) de votre choix.
|
la première commande (*init*) de votre choix.
|
||||||
|
|
||||||
|
|
||||||
#### `pivot_root`
|
##### `pivot_root`\
|
||||||
|
|
||||||
Cette commande, plus proche du fonctionnement de l'appel système
|
Cette commande, plus proche du fonctionnement de l'appel système
|
||||||
`pivot_root(2)`, requiert de notre part que nous ayons préalablement déplacé
|
`pivot_root(2)`, requiert de notre part que nous ayons préalablement déplacé
|
||||||
|
14
tutorial/4/namespaces_more.md
Normal file
14
tutorial/4/namespaces_more.md
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
### Aller plus loin {-}
|
||||||
|
|
||||||
|
Je vous recommande la lecture du *man* `namespaces(7)` introduisant et
|
||||||
|
énumérant les *namespaces*.
|
||||||
|
|
||||||
|
Pour tout connaître en détails, [la série d'articles de Michael Kerrisk sur les
|
||||||
|
*namespaces*](https://lwn.net/Articles/531114/) est excellente ! Auquel il faut
|
||||||
|
ajouter [l'article sur le plus récent `cgroup`
|
||||||
|
*namespace*](https://lwn.net/Articles/621006/) et [le petit dernier sur le
|
||||||
|
*namespace* `time`](https://lwn.net/Articles/766089/).
|
||||||
|
|
||||||
|
[Cet article de Michael Crosby montrant l'utilisation de clone(2)](https://web.archive.org/web/20190206073558/http://crosbymichael.com/creating-containers-part-1.html)
|
||||||
|
est également des plus intéressants, pour ce qui concerne la programmation
|
||||||
|
plus bas-niveau.
|
@ -1,15 +1,15 @@
|
|||||||
\newpage
|
\newpage
|
||||||
|
|
||||||
Le *namespace* `network` {#net-ns}
|
Le *namespace* `network` {#net-ns}
|
||||||
========================
|
------------------------
|
||||||
|
|
||||||
## Introduction
|
### Introduction
|
||||||
|
|
||||||
L'espace de noms `network`, comme son nom l'indique permet de virtualiser tout
|
L'espace de noms `network`, comme son nom l'indique permet de virtualiser tout
|
||||||
ce qui est en lien avec le réseau : les interfaces, les ports, les routes, les
|
ce qui est en lien avec le réseau : les interfaces, les ports, les routes, les
|
||||||
règles de filtrage, etc.
|
règles de filtrage, etc.
|
||||||
|
|
||||||
En entrant dans un nouvel espace de nom `network`, on se retrouve dans un
|
En entrant dans un nouvel espace de noms `network`, on se retrouve dans un
|
||||||
environnement qui n'a plus qu'une interface de *loopback* :
|
environnement qui n'a plus qu'une interface de *loopback* :
|
||||||
|
|
||||||
<div lang="en-US">
|
<div lang="en-US">
|
||||||
@ -30,12 +30,12 @@ possible de lancer un serveur web sans qu'il n'entre en conflit avec celui d'un
|
|||||||
autre espace de noms.
|
autre espace de noms.
|
||||||
|
|
||||||
|
|
||||||
## Premiers pas avec `ip netns`
|
### Premiers pas avec `ip netns`
|
||||||
|
|
||||||
La suite d'outils `iproute2` propose une interface simplifiée pour utiliser le
|
La suite d'outils `iproute2` propose une interface simplifiée pour utiliser le
|
||||||
*namespace* `network` : `ip netns`.
|
*namespace* `network` : `ip netns`.
|
||||||
|
|
||||||
Nous pouvons tout d'abord créer un nouvel espace de nom :
|
Nous pouvons tout d'abord créer un nouvel espace de noms :
|
||||||
|
|
||||||
<div lang="en-US">
|
<div lang="en-US">
|
||||||
```bash
|
```bash
|
||||||
@ -84,7 +84,7 @@ PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
## *Virtual Ethernet*
|
### *Virtual Ethernet*
|
||||||
|
|
||||||
Étant donné qu'une interface réseau ne peut être présente que dans un seul
|
Étant donné qu'une interface réseau ne peut être présente que dans un seul
|
||||||
espace de noms à la fois, il n'est pas bien pratique d'imposer d'avoir une
|
espace de noms à la fois, il n'est pas bien pratique d'imposer d'avoir une
|
||||||
@ -106,7 +106,7 @@ créé deux interfaces `veth0` et `veth1` : les paquets envoyés sur `veth0` son
|
|||||||
donc reçus par `veth1` et les paquets envoyés à `veth1` sont reçus par `veth0`.
|
donc reçus par `veth1` et les paquets envoyés à `veth1` sont reçus par `veth0`.
|
||||||
|
|
||||||
Dans cette configuration, ces deux interfaces ne sont pas très utiles, mais si
|
Dans cette configuration, ces deux interfaces ne sont pas très utiles, mais si
|
||||||
l'on place l'une des deux extrêmités dans un autre *namespace* `network`, il
|
l'on place l'une des deux extrémités dans un autre *namespace* `network`, il
|
||||||
devient alors possible de réaliser un échange de paquets entre les deux.
|
devient alors possible de réaliser un échange de paquets entre les deux.
|
||||||
|
|
||||||
Pour déplacer `veth1` dans notre *namespace* `virli` :
|
Pour déplacer `veth1` dans notre *namespace* `virli` :
|
||||||
@ -143,7 +143,7 @@ Il ne reste donc pas grand chose à faire pour fournir Internet à notre
|
|||||||
conteneur : via un peu de NAT ou grâce à un pont Ethernet.
|
conteneur : via un peu de NAT ou grâce à un pont Ethernet.
|
||||||
|
|
||||||
|
|
||||||
## Les autres types d'interfaces
|
### Les autres types d'interfaces
|
||||||
|
|
||||||
Le bridge ou le NAT obligera tous les paquets à passer à travers de nombreuses
|
Le bridge ou le NAT obligera tous les paquets à passer à travers de nombreuses
|
||||||
couches du noyau. Utiliser les interfaces *veth* est plutôt simple et disponible
|
couches du noyau. Utiliser les interfaces *veth* est plutôt simple et disponible
|
||||||
@ -151,7 +151,7 @@ partout, mais c'est loin d'être la technique la plus rapide ou la moins
|
|||||||
gourmande.
|
gourmande.
|
||||||
|
|
||||||
|
|
||||||
### VLAN
|
#### VLAN\
|
||||||
|
|
||||||
Il est possible d'attribuer juste une interface de VLAN, si l'on a un switch
|
Il est possible d'attribuer juste une interface de VLAN, si l'on a un switch
|
||||||
supportant la technologie [802.1q](https://fr.wikipedia.org/wiki/IEEE_802.1Q)
|
supportant la technologie [802.1q](https://fr.wikipedia.org/wiki/IEEE_802.1Q)
|
||||||
@ -166,7 +166,7 @@ derrière notre machine.
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
### MACVLAN
|
#### MACVLAN\
|
||||||
|
|
||||||
<!-- https://hicu.be/bridge-vs-macvlan -->
|
<!-- https://hicu.be/bridge-vs-macvlan -->
|
||||||
|
|
||||||
@ -180,7 +180,7 @@ destination d'un MAC seront délivrés à l'interface possédant la MAC. Les
|
|||||||
différences entre les modes se trouvent au niveau de la communication entre les
|
différences entre les modes se trouvent au niveau de la communication entre les
|
||||||
interfaces.
|
interfaces.
|
||||||
|
|
||||||
#### VEPA
|
##### VEPA
|
||||||
|
|
||||||
Dans ce mode, tous les paquets sortants sont directement envoyés sur
|
Dans ce mode, tous les paquets sortants sont directement envoyés sur
|
||||||
l'interface Ethernet de sortie, sans qu'aucun routage préalable n'ait été
|
l'interface Ethernet de sortie, sans qu'aucun routage préalable n'ait été
|
||||||
@ -198,7 +198,7 @@ Pour construire une nouvelle interface de ce type :
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
#### *Private*
|
##### *Private*
|
||||||
|
|
||||||
À la différence du mode *VEPA*, si un paquet émis par un conteneur à
|
À la différence du mode *VEPA*, si un paquet émis par un conteneur à
|
||||||
destination d'un autre conteneur est réfléchi par un switch, le paquet ne sera
|
destination d'un autre conteneur est réfléchi par un switch, le paquet ne sera
|
||||||
@ -214,7 +214,7 @@ conteneur de la même machine.
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
#### *Bridge*
|
##### *Bridge*
|
||||||
|
|
||||||
À l'inverse des modes *VEPA* et *private*, les paquets sont routés selon leur
|
À l'inverse des modes *VEPA* et *private*, les paquets sont routés selon leur
|
||||||
adresse MAC : si jamais une adresse MAC est connue, le paquet est délivré à
|
adresse MAC : si jamais une adresse MAC est connue, le paquet est délivré à
|
||||||
@ -230,12 +230,12 @@ Pour construire une nouvelle interface de ce type :
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
## Aller plus loin {-}
|
### Aller plus loin {-}
|
||||||
|
|
||||||
Pour approfondir les différentes techniques de routage, je vous
|
Pour approfondir les différentes techniques de routage, je vous
|
||||||
recommande cet article :
|
recommande cet article :
|
||||||
[Linux Containers and Networking](https://blog.flameeyes.eu/2010/09/linux-containers-and-networking).
|
[Linux Containers and Networking](https://blog.flameeyes.eu/2010/09/linux-containers-and-networking).
|
||||||
|
|
||||||
Appliqué à Docker, vous apprécirez cet article : [Understanding Docker
|
Appliqué à Docker, vous apprécierez cet article : [Understanding Docker
|
||||||
Networking Drivers and their use
|
Networking Drivers and their use
|
||||||
cases](https://www.docker.com/blog/understanding-docker-networking-drivers-use-cases/).
|
cases](https://www.docker.com/blog/understanding-docker-networking-drivers-use-cases/).
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
\newpage
|
\newpage
|
||||||
|
|
||||||
Le *namespace* `PID` {#pid-ns}
|
Le *namespace* `PID` {#pid-ns}
|
||||||
=====================
|
--------------------
|
||||||
|
|
||||||
## Introduction {#pid-ns-intro}
|
### Introduction {#pid-ns-intro}
|
||||||
|
|
||||||
L'espace de noms `PID` est celui qui va nous permettre d'isoler un sous-arbre
|
L'espace de noms `PID` est celui qui va nous permettre d'isoler un sous-arbre
|
||||||
de processus en créant un nouvel arbre, qui aura son propre processus considéré
|
de processus en créant un nouvel arbre, qui aura son propre processus considéré
|
||||||
@ -18,7 +18,7 @@ pas de PID en cours de route, puisqu'il dépend du *namespace* dans lequel il se
|
|||||||
trouve.
|
trouve.
|
||||||
|
|
||||||
|
|
||||||
## Isolons !
|
### Isolons !
|
||||||
|
|
||||||
Première étape s'isoler :
|
Première étape s'isoler :
|
||||||
|
|
||||||
@ -32,7 +32,7 @@ Nous utilisons ici l'option `-f`, pour que le passage dans le nouvel espace de
|
|||||||
noms des PID soit effectif (cf. [Introduction](#pid-ns-intro)).
|
noms des PID soit effectif (cf. [Introduction](#pid-ns-intro)).
|
||||||
|
|
||||||
Un coup d'œil à `top` ou `ps aux` devrait nous montrer que l'on est maintenant
|
Un coup d'œil à `top` ou `ps aux` devrait nous montrer que l'on est maintenant
|
||||||
seul processus ... pourtant, il n'en est rien, ces deux commandes continuent
|
le seul processus ... pourtant, il n'en est rien, ces deux commandes continuent
|
||||||
d'afficher la liste complète des processus de notre système.
|
d'afficher la liste complète des processus de notre système.
|
||||||
|
|
||||||
Cela est dû au fait que ces deux programmes, sous Linux, se basent sur le
|
Cela est dû au fait que ces deux programmes, sous Linux, se basent sur le
|
||||||
@ -45,7 +45,7 @@ notre système initial. Pour s'en sortir, il est nécessaire de s'isoler dans un
|
|||||||
*namespace* `mount` séparé.
|
*namespace* `mount` séparé.
|
||||||
|
|
||||||
|
|
||||||
### Double isolation : ajout du *namespace* `mount`
|
#### Double isolation : ajout du *namespace* `mount`\
|
||||||
|
|
||||||
Voici la nouvelle ligne de commande que l'on va utiliser :
|
Voici la nouvelle ligne de commande que l'on va utiliser :
|
||||||
|
|
||||||
@ -62,7 +62,7 @@ Cette fois, `top` et `ps` nous rapportent bien que l'on est seul dans notre
|
|||||||
*namespace*.
|
*namespace*.
|
||||||
|
|
||||||
|
|
||||||
## Arborescence à l'extérieur du *namespace*
|
### Arborescence à l'extérieur du *namespace*
|
||||||
|
|
||||||
Lors de notre première tentative de `top`, lorsque `/proc` était encore monté
|
Lors de notre première tentative de `top`, lorsque `/proc` était encore monté
|
||||||
sur le `procfs` de l'espace de noms initial : notre processus (au PID 1 dans
|
sur le `procfs` de l'espace de noms initial : notre processus (au PID 1 dans
|
||||||
@ -79,14 +79,14 @@ parent, il faut le faire avec son identifiant de processus du même *namespace*
|
|||||||
que le processus appelant.
|
que le processus appelant.
|
||||||
|
|
||||||
|
|
||||||
## Processus orphelins et `nsenter`
|
### Processus orphelins et `nsenter`
|
||||||
|
|
||||||
Au sein d'un *namespace*, le processus au PID 1 est considéré comme le
|
Au sein d'un *namespace*, le processus au PID 1 est considéré comme le
|
||||||
programme `init`, les mêmes propriétés s'appliquent donc.
|
programme `init`, les mêmes propriétés s'appliquent donc.
|
||||||
|
|
||||||
Si un processus est orphelin, il est donc affiché comme étant fils du PID 1
|
Si un processus est orphelin, il est donc affiché comme étant fils du PID 1
|
||||||
dans son *namespace*[^PR_SET_CHILD_SUBREAPER] ; il n'est pas sorti de l'espace
|
dans son *namespace*[^PR_SET_CHILD_SUBREAPER] ; il n'est pas sorti de l'espace
|
||||||
de nom.
|
de noms.
|
||||||
|
|
||||||
[^PR_SET_CHILD_SUBREAPER]: en réalité, ce comportement est lié à la propriété
|
[^PR_SET_CHILD_SUBREAPER]: en réalité, ce comportement est lié à la propriété
|
||||||
`PR_SET_CHILD_SUBREAPER`, qui peut être définie pour n'importe quel processus
|
`PR_SET_CHILD_SUBREAPER`, qui peut être définie pour n'importe quel processus
|
||||||
@ -101,7 +101,7 @@ l'extérieur du conteneur, les propriétés d'`init` sont biens appliquées à
|
|||||||
l'intérieur pour conserver un comportement cohérent.
|
l'intérieur pour conserver un comportement cohérent.
|
||||||
|
|
||||||
|
|
||||||
## Aller plus loin {-}
|
### Aller plus loin {-}
|
||||||
|
|
||||||
N'hésitez pas à jeter un œil à la page de manuel consacré à cet espace de
|
N'hésitez pas à jeter un œil à la page de manuel consacrée à cet espace de
|
||||||
noms : `pid_namespaces(7)`.
|
noms : `pid_namespaces(7)`.
|
||||||
|
@ -3,16 +3,19 @@
|
|||||||
Projet et rendu
|
Projet et rendu
|
||||||
===============
|
===============
|
||||||
|
|
||||||
Projet
|
Est attendu d'ici le TP suivant :
|
||||||
------
|
|
||||||
|
|
||||||
[Le sujet complet du projet est disponible ici](https://virli.nemunai.re/project-3.pdf). Il
|
- le rendu des exercice de ce TP ;
|
||||||
n'est pas à rendre en même temps que le TP. Consultez ses modalités de rendu
|
- vos réponses à [l'évaluation du cours](https://virli.nemunai.re/quiz/15).
|
||||||
pour plus d'informations.
|
|
||||||
|
|
||||||
|
Pour les GISTRE (et en bonus pour les SRS), [un
|
||||||
|
projet](https://virli.nemunai.re/project-2.pdf) est à rendre pour le 13
|
||||||
|
novembre. Consultez les modalités de rendu sur le sujet directement.
|
||||||
|
|
||||||
Modalités de rendu
|
## Modalités de rendu
|
||||||
------------------
|
|
||||||
|
En tant que personnes sensibilisées à la sécurité des échanges électroniques,
|
||||||
|
vous devrez m'envoyer vos rendus signés avec votre clef PGP.
|
||||||
|
|
||||||
Un service automatique s'occupe de réceptionner vos rendus, de faire des
|
Un service automatique s'occupe de réceptionner vos rendus, de faire des
|
||||||
vérifications élémentaires et de vous envoyer un accusé de réception (ou de
|
vérifications élémentaires et de vous envoyer un accusé de réception (ou de
|
||||||
@ -23,14 +26,11 @@ et exclusivement à celle-ci que vous devez envoyer vos rendus. Tout rendu
|
|||||||
envoyé à une autre adresse et/ou non signé et/ou reçu après la correction ne
|
envoyé à une autre adresse et/ou non signé et/ou reçu après la correction ne
|
||||||
sera pas pris en compte.
|
sera pas pris en compte.
|
||||||
|
|
||||||
Afin d'orienter correctement votre rendu, ajoutez une balise `[TP5]` au sujet
|
Afin d'orienter correctement votre rendu, ajoutez une balise `[TP4]` au sujet
|
||||||
de votre courriel. N'hésitez pas à indiquer dans le corps du courriel votre
|
de votre courriel. N'hésitez pas à indiquer dans le corps du message votre
|
||||||
ressenti et vos difficultés ou bien alors écrivez votre meilleure histoire
|
ressenti et vos difficultés ou bien alors écrivez votre meilleure histoire
|
||||||
drôle si vous n'avez rien à dire.
|
drôle si vous n'avez rien à dire.
|
||||||
|
|
||||||
Par ailleurs, n'oubliez pas de répondre à
|
|
||||||
[l'évaluation du cours](https://virli.nemunai.re/quiz/7).
|
|
||||||
|
|
||||||
|
|
||||||
Tarball
|
Tarball
|
||||||
-------
|
-------
|
||||||
@ -38,12 +38,14 @@ Tarball
|
|||||||
Tous les exercices de ce TP sont à placer dans une tarball (pas d'archive ZIP,
|
Tous les exercices de ce TP sont à placer dans une tarball (pas d'archive ZIP,
|
||||||
RAR, ...).
|
RAR, ...).
|
||||||
|
|
||||||
Voici une arborescence type :
|
Voici une arborescence type (adaptez les extensions et les éventuels
|
||||||
|
fichiers supplémentaires associés au langage que vous aurez choisi
|
||||||
|
pour chaque exercice) :
|
||||||
|
|
||||||
<div lang="en-US">
|
<div lang="en-US">
|
||||||
```
|
```
|
||||||
login_x-TP5/cmpns.sh
|
login_x-TP4/cmpns.sh
|
||||||
login_x-TP5/mydocker_exec.sh
|
login_x-TP4/mydocker_exec.sh
|
||||||
login_x-TP5/myswitch_root.sh
|
login_x-TP4/myswitch_root.sh
|
||||||
```
|
```
|
||||||
</div>
|
</div>
|
||||||
|
57
tutorial/4/setns-samples.md
Normal file
57
tutorial/4/setns-samples.md
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
#### Exemple C\
|
||||||
|
|
||||||
|
Voici un exemple de code C utilisant `setns(2)` :
|
||||||
|
|
||||||
|
<div lang="en-US">
|
||||||
|
```c
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sched.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
// ./a.out /proc/PID/ns/FILE cmd args...
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
int fd = open(argv[1], O_RDONLY);
|
||||||
|
if (fd == -1)
|
||||||
|
{
|
||||||
|
perror("open");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (setns(fd, 0) == -1)
|
||||||
|
{
|
||||||
|
perror("setns");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
execvp(argv[2], &argv[2]);
|
||||||
|
|
||||||
|
perror("execve");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
#### Exemple shell\
|
||||||
|
|
||||||
|
Dans un shell, on utilisera la commande `nsenter(1)` :
|
||||||
|
|
||||||
|
<div lang="en-US">
|
||||||
|
```bash
|
||||||
|
42sh# unshare --uts /bin/bash
|
||||||
|
inutsns# echo $$
|
||||||
|
42
|
||||||
|
inutsns# hostname jument
|
||||||
|
# Keep this sheel active to perform nexts steps, in another shell.
|
||||||
|
|
||||||
|
42sh# hostname
|
||||||
|
chaton
|
||||||
|
42sh# nsenter --uts=/proc/42/ns/uts /bin/bash
|
||||||
|
inutsns# hostname
|
||||||
|
jument
|
||||||
|
```
|
||||||
|
</div>
|
67
tutorial/4/setns.md
Normal file
67
tutorial/4/setns.md
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
\newpage
|
||||||
|
|
||||||
|
### Rejoindre un *namespace*
|
||||||
|
|
||||||
|
Rejoindre un espace de noms se fait en utilisant l'appel système `setns(2)`, ou
|
||||||
|
la commande `nsenter(1)`. Il est nécessaire de donner en argument
|
||||||
|
respectivement un *file descriptor* ou le chemin vers le fichier, lien
|
||||||
|
symbolique, représentant l'espace de nom.
|
||||||
|
|
||||||
|
|
||||||
|
#### Voir les *namespace*s d'un processus\
|
||||||
|
|
||||||
|
Chaque processus lancé est rattaché à une liste d'espaces de nom, y compris
|
||||||
|
s'il est issu du système de base (« l'hôte »).
|
||||||
|
|
||||||
|
Nous pouvons dès lors consulter le dossier `/proc/<PID>/ns/` de chaque
|
||||||
|
processus, pour consulter les différents espaces de nom de nos processus.
|
||||||
|
|
||||||
|
Tous les processus auront la même liste de fichiers, car ils sont liés à un
|
||||||
|
espace de noms par *namespace* utilisable avec le noyau. D'une machine à
|
||||||
|
l'autre, d'une version du noyau à l'autre, il est normal d'avoir une liste de
|
||||||
|
*namespace*s différents, mais d'un processus à l'autre sur le même noyau, nous
|
||||||
|
aurons les mêmes.
|
||||||
|
|
||||||
|
Ces fichiers sont en fait des liens symboliques un peu particuliers, car ils ne
|
||||||
|
pointent pas vers une destination valide :
|
||||||
|
|
||||||
|
<div lang="en-US">
|
||||||
|
```bash
|
||||||
|
42sh$ ls -l /proc/self/ns
|
||||||
|
lrwxrwxrwx 1 nemunaire 0 1 oct. 23:42 cgroup -> 'cgroup:[4026531835]'
|
||||||
|
lrwxrwxrwx 1 nemunaire 0 1 oct. 23:42 ipc -> 'ipc:[4026531839]'
|
||||||
|
lrwxrwxrwx 1 nemunaire 0 1 oct. 23:42 mnt -> 'mnt:[4026531840]'
|
||||||
|
lrwxrwxrwx 1 nemunaire 0 1 oct. 23:42 net -> 'net:[4026532008]'
|
||||||
|
lrwxrwxrwx 1 nemunaire 0 1 oct. 23:42 pid -> 'pid:[4026531836]'
|
||||||
|
lrwxrwxrwx 1 nemunaire 0 1 oct. 23:42 pid_for_children -> 'pid:[4026531836]'
|
||||||
|
lrwxrwxrwx 1 nemunaire 0 1 oct. 23:42 time -> 'time:[4026531834]'
|
||||||
|
lrwxrwxrwx 1 nemunaire 0 1 oct. 23:42 time_for_children -> 'time:[4026531834]'
|
||||||
|
lrwxrwxrwx 1 nemunaire 0 1 oct. 23:42 user -> 'user:[4026531837]'
|
||||||
|
lrwxrwxrwx 1 nemunaire 0 1 oct. 23:42 uts -> 'uts:[4026531838]'
|
||||||
|
|
||||||
|
```
|
||||||
|
</div>
|
||||||
|
|
||||||
|
Les liens référencent une structure du noyau résidant en mémoire. Les numéros
|
||||||
|
entre crochets seront les mêmes pour deux processus qui partagent le même
|
||||||
|
espace de noms. La structure pointée sera différente si l'espace de nom est
|
||||||
|
différent, donc le numéro sera différent.
|
||||||
|
|
||||||
|
On ne peut pas afficher tel quel les structures, mais on peut l'ouvrir avec
|
||||||
|
`open(2)` pour obtenir un *file descriptor* que l'on pourra passer à
|
||||||
|
`setns(2)`.
|
||||||
|
|
||||||
|
Pour les commandes *shell*, il convient de donner en argument le chemin vers le
|
||||||
|
lien symbolique : la commande se chargera d'`open(2)` le fichier.
|
||||||
|
|
||||||
|
|
||||||
|
#### `*_for_children`\
|
||||||
|
|
||||||
|
Vous avez peut-être remarqué des fichiers `*_for_children` dans le dossier `ns`
|
||||||
|
de vos processus. Nous verrons par la suite que les espaces de noms *PID* et
|
||||||
|
*Time*, une fois créés, ne s'appliquent pas directement au processus en cours
|
||||||
|
d'exécution, la dissociation de *namespace* ne peut se faire que pour les
|
||||||
|
processus/threads fils.
|
||||||
|
|
||||||
|
`pid_for_children` et `time_for_children` représentent donc les *namespace*s
|
||||||
|
qui seront attribués aux fils lancés après un `unshare(2)` réussi.
|
@ -1,14 +1,11 @@
|
|||||||
\newpage
|
### Prérequis
|
||||||
|
|
||||||
Mise en place
|
|
||||||
=============
|
|
||||||
|
|
||||||
Noyau Linux
|
#### Noyau Linux \
|
||||||
-----------
|
|
||||||
|
|
||||||
Ce TP requiert un noyau Linux, dans sa version 3.12 au minimum. Il doit de plus
|
Pour pouvoir suivre les exercices ci-après, vous devez disposez d'un noyau
|
||||||
être compilé avec les options suivantes (lorsqu'elles sont disponibles pour
|
Linux, idéalement dans sa version 5.6 ou mieux. Il doit de plus être compilé
|
||||||
votre version) :
|
avec les options suivantes (lorsqu'elles sont disponibles pour votre version) :
|
||||||
|
|
||||||
<div lang="en-US">
|
<div lang="en-US">
|
||||||
```
|
```
|
||||||
@ -16,6 +13,7 @@ General setup --->
|
|||||||
[*] Control Group support --->
|
[*] Control Group support --->
|
||||||
-*- Namespaces support
|
-*- Namespaces support
|
||||||
[*] UTS namespace
|
[*] UTS namespace
|
||||||
|
[*] TIME namespace
|
||||||
[*] IPC namespace
|
[*] IPC namespace
|
||||||
[*] User namespace
|
[*] User namespace
|
||||||
[*] PID Namespaces
|
[*] PID Namespaces
|
||||||
@ -38,6 +36,7 @@ CONFIG_CGROUPS=y
|
|||||||
|
|
||||||
CONFIG_NAMESPACES=y
|
CONFIG_NAMESPACES=y
|
||||||
CONFIG_UTS_NS=y
|
CONFIG_UTS_NS=y
|
||||||
|
CONFIG_TIME_NS=y
|
||||||
CONFIG_IPC_NS=y
|
CONFIG_IPC_NS=y
|
||||||
CONFIG_USER_NS=y
|
CONFIG_USER_NS=y
|
||||||
CONFIG_PID_NS=y
|
CONFIG_PID_NS=y
|
||||||
@ -52,11 +51,11 @@ CONFIG_VETH=m
|
|||||||
```
|
```
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
Référez-vous, si besoin, au TP précédent pour la marche à suivre.
|
Référez-vous, si besoin, à la précédente configuration que l'on a faite pour la
|
||||||
|
marche à suivre.
|
||||||
|
|
||||||
|
|
||||||
Paquets
|
#### Paquets \
|
||||||
-------
|
|
||||||
|
|
||||||
Nous allons utiliser des programmes issus des
|
Nous allons utiliser des programmes issus des
|
||||||
[`util-linux`](https://www.kernel.org/pub/linux/utils/util-linux/), de
|
[`util-linux`](https://www.kernel.org/pub/linux/utils/util-linux/), de
|
||||||
@ -69,12 +68,18 @@ Sous Debian et ses dérivés, ces paquets sont respectivement :
|
|||||||
* `procps`
|
* `procps`
|
||||||
* `libcap2-bin`
|
* `libcap2-bin`
|
||||||
|
|
||||||
|
Sous ArchLinux et ses dérivés, ces paquets sont respectivement :
|
||||||
|
|
||||||
À propos de la sécurité de l'espace de nom `user`
|
* `util-linux`
|
||||||
-------------------------------------------------
|
* `procps-ng`
|
||||||
|
* `libcap`
|
||||||
|
|
||||||
La sécurité du *namespace* `user` a souvent été remise en cause et on lui
|
|
||||||
attribue de nombreuses vulnérabilités. Je vous laisse consulter à ce sujet :
|
#### À propos de la sécurité de l'espace de noms `user` \
|
||||||
|
|
||||||
|
La sécurité du *namespace* `user` a souvent été remise en cause par le passé,
|
||||||
|
on lui attribue de nombreuses vulnérabilités. Vous devriez notamment consulter
|
||||||
|
à ce sujet :
|
||||||
|
|
||||||
* [Security Implications of User Namespaces](https://blog.araj.me/security-implications-of-user-namespaces/) ;
|
* [Security Implications of User Namespaces](https://blog.araj.me/security-implications-of-user-namespaces/) ;
|
||||||
* [Anatomy of a user namespaces vulnerability](https://lwn.net/Articles/543273/) ;
|
* [Anatomy of a user namespaces vulnerability](https://lwn.net/Articles/543273/) ;
|
||||||
@ -84,13 +89,14 @@ attribue de nombreuses vulnérabilités. Je vous laisse consulter à ce sujet :
|
|||||||
De nombreux projets ont choisi de ne pas autoriser l'utilisation de cet espace
|
De nombreux projets ont choisi de ne pas autoriser l'utilisation de cet espace
|
||||||
de noms sans disposer de certaines *capabilities*[^userns-caps].
|
de noms sans disposer de certaines *capabilities*[^userns-caps].
|
||||||
|
|
||||||
[^userns-caps]: Sont nécessaires, conjointement, `CAP_SYS_ADMIN`, `CAP_SETUID` et `CAP_SETGID`.
|
[^userns-caps]: Sont nécessaires, conjointement : `CAP_SYS_ADMIN`, `CAP_SETUID` et `CAP_SETGID`.
|
||||||
|
|
||||||
De nombreuses distributions ont par exemple choisi d'utiliser un paramètre du
|
De nombreuses distributions ont choisi d'utiliser un paramètre du noyau pour
|
||||||
noyau pour adapter le comportement.
|
adapter le comportement.
|
||||||
|
|
||||||
|
|
||||||
### Debian et ses dérivées {.unnumbered}
|
::::: {.question}
|
||||||
|
##### Debian et ses dérivées {.unnumbered}
|
||||||
|
|
||||||
Si vous utilisez Debian ou l'un de ses dérivés, vous devrez autoriser
|
Si vous utilisez Debian ou l'un de ses dérivés, vous devrez autoriser
|
||||||
explicitement cette utilisation non-privilégiée :
|
explicitement cette utilisation non-privilégiée :
|
||||||
@ -102,12 +108,13 @@ explicitement cette utilisation non-privilégiée :
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
### Grsecurity {.unnumbered}
|
##### Grsecurity {.unnumbered}
|
||||||
|
|
||||||
D'autres patchs, tels que
|
D'autres patchs, tels que
|
||||||
[*grsecurity*](https://forums.grsecurity.net/viewtopic.php?f=3&t=3929#p13904) ont
|
[*grsecurity*](https://forums.grsecurity.net/viewtopic.php?f=3&t=3929#p13904) ont
|
||||||
fait le choix de désactiver cette possibilité sans laisser d'option pour la
|
fait le choix de désactiver cette possibilité sans laisser d'option pour la
|
||||||
réactiver éventuellement à l'exécution. Pour avoir un comportement identique à
|
réactiver éventuellement à l'exécution. Pour avoir un comportement identique à
|
||||||
celui de Debian, vous pouvez
|
celui de Debian, vous pouvez
|
||||||
[appliquer ce patch](https://virli.nemunai.re/grsec-enable-user-ns.patch), sur
|
[appliquer ce patch](https://virli.nemunai.re/grsec-enable-user-ns.patch) sur
|
||||||
vos sources incluant le patch de *grsecurity*.
|
vos sources incluant le patch de *grsecurity*.
|
||||||
|
:::::
|
||||||
|
@ -13,7 +13,10 @@ abstract: |
|
|||||||
\vspace{1em}
|
\vspace{1em}
|
||||||
|
|
||||||
Tous les exercices de ce TP sont à rendre à <virli@nemunai.re> au
|
Tous les exercices de ce TP sont à rendre à <virli@nemunai.re> au
|
||||||
plus tard le jeudi 19 novembre 2020 à 12 h 42.
|
plus tard le mercredi 4 novembre 2021 à 23 h 42. Consultez la dernière
|
||||||
|
section de chaque partie pour plus d'informations sur les éléments à
|
||||||
|
rendre. Et n'oubliez pas de répondre aux [questions de
|
||||||
|
cours](https://virli.nemunai.re/quiz/13).
|
||||||
|
|
||||||
En tant que personnes sensibilisées à la sécurité des échanges électroniques,
|
En tant que personnes sensibilisées à la sécurité des échanges électroniques,
|
||||||
vous devrez m'envoyer vos rendus signés avec votre clef PGP. Pensez à
|
vous devrez m'envoyer vos rendus signés avec votre clef PGP. Pensez à
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
\newpage
|
\newpage
|
||||||
|
|
||||||
Le *namespace* `user` {#user-ns}
|
Le *namespace* `user` {#user-ns}
|
||||||
=====================
|
---------------------
|
||||||
|
|
||||||
## Introduction
|
### Introduction
|
||||||
|
|
||||||
L'espace de noms `user` est plutôt pratique car il permet de virtualiser la
|
L'espace de noms `user` est plutôt pratique car il permet de virtualiser la
|
||||||
liste et les droits des utilisateurs.
|
liste et les droits des utilisateurs.
|
||||||
@ -15,44 +15,44 @@ avoir besoin à l'intérieur de cet espace de noms, sans que cela ne réduise la
|
|||||||
sécurité des composants à l'extérieur de cet espace.
|
sécurité des composants à l'extérieur de cet espace.
|
||||||
|
|
||||||
|
|
||||||
## Comportement vis-à-vis des autres *namespaces*
|
### Comportement vis-à-vis des autres *namespaces*
|
||||||
|
|
||||||
Alors qu'il est normalement nécessaire d'avoir des privilèges pour créer de
|
Alors qu'il est normalement nécessaire d'avoir des privilèges pour créer de
|
||||||
nouveaux espaces de noms, en commençant par demander un *namespace*
|
nouveaux espaces de noms, en commençant par demander un *namespace*
|
||||||
utilisateurs, on obtient les privilèges requis pour créer tous les autres types
|
utilisateur, on obtient les privilèges requis pour créer tous les autres types
|
||||||
de *namespaces*.
|
de *namespaces*.
|
||||||
|
|
||||||
Grâce à cette technique, il est possible de lancer des conteneurs en tant que
|
Grâce à cette technique, il est possible de lancer des conteneurs en tant que
|
||||||
simple utilisateur ; le projet [Singularity](https://sylabs.io/) repose
|
simple utilisateur ; le projet [Singularity](https://sylabs.io/) repose
|
||||||
entièrement sur cela.
|
en grande partie sur cela.
|
||||||
|
|
||||||
|
|
||||||
## Correspondance des utilisateurs et des groupes
|
### Correspondance des utilisateurs et des groupes
|
||||||
|
|
||||||
Comme pour les autres espaces de noms, le *namespace* `user` permet de ne
|
Comme pour les autres espaces de noms, le *namespace* `user` permet de ne
|
||||||
garder dans le nouvel espace, que les utilisateurs et les groupes utiles au
|
garder dans le nouvel espace, que les utilisateurs et les groupes utiles au
|
||||||
processus, en les renumérotant au passage si besoin.
|
processus, en les renumérotant au passage si besoin.
|
||||||
|
|
||||||
|
|
||||||
### L'utilisateur -2 : *nobody*
|
#### L'utilisateur -2 : *nobody*\
|
||||||
|
|
||||||
Lorsque l'on arrive dans un nouvel espace, aucun utilisateur ni groupe n'est
|
Lorsque l'on arrive dans un nouvel espace, aucun utilisateur ni groupe n'est
|
||||||
défini. Dans cette situation, tous les identifiants d'utilisateur et de groupe,
|
défini. Dans cette situation, tous les identifiants d'utilisateur et de groupe,
|
||||||
renvoyés par le noyau sont à -2 ; valeur qui correspond par convention à
|
renvoyés par le noyau sont à -2 ; valeur qui correspond par convention à
|
||||||
l'utilisateur *nobody* et au groupe *nogroup*.
|
l'utilisateur *nobody* et au groupe *nogroup*.
|
||||||
|
|
||||||
-1 étant réservé pour indiqué une erreur dans le retour d'une commande, ou la
|
-1 étant réservé pour indiquer une erreur dans le retour d'une commande, ou la
|
||||||
non-modification d'un paramètres passé en argument d'une fonction.
|
non-modification d'un paramètre passé en argument d'une fonction.
|
||||||
|
|
||||||
|
|
||||||
### `uid_map` et `gid_map`
|
#### `uid_map` et `gid_map` \
|
||||||
|
|
||||||
#### `uid_map`
|
|
||||||
|
|
||||||
Pour établir la correspondance, une fois que l'on a créé le nouveau
|
Pour établir la correspondance, une fois que l'on a créé le nouveau
|
||||||
*namespace*, ces deux fichiers, accessibles dans `/proc/self/`, peuvent être
|
*namespace*, ces deux fichiers, accessibles dans `/proc/self/`, peuvent être
|
||||||
écrits une fois.
|
écrits une fois.
|
||||||
|
|
||||||
|
##### `uid_map`\
|
||||||
|
|
||||||
Sur chaque ligne, on doit indiquer :
|
Sur chaque ligne, on doit indiquer :
|
||||||
|
|
||||||
- L'identifiant marquant le début de la plage d'utilisateurs, pour le processus
|
- L'identifiant marquant le début de la plage d'utilisateurs, pour le processus
|
||||||
@ -72,8 +72,8 @@ Par exemple, le *namespace* `user` initial défini la correspondance suivante :
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
Cela signifie que les utilisateurs dont l'identifiant court de 0 à `MAX_INT -
|
Cela signifie que les utilisateurs dont l'identifiant court de 0 à `MAX_INT -
|
||||||
2` inclu, dans cet espace de noms, correspondent aux utilisateurs allant de 0 à
|
2` inclus, dans cet espace de noms, correspondent aux utilisateurs allant de 0 à
|
||||||
`MAX_INT - 1` inclu, pour le processus affichant ce fichier.
|
`MAX_INT - 1` inclus, pour le processus affichant ce fichier.
|
||||||
|
|
||||||
Lorsque l'on crée un *namespace* `user`, généralement, la correspondance vaut :
|
Lorsque l'on crée un *namespace* `user`, généralement, la correspondance vaut :
|
||||||
|
|
||||||
@ -89,13 +89,13 @@ l'utilisateur root, dans le conteneur équivaut à l'utilisateur 1000 hors de
|
|||||||
l'espace de noms.
|
l'espace de noms.
|
||||||
|
|
||||||
|
|
||||||
#### `gid_map`
|
##### `gid_map`\
|
||||||
|
|
||||||
Le principe est identique pour ce fichier, mais agit sur les correspondances
|
Le principe est identique pour ce fichier, mais agit sur les correspondances
|
||||||
des groupes au lieu des utilisateurs.
|
des groupes au lieu des utilisateurs.
|
||||||
|
|
||||||
|
|
||||||
## Utilisation de l'espace de noms
|
### Utilisation de l'espace de noms
|
||||||
|
|
||||||
<div lang="en-US">
|
<div lang="en-US">
|
||||||
```bash
|
```bash
|
||||||
@ -110,7 +110,7 @@ jeu. L'idée étant que l'on a été désigné root dans son conteneur, on devra
|
|||||||
pouvoir y faire ce que l'on veut, tant que l'on n'agit pas en dehors.
|
pouvoir y faire ce que l'on veut, tant que l'on n'agit pas en dehors.
|
||||||
|
|
||||||
|
|
||||||
## Aller plus loin {-}
|
### Aller plus loin {-}
|
||||||
|
|
||||||
N'hésitez pas à jeter un œil à la page du manuel consacré à ce *namespace* :
|
N'hésitez pas à jeter un œil à la page du manuel consacrée à ce *namespace* :
|
||||||
`user_namespaces(7)`.
|
`user_namespaces(7)`.
|
||||||
|
Loading…
Reference in New Issue
Block a user