tuto4: done
This commit is contained in:
parent
886197bfe8
commit
a476cd8b6d
@ -1,4 +1,6 @@
|
||||
SOURCES = tutorial.md mount.md namespaces.md networkns.md pidns.md mountns.md userns.md project-intro.md project-body.md project-rendu.md sondage.md
|
||||
SOURCES_TUTO = tutorial.md setup.md cmpns.md docker-exec.md mountns.md rendu.md
|
||||
SOURCES_LESSON = lesson.md mount.md namespaces.md networkns.md pidns.md userns.md
|
||||
|
||||
PANDOCOPTS = --latex-engine=xelatex \
|
||||
--standalone \
|
||||
--normalize \
|
||||
@ -13,10 +15,13 @@ PANDOCOPTS = --latex-engine=xelatex \
|
||||
--include-in-header=../header.tex
|
||||
|
||||
|
||||
all: tutorial.pdf
|
||||
all: lesson.pdf tutorial.pdf
|
||||
|
||||
tutorial.pdf: ${SOURCES}
|
||||
lesson.pdf: ${SOURCES_LESSON}
|
||||
pandoc ${PANDOCOPTS} -o $@ $+
|
||||
|
||||
tutorial.pdf: ${SOURCES_TUTO}
|
||||
pandoc ${PANDOCOPTS} -o $@ $+
|
||||
|
||||
clean::
|
||||
rm tutorial.pdf
|
||||
rm lesson.pdf tutorial.pdf
|
||||
|
60
tutorial/4/cmpns.md
Normal file
60
tutorial/4/cmpns.md
Normal file
@ -0,0 +1,60 @@
|
||||
\newpage
|
||||
|
||||
Comparaison de *namespace*
|
||||
==========================
|
||||
|
||||
Les *namespaces* d'un programme sont exposés sous forme de liens symboliques
|
||||
dans le répertoire `/proc/<PID>/ns/`.
|
||||
|
||||
Deux programmes qui partagent un même *namespace* auront un lien vers la même
|
||||
structure de données.
|
||||
|
||||
Écrivons un script ou un programme, `cmpns`, permettant de déterminer si deux
|
||||
programmes s'exécutent dans les mêmes *namespaces*.
|
||||
|
||||
|
||||
Exemples {.unnumbered}
|
||||
--------
|
||||
|
||||
<div lang="en-US">
|
||||
```sh
|
||||
42sh$ ./cmpns $(pgrep influxdb) $(pgrep init)
|
||||
- cgroup: differ
|
||||
- ipc: differ
|
||||
- mnt: differ
|
||||
- net: differ
|
||||
- pid: differ
|
||||
- user: same
|
||||
- uts: same
|
||||
```
|
||||
</div>
|
||||
|
||||
<div lang="en-US">
|
||||
```sh
|
||||
42sh$ ./cmpns $(pgrep init) self
|
||||
- cgroup: same
|
||||
- ipc: same
|
||||
- mnt: same
|
||||
- net: same
|
||||
- pid: same
|
||||
- user: same
|
||||
- uts: same
|
||||
```
|
||||
</div>
|
||||
|
||||
Ici, `self` fait référence au processus actuellement exécuté.
|
||||
|
||||
Et pourquoi pas :
|
||||
|
||||
<div lang="en-US">
|
||||
```sh
|
||||
42sh$ unshare -m ./cmpns $$ self
|
||||
- cgroup: same
|
||||
- ipc: same
|
||||
- mnt: differ
|
||||
- net: same
|
||||
- pid: same
|
||||
- user: same
|
||||
- uts: same
|
||||
```
|
||||
</div>
|
49
tutorial/4/docker-exec.md
Normal file
49
tutorial/4/docker-exec.md
Normal file
@ -0,0 +1,49 @@
|
||||
\newpage
|
||||
|
||||
`docker exec`
|
||||
=============
|
||||
|
||||
Après voir lu la partie concernant les *namespaces*, vous avez dû comprendre
|
||||
qu'un `docker exec`, n'était donc rien de plus qu'un `nsenter(1)`.
|
||||
|
||||
Réécrivons, en quelques lignes, la commande `docker exec` !
|
||||
|
||||
Pour savoir si vous avez réussi, comparez les sorties des commandes :
|
||||
|
||||
- `ip address` ;
|
||||
- `hostname` ;
|
||||
- `mount` ;
|
||||
- `pa -aux` ;
|
||||
- ...
|
||||
|
||||
|
||||
Tests {.unnumbered}
|
||||
-----
|
||||
|
||||
<div lang="en-US">
|
||||
```shell
|
||||
42sh$ docker run --name mywebserver -d -p 80:80 nginx
|
||||
d63ceae863956f8312aca60b7a57fbcc1fdf679ae4c90c5d9455405005d4980a
|
||||
42sh$ docker container inspect --format '{{ .State.Pid }}' mywebserver
|
||||
234269
|
||||
|
||||
42sh# ./mydocker_exec mywebserver ip address
|
||||
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
|
||||
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
|
||||
inet 127.0.0.1/8 scope host lo
|
||||
valid_lft forever preferred_lft forever
|
||||
13: eth0@if14: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
|
||||
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
|
||||
inet 172.17.0.1/16 scope global eth0
|
||||
valid_lft forever preferred_lft forever
|
||||
|
||||
42sh# hostname
|
||||
koala.zoo.paris
|
||||
42sh# ./mydocker_exec mywebserver hostname
|
||||
d63ceae86395
|
||||
|
||||
42sh# ./mydocker_exec mywebserver mount
|
||||
42sh# ./mydocker_exec mywebserver ps aux
|
||||
...
|
||||
```
|
||||
</div>
|
14
tutorial/4/lesson.md
Normal file
14
tutorial/4/lesson.md
Normal file
@ -0,0 +1,14 @@
|
||||
---
|
||||
title: Virtualisation légère -- Linux Internals partie 2
|
||||
subtitle: Support de cours
|
||||
author: Pierre-Olivier *nemunaire* Mercier
|
||||
institute: EPITA
|
||||
date: Jeudi 2 novembre 2017
|
||||
...
|
||||
|
||||
Le but de cette seconde partie sur les mécanismes internes du noyau va nous
|
||||
permettre d'utiliser les commandes et les appels systèmes relatifs aux espaces
|
||||
de noms du noyau Linux ainsi que d'appréhender la complexité des sytèmes de
|
||||
fichiers.
|
||||
|
||||
\tableofcontents
|
@ -1,6 +1,6 @@
|
||||
\newpage
|
||||
|
||||
Des particularités de `mount`
|
||||
Des particularités de `mount` {#mount}
|
||||
=============================
|
||||
|
||||
## Les points de montage
|
||||
@ -14,7 +14,7 @@ précédent.
|
||||
Mais avez-vous déjà essayé de monter la même partition d'un disque physique à
|
||||
deux endroits différents de votre arborescence ?
|
||||
|
||||
Si pour plein de raisons on pourrait 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
|
||||
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
|
||||
@ -22,26 +22,62 @@ 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
|
||||
arborescence.
|
||||
|
||||
Durant cette partie du TP, vous allez avoir besoin de la commande
|
||||
`findmnt(1)`. Commençons par la lancer maintenant pour se familiariser avec les
|
||||
différents points d'accroche actuellement montés.
|
||||
La commande `findmnt(1)`, des
|
||||
[`util-linux`](https://www.kernel.org/pub/linux/utils/util-linux/) nous permet
|
||||
d'avoir une vision arborescente des points de montage en cours d'utilisation.
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
TARGET SOURCE FSTYPE OPTIONS
|
||||
/ /dev/sda1 ext4 rw,relatime,data=ordered
|
||||
├─/proc proc proc rw,nosuid,nodev,noexec,relatime
|
||||
├─/sys sysfs sysfs rw,nosuid,nodev,noexec,relatime
|
||||
│ ├─/sys/kernel/security securityfs securityfs rw,nosuid,nodev,noexec,relatime
|
||||
│ ├─/sys/firmware/efi/efivars efivarfs efivarfs ro,relatime
|
||||
│ └─/sys/fs/cgroup cgroup_root tmpfs rw,nosuid,nodev,noexec,relatime,size=10240k,mode=755
|
||||
│ ├─/sys/fs/cgroup/unified none cgroup2 rw,nosuid,nodev,noexec,relatime
|
||||
│ ├─/sys/fs/cgroup/cpuset cpuset cgroup rw,nosuid,nodev,noexec,relatime,cpuset
|
||||
│ ├─/sys/fs/cgroup/cpu cpu cgroup rw,nosuid,nodev,noexec,relatime,cpu
|
||||
│ ├─/sys/fs/cgroup/cpuacct cpuacct cgroup rw,nosuid,nodev,noexec,relatime,cpuacct
|
||||
│ ├─/sys/fs/cgroup/blkio blkio cgroup rw,nosuid,nodev,noexec,relatime,blkio
|
||||
│ ├─/sys/fs/cgroup/memory memory cgroup rw,nosuid,nodev,noexec,relatime,memory
|
||||
│ ├─/sys/fs/cgroup/devices devices cgroup rw,nosuid,nodev,noexec,relatime,devices
|
||||
│ ├─/sys/fs/cgroup/freezer freezer cgroup rw,nosuid,nodev,noexec,relatime,freezer
|
||||
│ ├─/sys/fs/cgroup/net_cls net_cls cgroup rw,nosuid,nodev,noexec,relatime,net_cls
|
||||
│ ├─/sys/fs/cgroup/perf_event perf_event cgroup rw,nosuid,nodev,noexec,relatime,perf_event
|
||||
│ ├─/sys/fs/cgroup/net_prio net_prio cgroup rw,nosuid,nodev,noexec,relatime,net_prio
|
||||
│ └─/sys/fs/cgroup/pids pids cgroup rw,nosuid,nodev,noexec,relatime,pids
|
||||
├─/dev devtmpfs devtmpfs rw,nosuid,size=10240k,nr_inodes=486250,mode=755
|
||||
│ ├─/dev/pts devpts devpts rw,nosuid,noexec,relatime,gid=5,mode=620,ptmxmode=000
|
||||
│ ├─/dev/shm tmpfs tmpfs rw
|
||||
│ └─/dev/mqueue mqueue mqueue rw,nosuid,nodev,noexec,relatime
|
||||
├─/home /dev/sda3 ext4 rw,nosuid,nodev,relatime,data=ordered
|
||||
├─/run tmpfs tmpfs rw,nosuid,nodev,noexec,mode=755
|
||||
└─/tmp tmpfs tmpfs rw,nosuid,nodev,noexec,relatime
|
||||
```
|
||||
</div>
|
||||
|
||||
## `bind`
|
||||
|
||||
Lorsque l'on souhaite monter à un deuxième endroit (ou plus) une partition, on
|
||||
utilise le *bind mount* : `mount --bind olddir newdir`.
|
||||
utilise le *bind mount* :
|
||||
|
||||
Lorsque l'on utilise des `chroot`s sur un système complet (par exemple lorsqu'on
|
||||
l'installe ou qu'on le répare via un live CD), il est nécessaire de dupliquer
|
||||
les points de montage de `/dev`, `/proc` et `/sys`.
|
||||
<div lang="en-US">
|
||||
```
|
||||
mount --bind olddir newdir
|
||||
```
|
||||
</div>
|
||||
|
||||
Reprenons l'environnement que nous avons créé au précédent TP. Sans monter ces
|
||||
partitions, vous ne serez pas en mesure d'utiliser le système dans son
|
||||
intégralité : vous ne pourrez pas monter les partitions indiquées par le
|
||||
`/etc/fstab`, vous ne pourrez pas utiliser `top` ou `ps`, ...
|
||||
Lorsque l'on souhaite `chroot` dans un système complet (par exemple lorsqu'on
|
||||
l'installe ou qu'on le répare via un *live CD*), il est nécessaire de dupliquer
|
||||
certains points de montage, tels que `/dev`, `/proc` et `/sys`.
|
||||
|
||||
Pour que tout cela fonctionne, vous avez besoin au préalable d'exécuter les
|
||||
Sans monter ces partitions, vous ne serez pas en mesure d'utiliser le système
|
||||
dans son intégralité : vous ne pourrez pas monter les partitions indiquées par
|
||||
le `/etc/fstab`, vous ne pourrez pas utiliser `top` ou `ps`, `sysctl` ne pourra
|
||||
pas accorder les paramètres du noyau, ...
|
||||
|
||||
Pour que tout cela fonctionne, nous aurons besoin, au préalable, d'exécuter les
|
||||
commandes suivantes :
|
||||
|
||||
<div lang="en-US">
|
||||
@ -53,12 +89,12 @@ commandes suivantes :
|
||||
```
|
||||
</div>
|
||||
|
||||
En se `chroot`ant à nouveau dans cette nouvelle racine, nous voyons que tous
|
||||
nos outils fonctionnent comme prévu.
|
||||
En se `chroot`ant à nouveau dans cette nouvelle racine, tous nos outils
|
||||
fonctionneront comme prévu.
|
||||
|
||||
Tous ? ... en fait non. Si l'on jette un œil à `findmnt(1)`, nous constatons
|
||||
par exemple que `/sys/fs/cgroup` dans notre nouvelle racine est vide, alors que
|
||||
celui de notre machine hôte contient bien les répertoires de nos CGroups.
|
||||
celui de notre machine hôte contient bien les répertoires de nos *cgroups*.
|
||||
|
||||
`--bind` va se contenter d'attacher le système de fichiers (ou au moins une
|
||||
partie de celui-ci) à un autre endroit, sans se préoccuper des points de
|
||||
@ -79,31 +115,28 @@ correct de lancer :
|
||||
|
||||
## Les montages parfumés
|
||||
|
||||
On distingue 4 variétés de répercution des montages pour un sous-arbre :
|
||||
On distingue quatre variétés de répercution des montages pour un sous-arbre :
|
||||
partagé, esclave, privé et non-attachable.
|
||||
|
||||
Il s'agit d'agir sur la manière dont seront propagées les nouvelles accroches
|
||||
au sein d'un système de fichiers attaché à plusieurs endroit.
|
||||
Chacun va agir sur la manière dont seront propagées les nouvelles accroches au
|
||||
sein d'un système de fichiers attaché à plusieurs endroits.
|
||||
|
||||
|
||||
### partagé -- *shared mount*
|
||||
|
||||
Une nouvelle accroche sera propagée parmi tous les systèmes de fichiers de ce
|
||||
partage (on parle de *peer group*).
|
||||
|
||||
Essayons de voir à quoi cela correspond avec l'exemple suivant :
|
||||
Dans une montage partagé, une nouvelle accroche sera propagée parmi tous les
|
||||
systèmes de fichiers de ce partage (on parle de *peer group*).
|
||||
|
||||
<div lang="en-US">
|
||||
```shell
|
||||
# Création de nos répertoires de travail
|
||||
cd /mnt
|
||||
mkdir test-shared
|
||||
# Création de nos répertoires de travail
|
||||
mkdir /mnt/test-shared
|
||||
|
||||
# On s'assure que le dossier que l'on va utiliser pour nos tests utilise bien la politique shared
|
||||
mount --make-shared /tmp
|
||||
# On s'assure que le dossier que l'on va utiliser pour nos tests utilise bien la politique shared
|
||||
mount --make-shared /tmp
|
||||
|
||||
# Duplication de l'accroche, sans s'occuper des éventuels sous-accroches
|
||||
mount --bind /tmp /mnt/test-shared
|
||||
# Duplication de l'accroche, sans s'occuper des éventuels sous-accroches
|
||||
mount --bind /tmp /mnt/test-shared
|
||||
```
|
||||
</div>
|
||||
|
||||
@ -112,32 +145,31 @@ Si l'on attache un nouveau point de montage dans `/tmp` ou dans
|
||||
|
||||
<div lang="en-US">
|
||||
```shell
|
||||
mkdir /mnt/test-shared/toto
|
||||
mount -t tmpfs none /mnt/test-shared/toto
|
||||
mkdir /mnt/test-shared/toto
|
||||
mount -t tmpfs none /mnt/test-shared/toto
|
||||
```
|
||||
</div>
|
||||
|
||||
Un coup de `findmnt` nous montre l'existence de deux nouveaux points de
|
||||
montages. À `/mnt/test-shared/toto`, mais également à `/tmp/toto`.
|
||||
montage. À `/mnt/test-shared/toto`, mais également à `/tmp/toto`.
|
||||
|
||||
|
||||
### esclave -- *slave mount*
|
||||
|
||||
De la même manière que lorsque la propagation est partagée, cette politique
|
||||
propagera, mais seulement dans un sens. Le point de montage déclaré comme
|
||||
esclave ne propagera pas ses nouveaux points de montage.
|
||||
esclave ne propagera pas ses nouveaux points de montage à son *maître*.
|
||||
|
||||
<div lang="en-US">
|
||||
```shell
|
||||
# Suite de l'exemple précédent
|
||||
cd /mnt
|
||||
mkdir test-slave
|
||||
# Suite de l'exemple précédent
|
||||
cd /mnt/test-slave
|
||||
|
||||
# Duplication de l'accroche, sans s'occuper des éventuels sous-accroches
|
||||
mount --bind /mnt/test-shared /mnt/test-slave
|
||||
# Duplication de l'accroche, sans s'occuper des éventuels sous-accroches
|
||||
mount --bind /mnt/test-shared /mnt/test-slave
|
||||
|
||||
# On rend notre dossier esclave
|
||||
mount --make-slave /mnt/test-slave
|
||||
# On rend notre dossier esclave
|
||||
mount --make-slave /mnt/test-slave
|
||||
```
|
||||
</div>
|
||||
|
||||
@ -145,8 +177,8 @@ Si l'on effectue un montage dans `/mnt/test-shared` :
|
||||
|
||||
<div lang="en-US">
|
||||
```shell
|
||||
mkdir /mnt/test-shared/foo
|
||||
mount -t tmpfs none /mnt/test-shared/foo
|
||||
mkdir /mnt/test-shared/foo
|
||||
mount -t tmpfs none /mnt/test-shared/foo
|
||||
```
|
||||
</div>
|
||||
|
||||
@ -154,8 +186,8 @@ Le point de montage apparaît bien sous `/mnt/test-slave/foo`. Par contre :
|
||||
|
||||
<div lang="en-US">
|
||||
```shell
|
||||
mkdir /mnt/test-slave/bar
|
||||
mount -t tmpfs none /mnt/test-slave/bar
|
||||
mkdir /mnt/test-slave/bar
|
||||
mount -t tmpfs none /mnt/test-slave/bar
|
||||
```
|
||||
</div>
|
||||
|
||||
@ -164,14 +196,15 @@ Le nouveau point de montage n'est pas propagé dans `/mnt/test-shared/bar`.
|
||||
|
||||
### privé -- *private mount*
|
||||
|
||||
C'est le mode le plus simple : ici les points de montage ne sont pas propagés.
|
||||
C'est le mode le plus simple : ici les points de montage ne sont tout
|
||||
simplement pas propagés.
|
||||
|
||||
Pour forcer un point d'accroche a ne pas propager et à ne pas recevoir de
|
||||
Pour forcer un point d'accroche à ne pas propager et à ne pas recevoir de
|
||||
propagation, on utilise l'option suivante :
|
||||
|
||||
<div lang="en-US">
|
||||
```shell
|
||||
mount --make-private mountpoint
|
||||
mount --make-private mountpoint
|
||||
```
|
||||
</div>
|
||||
|
||||
@ -182,7 +215,7 @@ Ce mode interdira tout tentative d'attache à un autre endroit.
|
||||
|
||||
<div lang="en-US">
|
||||
```shell
|
||||
mount --make-unbindable /mnt/test-slave
|
||||
mount --make-unbindable /mnt/test-slave
|
||||
```
|
||||
</div>
|
||||
|
||||
@ -190,24 +223,24 @@ Il ne sera pas possible de faire :
|
||||
|
||||
<div lang="en-US">
|
||||
```shell
|
||||
mkdir /mnt/test-unbindable
|
||||
mount --bind /mnt/test-slave /mnt/test-unbindable
|
||||
mkdir /mnt/test-unbindable
|
||||
mount --bind /mnt/test-slave /mnt/test-unbindable
|
||||
```
|
||||
</div>
|
||||
|
||||
|
||||
### Parfums récursifs
|
||||
|
||||
Les options que nous venons de voir s'applique 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
|
||||
contenu dans le sous-arbre :
|
||||
contenus dans leur sous-arbre :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
mount --make-rshared mountpoint
|
||||
mount --make-rslave mountpoint
|
||||
mount --make-rprivate mountpoint
|
||||
mount --make-runbindable mountpoint
|
||||
mount --make-rshared mountpoint
|
||||
mount --make-rslave mountpoint
|
||||
mount --make-rprivate mountpoint
|
||||
mount --make-runbindable mountpoint
|
||||
```
|
||||
</div>
|
||||
|
||||
@ -215,9 +248,10 @@ mount --make-runbindable mountpoint
|
||||
## `bind` de dossiers et de fichiers
|
||||
|
||||
Il n'est pas nécessaire que le point d'accroche que l'on cherche à dupliquer
|
||||
pointe sur un point de montage. Il peut parfaitement pointer sur un dossier, et
|
||||
même sur un simple fichier, à la manière d'un *hardlink*, mais que l'on
|
||||
pourrait faire entre plusieurs partition et qui ne persisterait pas au
|
||||
pointe sur un point de montage (c'est-à-dire, dans la plupart des cas : une
|
||||
partition ou un système de fichiers virtuel). Il peut parfaitement pointer sur
|
||||
un dossier, et même sur un simple fichier, à la manière d'un *hardlink*, mais
|
||||
que l'on pourrait faire entre plusieurs partitions et qui ne persisterait pas au
|
||||
redémarrage.
|
||||
|
||||
Nous verrons dans la partie *namespace* réseau, une utilisation d'attache sur
|
||||
@ -226,17 +260,17 @@ un fichier.
|
||||
|
||||
## Déplacer un point de montage
|
||||
|
||||
À tout moment, il est possible réorganiser les points de montage, en les
|
||||
À tout moment, il est possible de réorganiser les points de montage, en les
|
||||
déplaçant. Comme cela se fait sans démonter de partition, il est possible de le
|
||||
faire même si un fichier est en cours d'utilisation. Il faut cependant veiller
|
||||
à ce que les programmes suceptibles d'aller chercher un fichier à l'ancien
|
||||
emplacement soit prévenu du changement.
|
||||
à ce que les programmes susceptibles d'aller chercher un fichier à l'ancien
|
||||
emplacement soient prévenu du changement.
|
||||
|
||||
On utilise pour cela l'option `--move` de `mount(8)` :
|
||||
|
||||
<div lang="en-US">
|
||||
```shell
|
||||
mount --move olddir newdir
|
||||
mount --move olddir newdir
|
||||
```
|
||||
</div>
|
||||
|
||||
@ -244,18 +278,19 @@ Par exemple :
|
||||
|
||||
<div lang="en-US">
|
||||
```shell
|
||||
mount --move /dev /newroot/dev
|
||||
mount --move /dev /newroot/dev
|
||||
```
|
||||
</div>
|
||||
|
||||
Il est courant de faire appel à cette option lorsque l'on souhaite changer la
|
||||
racine de notre système de fichier : passer de l'initramfs au système au
|
||||
booter, de notre système hôte au système d'un conteneur, ...
|
||||
racine de notre système de fichiers: par exemple pour passer de l'*initramfs* au
|
||||
système démarré, de notre système hôte au système d'un conteneur, ...
|
||||
|
||||
|
||||
## Aller plus loin
|
||||
|
||||
Voici quelques articles qui valent de détour :
|
||||
Voici quelques articles qui valent le détour, en lien avec les points de
|
||||
montage :
|
||||
|
||||
* [Shared subtree](https://lwn.net/Articles/159077) et la
|
||||
[documentation du noyau associée](https://kernel.org/doc/Documentation/filesystems/sharedsubtree.txt) ;
|
||||
|
@ -3,10 +3,8 @@
|
||||
Le *namespace* `mount`
|
||||
======================
|
||||
|
||||
## Introduction
|
||||
|
||||
Le *namespace* `mount`, comme nous l'avons vu au chapitre précédent, permet
|
||||
d'isoler la vision du système de fichiers qu'à un processus et ses fils.
|
||||
L'espace de noms `mount` permet d'isoler la vision du système de fichiers
|
||||
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 ?
|
||||
|
||||
@ -42,8 +40,8 @@ Si vous n'avez pas de partition à disposition, vous pouvez utiliser un `tmpfs`
|
||||
|
||||
<div lang="en-US">
|
||||
```shell
|
||||
mkdir /mnt/newroot
|
||||
mount -t tmpfs none /mnt/newroot
|
||||
42sh# mkdir /mnt/newroot
|
||||
42sh# mount -t tmpfs none /mnt/newroot
|
||||
```
|
||||
</div>
|
||||
|
||||
@ -76,7 +74,7 @@ Isolons-nous :
|
||||
|
||||
<div lang="en-US">
|
||||
```shell
|
||||
unshare -p -m -f --mount-proc
|
||||
42sh# unshare -p -m -f --mount-proc
|
||||
```
|
||||
</div>
|
||||
|
||||
@ -92,7 +90,7 @@ comme esclave :
|
||||
|
||||
<div lang="en-US">
|
||||
```shell
|
||||
mount --make-rslave /
|
||||
42sh# mount --make-rslave /
|
||||
```
|
||||
</div>
|
||||
|
||||
@ -119,12 +117,13 @@ la première commande (*init*) de votre choix.
|
||||
#### `pivot_root`
|
||||
|
||||
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ées
|
||||
`pivot_root(2)`, requiert de notre part que nous ayons préalablement déplacé
|
||||
les partitions systèmes à leur place dans la nouvelle racine.
|
||||
|
||||
L'appel de la commande, qui prend en argument le chemin de la nouvelle racine
|
||||
et le chemin dans la nouvelle racine où placer l'ancienne, va donc intervertir
|
||||
les deux racines.
|
||||
L'appel de la commande sert à intervertir les deux racines ; elle prend en argument :
|
||||
|
||||
* le chemin de la nouvelle racine,
|
||||
* le chemin dans la nouvelle racine où placer l'ancienne.
|
||||
|
||||
Une fois le pivot effectué, on peut démonter l'ancienne racine.
|
||||
|
||||
@ -133,6 +132,6 @@ par :
|
||||
|
||||
<div lang="en-US">
|
||||
```shell
|
||||
exec chroot / command
|
||||
42sh# exec chroot / command
|
||||
```
|
||||
</div>
|
||||
|
@ -1,53 +1,77 @@
|
||||
\newpage
|
||||
|
||||
Les *namespaces*
|
||||
================
|
||||
Les espaces de noms -- *namespaces* {#namespaces}
|
||||
===================================
|
||||
|
||||
## Introduction
|
||||
|
||||
Les espaces de noms du noyau, les *namespaces*, permettent de dupliquer
|
||||
certaines structures du noyau, dans le but de les isoler d'un groupe de
|
||||
processus à un autre.
|
||||
Les espaces de noms du noyau, les *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 7 depuis Linux 4.6 : `CGroup`, `IPC`, `network`, `mount`, `PID`,
|
||||
`user` et `UTS`.
|
||||
On en dénombre sept depuis Linux 4.6 : `cgroup`, `IPC`, `network`,
|
||||
`mount`, `PID`, `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](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/179825/).
|
||||
|
||||
### `mount` *namespaces*
|
||||
### L'espace de noms `mount` {#mount-ns}
|
||||
|
||||
Depuis Linux 2.4.19.
|
||||
|
||||
Isole la liste des points de montage.
|
||||
Cet espace de noms isole la liste des points de montage.
|
||||
|
||||
Chaque processus d'un *namespace* différent peut monter, démonter et
|
||||
réorganiser à sa guise les points de montage. Une partition ne sera donc pas
|
||||
nécessairement démonté après un appel à `umount(2)`, elle le sera lorsqu'elle
|
||||
Chaque processus appartenant à un *namespace* 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* 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.
|
||||
|
||||
### `UTS` *namespaces*
|
||||
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.
|
||||
|
||||
```shell
|
||||
mount --make-rslave /
|
||||
```
|
||||
|
||||
|
||||
### L'espace de noms `UTS` {#uts-ns}
|
||||
|
||||
Depuis Linux 2.6.19.
|
||||
|
||||
Isole le nom de machine et son domaine NIS.
|
||||
Cet espace de noms isole le nom de machine et son domaine NIS.
|
||||
|
||||
|
||||
### `IPC` *namespaces*
|
||||
### L'espace de noms `IPC` {#ipc-ns}
|
||||
|
||||
Depuis Linux 2.6.19.
|
||||
|
||||
Isole les objets IPC et les files de messages POSIX.
|
||||
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 *namespace*.
|
||||
qu'avec les autres processus de son espace de noms (lorsque ceux-ci passent par
|
||||
l'API IPC du noyau).
|
||||
|
||||
|
||||
### `PID` *namespaces*
|
||||
### L'espace de noms `PID`
|
||||
|
||||
Depuis Linux 2.6.24.
|
||||
|
||||
Isole la liste des processus et virtualise leurs numéros.
|
||||
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
|
||||
@ -55,22 +79,22 @@ 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é ; 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
|
||||
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.
|
||||
|
||||
|
||||
### `network` *namespaces*
|
||||
### L'espace de nom `network`
|
||||
|
||||
Depuis Linux 2.6.29.
|
||||
|
||||
Fourni une isolation pour toutes les ressources associées aux réseaux : les
|
||||
interfaces, les piles protocolaires IPv4 et IPv6, les tables de routage,
|
||||
pare-feu, ports numérotés, etc.
|
||||
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
|
||||
*namespace* à la fois, mais il est possible de les déplacer.
|
||||
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
|
||||
@ -78,30 +102,32 @@ ramenées dans l'espace initial (et non pas dans l'espace parent, en cas
|
||||
d'imbrication).
|
||||
|
||||
|
||||
### `user` *namespaces*
|
||||
### L'espace de noms `user`
|
||||
|
||||
Depuis Linux 3.8.
|
||||
|
||||
Isole la liste des utilisateurs, des groupes, leurs identifiants, les
|
||||
capabilities, la racine et le trousseau de clefs du noyau.
|
||||
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érent entre l'intérieur et
|
||||
l'extérieur du conteneur. Il est alors possible, alors que l'on est un simple
|
||||
utilisateur à l'extérieur du *namespace*, d'avoir l'UID 0 dans le conteneur.
|
||||
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.
|
||||
|
||||
|
||||
### `CGroup` *namespaces*
|
||||
### L'espace de noms `cgroup` {#cgroup-ns}
|
||||
|
||||
Depuis Linux 4.6.
|
||||
|
||||
Isole la vue de la racine des *Control Group* en la plaçant sur un
|
||||
sous-groupe de l'arborescence.
|
||||
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'arborescences des cgroups n'a alors
|
||||
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.
|
||||
|
||||
|
||||
@ -112,38 +138,34 @@ plus d'importance car le processus ne voit que son groupe.
|
||||
|
||||
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
|
||||
nécessaire pour appeler l'appel système `unshare(2)`, puis, tout comme
|
||||
nécessaire pour lancer l'appel système `unshare(2)`, puis, tout comme
|
||||
`chroot(1)`, exécuter le programme passé en paramètre.
|
||||
|
||||
En fonction des options qui lui sont passées, `unshare(1)` va créer le/les
|
||||
nouveaux *namespaces* et placer le processus dedans.
|
||||
|
||||
Par exemple, nous pouvons modifier sans crainte le nom de notre machine, si
|
||||
nous sommes passé dans un autre *namespace* `UTS` :
|
||||
nous sommes passés dans un autre *namespace* `UTS` :
|
||||
|
||||
<div lang="en-US">
|
||||
```shell
|
||||
42sh# hostname --fqdn
|
||||
koala.zoo.paris
|
||||
42sh# sudo unshare -u /bin/bash
|
||||
bash# hostname --fqdn
|
||||
koala.zoo.paris
|
||||
bash# hostname lynx.zoo.paris
|
||||
bash# hostname --fqdn
|
||||
lynx.zoo.paris
|
||||
bash# exit
|
||||
42sh# hostname --fqdn
|
||||
koala.zoo.paris
|
||||
42sh# hostname --fqdn
|
||||
koala.zoo.paris
|
||||
42sh# sudo unshare -u /bin/bash
|
||||
bash# hostname --fqdn
|
||||
koala.zoo.paris
|
||||
bash# hostname lynx.zoo.paris
|
||||
bash# hostname --fqdn
|
||||
lynx.zoo.paris
|
||||
bash# exit
|
||||
42sh# hostname --fqdn
|
||||
koala.zoo.paris
|
||||
```
|
||||
</div>
|
||||
|
||||
Nous avons pu ici modifier le nom de machine, sans que cela n'affecte notre
|
||||
Nous avons pu ici modifier le nom de la machine, sans que cela n'affecte notre
|
||||
machine hôte.
|
||||
|
||||
Essayons maintenant avec d'autres options de notre programme pour voir les
|
||||
effets produits : par exemple, comparons un `ip address` à l'extérieur et à
|
||||
l'intérieur d'un `unshare -n`.
|
||||
|
||||
|
||||
### Les appels systèmes
|
||||
|
||||
@ -166,8 +188,9 @@ avec d'autres `flags` attendu par la fonction.
|
||||
|
||||
Les mêmes `flags` sont utilisés lors des appels à `unshare(2)` ou `setns(2)`.
|
||||
|
||||
Pour créer un nouveau processus qui sera à la fois dans un nouvel *namespace*
|
||||
réseau et dans un nouveau *namespace* CGroup, on écrirait un code similaire à :
|
||||
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
|
||||
similaire à :
|
||||
|
||||
<div lang="en-US">
|
||||
```c
|
||||
@ -188,67 +211,10 @@ pid_t pid = clone(do_execvp,
|
||||
Le premier argument est un pointeur sur fonction. Il s'agit de la fonction qui
|
||||
sera appelée par le nouveau processus.
|
||||
|
||||
## Comparaison de *namespace*
|
||||
|
||||
Les *namespaces* d'un programme sont exposés sous forme de liens symboliques
|
||||
dans le répertoire `/proc/<PID>/ns/`.
|
||||
|
||||
Deux programmes qui partagent un même *namespace* auront un lien vers la même
|
||||
structure de données.
|
||||
|
||||
Écrivons un script ou un programme, `cmpns`, permettant de déterminer si deux
|
||||
programmes s'exécutent dans les mêmes *namespaces*.
|
||||
|
||||
|
||||
### Exemples
|
||||
|
||||
<div lang="en-US">
|
||||
```sh
|
||||
42sh$ ./cmpns $(pgrep influxdb) $(pgrep init)
|
||||
- cgroup: differ
|
||||
- ipc: differ
|
||||
- mnt: differ
|
||||
- net: differ
|
||||
- pid: differ
|
||||
- user: same
|
||||
- uts: same
|
||||
```
|
||||
</div>
|
||||
|
||||
<div lang="en-US">
|
||||
```sh
|
||||
42sh$ ./cmpns $(pgrep init) self
|
||||
- cgroup: same
|
||||
- ipc: same
|
||||
- mnt: same
|
||||
- net: same
|
||||
- pid: same
|
||||
- user: same
|
||||
- uts: same
|
||||
```
|
||||
</div>
|
||||
|
||||
Ici, `self` fait référence au processus actuellement exécuté.
|
||||
|
||||
Et pourquoi pas :
|
||||
|
||||
<div lang="en-US">
|
||||
```sh
|
||||
42sh$ unshare -m ./cmpns $$ self
|
||||
- cgroup: same
|
||||
- ipc: same
|
||||
- mnt: differ
|
||||
- net: same
|
||||
- pid: same
|
||||
- user: same
|
||||
- uts: same
|
||||
```
|
||||
</div>
|
||||
|
||||
|
||||
## Rejoindre un *namespace*
|
||||
|
||||
Rejoindre un *namespace* se fait en utilisant l'appel système `setns(2)`,
|
||||
Rejoindre un espace de noms se fait en utilisant l'appel système `setns(2)`,
|
||||
auquel on passe le *file descriptor* d'un des liens du dossier
|
||||
`/proc/<PID>/ns/` :
|
||||
|
||||
@ -293,31 +259,15 @@ Dans un shell, on utilisera la commande `nsenter(1)` :
|
||||
</div>
|
||||
|
||||
|
||||
### `docker exec`
|
||||
## Durée de vie d'un *namespace* {#ns-lifetime}
|
||||
|
||||
Si vous avez bien suivi jusque là, vous avez dû comprendre qu'un `docker exec`,
|
||||
n'était donc rien de plus qu'un `nsenter(1)`.
|
||||
|
||||
Réécrivons, en quelques lignes, la commande `docker exec` !
|
||||
|
||||
Pour savoir si vous avez réussi, comparez les sorties des commandes :
|
||||
|
||||
- `ip address` ;
|
||||
- `hostname` ;
|
||||
- `mount` ;
|
||||
- `pa -aux` ;
|
||||
- ...
|
||||
|
||||
|
||||
## Durée de vie d'un *namespace*
|
||||
|
||||
Le noyau tient à jour un compteur de référence pour chaque *namespace*. Dès
|
||||
qu'une référence tombe à 0, le *namespace* est automatiquement libéré, les
|
||||
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'utilisent. C'est-à-dire que, la plupart du temps, le
|
||||
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.
|
||||
|
||||
@ -339,7 +289,8 @@ de fichier valide vers le *namespace* (pour passer à `setns(2)`).
|
||||
|
||||
### Faire persister un *namespace*
|
||||
|
||||
Il n'est pas possible de faire persister un namespace d'un reboot à l'autre.
|
||||
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.
|
||||
@ -349,12 +300,13 @@ structure du noyau, qui ne persistera pas au redémarrage.
|
||||
|
||||
Je vous recommande la lecture des *man* suivants :
|
||||
|
||||
* `namespaces(7)` : introduisant et énumérant les namespaces ;
|
||||
* `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
|
||||
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)](http://crosbymichael.com/creating-containers-part-1.html).
|
||||
[Cet article de Michael Crosby montrant l'utilisation de clone(2)](http://crosbymichael.com/creating-containers-part-1.html)
|
||||
est également des plus intéressants, pour ce qui concerne la programmation
|
||||
plus bas-niveau.
|
||||
|
@ -1,6 +1,6 @@
|
||||
\newpage
|
||||
|
||||
Le *namespace* `network`
|
||||
Le *namespace* `network` {#net-ns}
|
||||
========================
|
||||
|
||||
## Introduction
|
||||
@ -10,7 +10,7 @@ ce qui est en lien avec le réseau : les interfaces, les ports, les routes, les
|
||||
règles de filtrage, etc.
|
||||
|
||||
En entrant dans un nouvel espace de nom `network`, on se retrouve dans un
|
||||
environnement qui n'a plus que l'interface de loopback :
|
||||
environnement qui n'a plus qu'une interface de *loopback* :
|
||||
|
||||
<div lang="en-US">
|
||||
```shell
|
||||
@ -20,9 +20,13 @@ environnement qui n'a plus que l'interface de loopback :
|
||||
```
|
||||
</div>
|
||||
|
||||
Qui dit nouvelle pile réseau, dit également que les ports qui étaient assignés
|
||||
Bien que portant le même nom que l'interface de *loopback* de notre
|
||||
environnement principal, il s'agit bien de deux interfaces isolées l'une de
|
||||
l'autre.
|
||||
|
||||
Qui dit nouvelle pile réseau, dit également que les ports qui sont assignés
|
||||
dans l'espace principal, ne le sont plus dans le conteneur : il est donc
|
||||
possible de lancer un serveur web sans qu'il entre en conflit avec celui d'un
|
||||
possible de lancer un serveur web sans qu'il n'entre en conflit avec celui d'un
|
||||
autre espace de noms.
|
||||
|
||||
|
||||
@ -31,45 +35,51 @@ autre espace de noms.
|
||||
La suite d'outils `iproute2` propose une interface simplifiée pour utiliser le
|
||||
*namespace* `network` : `ip netns`.
|
||||
|
||||
Tout d'abord, nous allons créer un nouvel espace de nom :
|
||||
Nous pouvons tout d'abord créer un nouvel espace de nom :
|
||||
|
||||
<div lang="en-US">
|
||||
```shell
|
||||
42sh$ ip netns add virli
|
||||
42sh# ip netns add virli
|
||||
```
|
||||
</div>
|
||||
|
||||
La technique utilisée ici pour avoir des *namespaces* nommés est la même que
|
||||
celle que nous avons vu dans la première partie sur les *namespaces* : via un
|
||||
`mount --bind` dans le dossier `/var/run/netns/`. Cela permet de faire
|
||||
persister le namespace malgré le fait que plus aucun processus ne s'y exécute.
|
||||
celle que nous avons vue dans
|
||||
[la première partie sur les *namespaces*](#ns-lifetime) : via un `mount --bind`
|
||||
dans le dossier `/var/run/netns/`. Cela permet de faire persister le namespace
|
||||
malgré le fait que plus aucun processus ne s'y exécute.
|
||||
|
||||
Maintenant que notre *namespace* est créé, voyons s'il contient des interfaces :
|
||||
Maintenant que notre *namespace* est créé, nous pouvons regarder s'il contient
|
||||
des interfaces :
|
||||
|
||||
<div lang="en-US">
|
||||
```sh
|
||||
42sh$ ip netns exec virli ip link
|
||||
42sh# ip netns exec virli ip link
|
||||
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT group default qlen 1
|
||||
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
|
||||
```
|
||||
</div>
|
||||
|
||||
Cette commande ne devrait vous montrer que l'interface de *loopback*, car nous
|
||||
n'avons pour l'instant pas encore attaché la moindre interface.
|
||||
Cette commande ne nous montre que l'interface de *loopback*, car nous n'avons
|
||||
pour l'instant pas encore attaché la moindre interface.
|
||||
|
||||
D'ailleurs, cette interface est rapportée comme étant désactivée, activons-là
|
||||
via la commande :
|
||||
|
||||
<div lang="en-US">
|
||||
```shell
|
||||
42sh$ ip netns exec virli ip link set dev lo up
|
||||
42sh# ip netns exec virli ip link set dev lo up
|
||||
```
|
||||
</div>
|
||||
|
||||
Si tout se passe bien, vous devriez maintenant pouvoir lancer un `ping` sur
|
||||
cette interface :
|
||||
À ce stade, nous pouvons déjà commencer à lancer un `ping` sur cette interface:
|
||||
|
||||
<div lang="en-US">
|
||||
```shell
|
||||
42sh$ ip netns exec virli ping 127.0.0.1
|
||||
42sh# ip netns exec virli ping 127.0.0.1
|
||||
PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
|
||||
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.038 ms
|
||||
...
|
||||
```
|
||||
</div>
|
||||
|
||||
@ -86,108 +96,135 @@ type `veth` :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
ip link add veth0 type veth peer name veth1
|
||||
42sh# ip link add veth0 type veth peer name veth1
|
||||
```
|
||||
</div>
|
||||
|
||||
Une interface `veth` se comporte comme un tube bidirectionnel : tout ce qui
|
||||
entre d'un côté sort de l'autre et inversement. La commande précédente a donc
|
||||
créé deux interfaces `veth0` et `veth1` : les paquets envoyés sur `veth0` sont
|
||||
donc reçu 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
|
||||
l'on place l'une des deux extrêmité dans une autre *namespace* `network`, il
|
||||
devient alors possible de réaliser un échange de paquet entre les deux.
|
||||
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.
|
||||
|
||||
Pour déplacer `veth1` dans notre *namespace* `virli` :
|
||||
|
||||
<div lang="en-US">
|
||||
```shell
|
||||
42sh# ip link set veth1 netns virli
|
||||
42sh# ip link set veth1 netns virli
|
||||
```
|
||||
</div>
|
||||
|
||||
Il ne reste plus maintenant qu'à assigner une IP à chacune des interfaces :
|
||||
Il ne reste maintenant plus qu'à assigner une IP à chacune des interfaces :
|
||||
|
||||
<div lang="en-US">
|
||||
```shell
|
||||
42sh# ip netns exec virli ip a add 10.10.10.42/24 dev veth1
|
||||
42sh# ip a add 10.10.10.41/24 dev veth0
|
||||
42sh# ip netns exec virli ip a add 10.10.10.42/24 dev veth1
|
||||
42sh# ip a add 10.10.10.41/24 dev veth0
|
||||
```
|
||||
</div>
|
||||
|
||||
Testons maintenant que la communication entre les deux passe bient :
|
||||
Dès lors[^linkdown], nous pouvons `ping`er chaque extrêmité :
|
||||
|
||||
[^linkdown]: Il peut être nécessaire d'activer chaque lien, via `ip link set
|
||||
vethX up`.
|
||||
|
||||
<div lang="en-US">
|
||||
```shell
|
||||
42sh# ping 10.10.10.42
|
||||
- et -
|
||||
42sh# ip netns exec virli ping 10.10.10.41
|
||||
42sh# ping 10.10.10.42
|
||||
- et -
|
||||
42sh# ip netns exec virli ping 10.10.10.41
|
||||
```
|
||||
</div>
|
||||
|
||||
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
|
||||
|
||||
Le bridge ou le NAT obligera tous les paquets à passer à travers de nombreuses
|
||||
couches du noyau. Utiliser les interface *veth* est plutôt simple et disponible
|
||||
couches du noyau. Utiliser les interfaces *veth* est plutôt simple et disponible
|
||||
partout, mais c'est loin d'être la technique la plus rapide ou la moins
|
||||
gourmande.
|
||||
|
||||
|
||||
### VLAN
|
||||
|
||||
Il est possible d'attribuer juste une interface de VLAN, si l'on a switch les
|
||||
supportant.
|
||||
Il est possible d'attribuer juste une interface de VLAN, si l'on a switch
|
||||
supportant la technologie [802.1q](https://fr.wikipedia.org/wiki/IEEE_802.1Q).
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
42sh# ip link add link eth0 name eth0.100 type vlan id 100
|
||||
42sh# ip link set dev eth0.100 up
|
||||
42sh# ip link set eth0.100 netns virli
|
||||
42sh# ip link add link eth0 name eth0.100 type vlan id 100
|
||||
42sh# ip link set dev eth0.100 up
|
||||
42sh# ip link set eth0.100 netns virli
|
||||
```
|
||||
</div>
|
||||
|
||||
|
||||
### MACVLAN
|
||||
|
||||
Lorsque l'on a pas assez de carte ethernet et que le switch ne supporte pas les
|
||||
VLAN, le noyau met à disposition un routage basé sur les adresses MAC : le
|
||||
<!-- https://hicu.be/bridge-vs-macvlan -->
|
||||
|
||||
Lorsque l'on n'a pas assez de carte ethernet et que le switch ne supporte pas
|
||||
les VLAN, le noyau met à disposition un routage basé sur les adresses MAC : le
|
||||
MACVLAN. S'il est activé dans votre noyau, vous allez avoir le choix entre l'un
|
||||
des deux modes : VEPA ou *bridge*.
|
||||
des quatre modes : *private*, VEPA, *bridge* ou *passthru*.
|
||||
|
||||
Quelque soit le mode choisi, les paquets en provenance d'autres machines et à
|
||||
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
|
||||
interfaces.
|
||||
|
||||
#### VEPA
|
||||
|
||||
Dans ce mode, tous les paquets sortant sont directement envoyé sur l'interface
|
||||
ethernet de sortie, sans qu'aucun routage préalable n'est été effectué. Ainsi,
|
||||
si un paquet est à destination d'un des autres conteneur de la machine, c'est à
|
||||
l'équipement réseau derrière la machine de rerouter le paquet vers la machine
|
||||
émetrice.
|
||||
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é
|
||||
effectué. Ainsi, si un paquet est à destination d'un des autres conteneurs de
|
||||
la machine, c'est à l'équipement réseau derrière la machine de rerouter le
|
||||
paquet vers la machine émettrice (par exemple un switch
|
||||
[802.1Qbg](http://www.ieee802.org/1/pages/802.1bg.html)).
|
||||
|
||||
Pour construire une nouvelle interface de ce type :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
ip link add link eth0 mac0 type macvlan mode vepa
|
||||
42sh# ip link add link eth0 mac0 type macvlan mode vepa
|
||||
```
|
||||
</div>
|
||||
|
||||
|
||||
#### *Private*
|
||||
|
||||
À 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
|
||||
pas délivré.
|
||||
|
||||
Dans ce mode, on est donc assuré qu'aucun conteneur ne puisse parler à un
|
||||
conteneur de la même machine.
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
42sh# ip link add link eth0 mac1 type macvlan mode private
|
||||
```
|
||||
</div>
|
||||
|
||||
|
||||
#### *Bridge*
|
||||
|
||||
À l'inverse du mode *VEPA*, les paquets sont routés selon leur adresse MAC : si
|
||||
jamais une adresse MAC est connuee, le paquet est délivré à l'interface MACVLAN
|
||||
correspondante ; dans le cas contraire, le paquet est envoyé sur l'interface de
|
||||
sortie.
|
||||
À 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é à
|
||||
l'interface MACVLAN correspondante ; dans le cas contraire, le paquet est
|
||||
envoyé sur l'interface de sortie.
|
||||
|
||||
Pour construire une nouvelle interface de ce type :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
ip link add link eth0 mac1 type macvlan mode bridge
|
||||
42sh# ip link add link eth0 mac2 type macvlan mode bridge
|
||||
```
|
||||
</div>
|
||||
|
||||
|
@ -1,21 +1,21 @@
|
||||
\newpage
|
||||
|
||||
Le *namespace* `PID`
|
||||
Le *namespace* `PID` {#pid-ns}
|
||||
=====================
|
||||
|
||||
## Introduction
|
||||
## Introduction {#pid-ns-intro}
|
||||
|
||||
Le *namespace* `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é
|
||||
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é
|
||||
comme l'`init`.
|
||||
|
||||
Contrairement aux autres *namespaces* où l'on peut demander à se séparer du
|
||||
*namespace* en question à n'importe quel moment de l'exécution du processus,
|
||||
via `unshare(2)` ou `setns(2)` par exemple, dans le cas du *namespace* PID, le
|
||||
changement n'est valable qu'après le prochain `fork(2)` (ou similaire). Le
|
||||
*namespace* PID du processus courant n'est pas changé, afin que le processus ne
|
||||
change pas de PID en cours de route (en fonction du *namespace* dans lequel il
|
||||
se trouve).
|
||||
via `unshare(2)` ou `setns(2)` par exemple, ici, le changement n'est valable
|
||||
qu'après le prochain `fork(2)` (ou similaire).
|
||||
L'espace de noms PID du processus courant n'est pas changé, afin que le
|
||||
processus ne change pas de PID en cours de route (puisque fonction du
|
||||
*namespace* dans lequel il se trouve).
|
||||
|
||||
|
||||
## Isolons !
|
||||
@ -24,12 +24,12 @@ Première étape s'isoler :
|
||||
|
||||
<div lang="en-US">
|
||||
```shell
|
||||
unshare --pid --fork /bin/bash
|
||||
42sh# unshare --pid --fork /bin/bash
|
||||
```
|
||||
</div>
|
||||
|
||||
Nous utilisons ici l'option `-f`, pour que le passage dans le nouvel espace de
|
||||
noms des PID soit effectif (cf. Introduction).
|
||||
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
|
||||
seul processus ... pourtant, il n'en est rien, ces deux commandes continuent
|
||||
@ -39,10 +39,10 @@ Cela est dû au fait que ces deux programmes, sous Linux, se basent sur le
|
||||
contenu de `/proc`. D'ailleurs, si l'on affiche le PID du processus courant
|
||||
`echo $$`, on obtient bien 1.
|
||||
|
||||
En l'état, beaucoup d'information fuitent. Mais il n'est pas possible de monter
|
||||
le bon `/proc` car il serait également monté pour les processus de notre
|
||||
système initial. Pour s'en sortir, il est nécessaire de s'isoler du *namespace*
|
||||
`mount`.
|
||||
En l'état, beaucoup d'informations sont divulguées. Mais il n'est pas possible
|
||||
de monter le bon `/proc` car il serait également monté pour les processus de
|
||||
notre système initial. Pour s'en sortir, il est nécessaire de s'isoler du
|
||||
*namespace* `mount`.
|
||||
|
||||
|
||||
### Double isolation : ajout du *namespace* `mount`
|
||||
@ -51,7 +51,7 @@ Voici la nouvelle ligne de commande que l'on va utiliser :
|
||||
|
||||
<div lang="en-US">
|
||||
```shell
|
||||
unshare --pid --mount --fork --mount-proc /bin/bash
|
||||
42sh# unshare --pid --mount --fork --mount-proc /bin/bash
|
||||
```
|
||||
</div>
|
||||
|
||||
@ -64,16 +64,15 @@ Cette fois, `top` et `ps` nous rapportent bien que l'on est seul dans notre
|
||||
|
||||
## Arborescence à l'extérieur du *namespace*
|
||||
|
||||
Vous l'avez sans doute remarqué lors de votre première tentative de `top`,
|
||||
lorsque le `/proc` était encore monté sur le procfs de l'espace initial : votre
|
||||
processus au PID 1 dans son nouveau *namespace* était présent dans
|
||||
l'arborescence de l'espace initial avec un PID dans la continuité des autres
|
||||
processus, étonnant !
|
||||
Lors de notre première tentative de `top`, lorsque `/proc` était encore monté
|
||||
sur le `procfs` de l'espace de noms initial : votre processus (au PID 1 dans
|
||||
son nouveau *namespace*) était présent dans l'arborescence de l'espace initial
|
||||
avec un PID dans la continuité des autres processus, étonnant !
|
||||
|
||||
En fait, l'isolation consiste en une virtualisation des numéros du processus :
|
||||
la plupart des processus du système intial ne sont pas accessibles, et ceux qui
|
||||
font parti de l'espace de noms créé disposent d'une nouvelle numérotation. Et
|
||||
c'est cette nouvelle numérotation qui est montré au processus.
|
||||
font partie de l'espace de noms créé disposent d'une nouvelle numérotation. Et
|
||||
c'est cette nouvelle numérotation qui est montrée au processus.
|
||||
|
||||
Si l'on veut interagir avec ce processus depuis un de ses espaces de noms
|
||||
parent, il faut le faire avec son identifiant de processus du même *namespace*
|
||||
@ -89,13 +88,13 @@ Si un processus est orphelin, il est donc affiché comme étant fils du PID 1
|
||||
dans son *namespace* ; il n'est pas sorti de l'espace de nom.
|
||||
|
||||
Lorsque l'on lance un processus via `nsenter(1)` ou `setns(2)`, cela crée un
|
||||
processus qui n'est sans doute pas un fils direct du processus d'init de notre
|
||||
conteneur. Malgré tout, même s'il est affiché comme n'étant pas un fils à
|
||||
l'extérieur du conteneur, les propriétés d'init sont biens appliquées à
|
||||
processus qui n'est sans doute pas un fils direct du processus d'`init` de
|
||||
notre conteneur. Malgré tout, même s'il est affiché comme n'étant pas un fils à
|
||||
l'extérieur du conteneur, les propriétés d'`init` sont biens appliquées à
|
||||
l'intérieur pour conserver un comportement cohérent.
|
||||
|
||||
|
||||
## Aller plus loin
|
||||
|
||||
N'hésitez pas à jeter un œil à la page de manuel consacré à ce *namespace* :
|
||||
`pid_namespaces(7)`.
|
||||
N'hésitez pas à jeter un œil à la page de manuel consacré à cet espace de
|
||||
noms : `pid_namespaces(7)`.
|
||||
|
@ -1,16 +1,21 @@
|
||||
## Modalité 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 les
|
||||
vérifications nécessaires et de vous envoyer un accusé de réception (ou de
|
||||
rejet).
|
||||
|
||||
Ce service écoute sur l'adresse <virli@nemunai.re>, c'est donc à cette adresse
|
||||
Ce service écoute sur l'adresse <virli@nemunai.re>. C'est donc à cette adresse
|
||||
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
|
||||
sera pas pris en compte.
|
||||
|
||||
|
||||
## Tarball
|
||||
Tarball
|
||||
-------
|
||||
|
||||
Le projet à rendre pour ce cours est à placer dans une tarball (pas d'archive
|
||||
ZIP, RAR, ...).
|
||||
|
47
tutorial/4/rendu.md
Normal file
47
tutorial/4/rendu.md
Normal file
@ -0,0 +1,47 @@
|
||||
\newpage
|
||||
|
||||
Projet et rendu
|
||||
===============
|
||||
|
||||
Projet
|
||||
------
|
||||
|
||||
[Le sujet complet du projet est disponible ici](https://virli.nemunai.re/project-2.pdf). Il
|
||||
n'est pas à rendre en même temps que le TP. Consultez ses modalités de rendu
|
||||
pour plus d'informations.
|
||||
|
||||
|
||||
Modalités de rendu
|
||||
------------------
|
||||
|
||||
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
|
||||
rejet).
|
||||
|
||||
Ce service écoute sur l'adresse <virli@nemunai.re>. C'est donc à cette adresse
|
||||
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
|
||||
sera pas pris en compte.
|
||||
|
||||
Par ailleurs, n'oubliez pas de répondre à
|
||||
[l'évaluation du cours](https://www.epitaf.fr/moodle/mod/quiz/view.php?id=42).
|
||||
|
||||
Afin de m'aider à améliorer ce cours, je vous invite à remplir
|
||||
[ce sondage anonyme](https://www.epitaf.fr/moodle/mod/quiz/view.php?id=44).
|
||||
|
||||
|
||||
Tarball
|
||||
-------
|
||||
|
||||
Tous les exercices de ce TP sont à placer dans une tarball (pas d'archive ZIP,
|
||||
RAR, ...).
|
||||
|
||||
Voici une arborescence type :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
login_x-TP4/cmpns.sh
|
||||
login_x-TP4/mydocker_exec.sh
|
||||
login_x-TP4/myswitch_root.sh
|
||||
```
|
||||
</div>
|
110
tutorial/4/setup.md
Normal file
110
tutorial/4/setup.md
Normal file
@ -0,0 +1,110 @@
|
||||
\newpage
|
||||
|
||||
Mise en place
|
||||
=============
|
||||
|
||||
Noyau Linux
|
||||
-----------
|
||||
|
||||
Ce TP requiert un noyau Linux, dans sa version 3.12 au minimum. Il doit de plus
|
||||
être compilé avec les options suivantes (lorsqu'elles sont disponibles pour
|
||||
votre version) :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
General setup --->
|
||||
[*] Control Group support --->
|
||||
-*- Namespaces support
|
||||
[*] UTS namespace
|
||||
[*] IPC namespace
|
||||
[*] User namespace
|
||||
[*] PID Namespaces
|
||||
[*] Network namespace
|
||||
[*] Networking support --->
|
||||
Networking options --->
|
||||
<M> 802.1d Ethernet Bridging
|
||||
Device Drivers --->
|
||||
[*] Network device support --->
|
||||
<M> MAC-VLAN support
|
||||
<M> Virtual ethernet pair device
|
||||
```
|
||||
</div>
|
||||
|
||||
Les variables de configuration correspondantes sont :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
CONFIG_CGROUPS=y
|
||||
|
||||
CONFIG_NAMESPACES=y
|
||||
CONFIG_UTS_NS=y
|
||||
CONFIG_IPC_NS=y
|
||||
CONFIG_USER_NS=y
|
||||
CONFIG_PID_NS=y
|
||||
CONFIG_NET_NS=y
|
||||
|
||||
CONFIG_NET=y
|
||||
CONFIG_BRIDGE=m
|
||||
|
||||
CONFIG_NETDEVICES=y
|
||||
CONFIG_MACVLAN=m
|
||||
CONFIG_VETH=m
|
||||
```
|
||||
</div>
|
||||
|
||||
Référez-vous, si besoin, au TP précédent pour la marche à suivre.
|
||||
|
||||
|
||||
Paquets
|
||||
-------
|
||||
|
||||
Nous allons utiliser des programmes issus des
|
||||
[`util-linux`](https://www.kernel.org/pub/linux/utils/util-linux/), de
|
||||
[`procps-ng`](https://gitlab.com/procps-ng/procps) ainsi que ceux de la
|
||||
[`libcap`](http://www.friedhoff.org/posixfilecaps.html).
|
||||
|
||||
Sous Debian et ses dérivés, ses paquets sont respectivement :
|
||||
|
||||
* `util-linux`
|
||||
* `procps`
|
||||
* `libcap2-bin`
|
||||
|
||||
|
||||
À propos de la sécurité de l'espace de nom `user`
|
||||
-------------------------------------------------
|
||||
|
||||
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 :
|
||||
|
||||
* [Anatomy of a user namespaces vulnerability](https://lwn.net/Articles/543273/) ;
|
||||
* <http://marc.info/?l=linux-kernel&m=135543612731939&w=2> ;
|
||||
* <http://marc.info/?l=linux-kernel&m=135545831607095&w=2>.
|
||||
|
||||
De nombreux projets ont choisi de ne pas autoriser l'utilisation de cet espace
|
||||
de noms sans disposer de certaines *capabilities*[^userns-caps].
|
||||
|
||||
[^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
|
||||
noyau pour adapter le comportement.
|
||||
|
||||
|
||||
### Debian et ses dérivées {.unnumbered}
|
||||
|
||||
Si vous utilisez Debian ou l'un de ses dérivés, vous devrez autoriser
|
||||
explicitement cette utilisation non-privilégiée :
|
||||
|
||||
```shell
|
||||
42sh# sysctl -w kernel.unprivileged_userns_clone=1
|
||||
```
|
||||
|
||||
|
||||
### Grsecurity {.unnumbered}
|
||||
|
||||
D'autres patchs, tels que
|
||||
[*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
|
||||
réactiver éventuellement à l'exécution. Pour avoir un comportement identique à
|
||||
celui de Debian, vous pouvez
|
||||
[appliquer ce patch](https://virli.nemunai.re/grsec-enable-user-ns.patch), sur
|
||||
vos sources incluant le patch de *grsecurity*.
|
@ -1,25 +1,23 @@
|
||||
---
|
||||
title: Virtualisation légère -- TP n^o^ 4
|
||||
subtitle: Linux Internals partie 2
|
||||
author: Pierre-Olivier *Nemunaire* Mercier
|
||||
author: Pierre-Olivier *nemunaire* Mercier
|
||||
institute: EPITA
|
||||
date: Jeudi 20 octobre 2016
|
||||
date: Jeudi 2 novembre 2017
|
||||
...
|
||||
|
||||
Le but de ce second TP sur les mécanismes internes du noyau va nous permettre
|
||||
d'utiliser les commandes et les appels systèmes relatifs aux *namespaces* ainsi
|
||||
que d'appréhender la complexité des sytèmes de fichiers.
|
||||
que d'appréhender la complexité des systèmes de fichiers.
|
||||
|
||||
Le projet du cours est à rendre à <virli@nemunai.re> au plus tard le dimanche
|
||||
20 novembre 2016 à 23 h 42.
|
||||
Tous les exercices de ce TP sont à rendre à <virli@nemunai.re> au plus tard le
|
||||
jeudi 9 novembre 2017 à 8 h 42.
|
||||
|
||||
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 à
|
||||
[me](https://pgp.mit.edu/pks/lookup?op=vindex&search=0x842807A84573CC96) faire
|
||||
signer votre clef et n'hésitez pas à
|
||||
[faire signer votre clef](https://www.meetup.com/fr/Paris-certification-de-cles-PGP-et-CAcert/).
|
||||
Vous pouvez utiliser l'adresse <signcheck@nemunai.re> pour savoir si vous vous
|
||||
y prenez correctement.
|
||||
|
||||
\hypersetup{linkcolor=black}
|
||||
\tableofcontents
|
||||
|
@ -1,11 +1,11 @@
|
||||
\newpage
|
||||
|
||||
Le *namespace* `user`
|
||||
Le *namespace* `user` {#user-ns}
|
||||
=====================
|
||||
|
||||
## Introduction
|
||||
|
||||
Le *namespace* `user` est plutôt pratiquxe 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.
|
||||
|
||||
Par exemple, on va pouvoir entrer dans un conteneur en tant que
|
||||
@ -31,14 +31,14 @@ repose entièrement sur cela.
|
||||
|
||||
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
|
||||
processus, en les renumérotant si besoin au passage.
|
||||
processus, en les renumérotant au passage si besoin.
|
||||
|
||||
|
||||
### l'utilisateur -1 : *nobody*
|
||||
### L'utilisateur -1 : *nobody*
|
||||
|
||||
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,
|
||||
renvoyés par le noyau est -1 ; valeur qui correspond en toute circonstance à
|
||||
renvoyés par le noyau sont à -1 ; valeur qui correspond en toute circonstance à
|
||||
l'utilisateur *nobody* et au groupe *nogroup*.
|
||||
|
||||
|
||||
@ -48,7 +48,7 @@ l'utilisateur *nobody* et au groupe *nogroup*.
|
||||
|
||||
Pour établir la correspondance, une fois que l'on a créé le nouveau
|
||||
*namespace*, ces deux fichiers, accessibles dans `/proc/self/`, peuvent être
|
||||
écrit une fois.
|
||||
écrits une fois.
|
||||
|
||||
Sur chaque ligne, on doit indiquer :
|
||||
|
||||
@ -59,23 +59,25 @@ Sur chaque ligne, on doit indiquer :
|
||||
- La taille de la page.
|
||||
|
||||
|
||||
Par exemple, le *namespace* `user` initial défini le correspondance suivante :
|
||||
Par exemple, le *namespace* `user` initial défini la correspondance suivante :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
0 0 4294967295
|
||||
42sh$ cat /proc/self/uid_map
|
||||
0 0 4294967295
|
||||
```
|
||||
</div>
|
||||
|
||||
Cela signifie que les utilisateurs dont l'identifiant court de 0 à -2 inclu,
|
||||
dans cet espace de noms, correspond aux utilisateurs allant de 0 à -1 inclu,
|
||||
pour le processus affichant ce fichier.
|
||||
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 à
|
||||
`MAX_INT - 1` inclu, pour le processus affichant ce fichier.
|
||||
|
||||
Lorsque l'on crée un *namespace* `user`, généralement, la correspondance vaut :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
0 1000 1
|
||||
42sh$ cat /proc/self/uid_map
|
||||
0 1000 1
|
||||
```
|
||||
</div>
|
||||
|
||||
@ -94,18 +96,18 @@ des groupes au lieu des utilisateurs.
|
||||
|
||||
<div lang="en-US">
|
||||
```shell
|
||||
42sh$ unshare --mount --pid --mount-proc --fork --net --user --map-root-user /bin/bash
|
||||
42sh$ unshare --mount --pid --mount-proc --fork --net --user --map-root-user /bin/bash
|
||||
```
|
||||
</div>
|
||||
|
||||
Un `capsh --print` nous montre que l'on est bien root et que l'on possède
|
||||
toutes les capabilities. Cependant, cela ne signifie pas que l'on a tous les
|
||||
droits sur le système ; il y a plusieurs niveau de validation qui entrent en
|
||||
Un `capsh --print` nous montre que l'on est bien `root` et que l'on possède
|
||||
toutes les *capabilities*. Cependant, cela ne signifie pas que l'on a tous les
|
||||
droits sur le système ; il y a plusieurs niveaux de validation qui entrent en
|
||||
jeu. L'idée étant que l'on a été désigné root dans son conteneur, on devrait
|
||||
pouvoir y faire ce que l'on veut, tant que l'on agit pas en dehors.
|
||||
pouvoir y faire ce que l'on veut, tant que l'on n'agit pas en dehors.
|
||||
|
||||
|
||||
## Aller plus loin
|
||||
|
||||
N'hésitez pas à jeter un œil à la page de manuel consacré à ce *namespace* :
|
||||
N'hésitez pas à jeter un œil à la page du manuel consacré à ce *namespace* :
|
||||
`user_namespaces(7)`.
|
||||
|
Loading…
x
Reference in New Issue
Block a user