Save tuto corrections
This commit is contained in:
parent
f5ee6b8534
commit
10448a6c8d
115 changed files with 1423 additions and 1289 deletions
|
|
@ -1,6 +1,6 @@
|
|||
\newpage
|
||||
|
||||
### Exercice : comparaison de *namespace* -- `cmpns.sh`
|
||||
### Exercice : comparaison de *namespace* -- `cmpns.sh`
|
||||
|
||||
Les *namespaces* d'un programme sont exposés sous forme de liens symboliques
|
||||
dans le répertoire `/proc/<PID>/ns/`.
|
||||
|
|
@ -46,9 +46,9 @@ que l'on cherche à comparer.
|
|||
|
||||
Ici, `self` fait référence au processus actuellement exécuté (comme il existe
|
||||
un dossier `/proc/self/`, vous n'avez pas besoin de gérer de cas particulier
|
||||
pour ça !).
|
||||
pour ça !).
|
||||
|
||||
Et pourquoi pas :
|
||||
Et pourquoi pas :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
|
|
|
|||
|
|
@ -1,19 +1,19 @@
|
|||
\newpage
|
||||
|
||||
Exercice : `docker exec`
|
||||
Exercice : `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` !
|
||||
Réécrivons, en quelques lignes, la commande `docker exec` !
|
||||
|
||||
Pour savoir si vous avez réussi, comparez les sorties des commandes :
|
||||
Pour savoir si vous avez réussi, comparez les sorties des commandes :
|
||||
|
||||
- `ip address` ;
|
||||
- `hostname` ;
|
||||
- `mount` ;
|
||||
- `pa -aux` ;
|
||||
- `ip address` ;
|
||||
- `hostname` ;
|
||||
- `mount` ;
|
||||
- `ps -aux` ;
|
||||
- ...
|
||||
|
||||
|
||||
|
|
@ -27,11 +27,11 @@ d63ceae863956f8312aca60b7a57fbcc1fdf679ae4c90c5d9455405005d4980a
|
|||
234269
|
||||
|
||||
42sh# ./mydocker_exec mywebserver ip address
|
||||
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
|
||||
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group def
|
||||
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
|
||||
13: eth0@if14: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 state UP group def
|
||||
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
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ 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és dans un autre *namespace* `UTS` :
|
||||
nous sommes passés dans un autre *namespace* `UTS` :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
|
|
@ -64,7 +64,7 @@ Ce *syscall*, propre à Linux, crée habituellement un nouveau processus (mais
|
|||
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 :
|
||||
sont passés :
|
||||
|
||||
* `CLONE_NEWNS`,
|
||||
* `CLONE_NEWUTS`,
|
||||
|
|
@ -83,7 +83,7 @@ que nous verrons plus tard.
|
|||
|
||||
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 C
|
||||
semblable à :
|
||||
semblable à :
|
||||
|
||||
<div lang="en-US">
|
||||
```c
|
||||
|
|
@ -118,7 +118,7 @@ dans un nouvel espace de noms. Dans ce cas, on utilisera l'appel système
|
|||
|
||||
::::: {.warning}
|
||||
Le comportement de `unshare(2)` (ou `unshare(3)`) avec les *namespace*s *PID*
|
||||
et *Time* n'est pas celui que l'on peut attendre !
|
||||
et *Time* n'est pas celui que l'on peut attendre !
|
||||
|
||||
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 à
|
||||
|
|
|
|||
|
|
@ -22,12 +22,12 @@ 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`,
|
||||
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
|
||||
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, ...).
|
||||
|
||||
|
|
@ -74,12 +74,12 @@ 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
|
||||
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
|
||||
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.
|
||||
|
||||
|
|
@ -89,7 +89,7 @@ processus, et non un fils de l'`init` de l'arbre global.
|
|||
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
|
||||
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
|
||||
|
|
@ -126,7 +126,7 @@ 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
|
||||
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.
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ de processus qui l'utilisent. C'est-à-dire que, la plupart du temps, le
|
|||
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` :
|
||||
persister après le dernier processus), on peut utiliser un `mount bind` :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
|
|
@ -29,7 +29,7 @@ obtenir un descripteur de fichier valide vers le *namespace* (pour passer à
|
|||
|
||||
|
||||
::::: {.question}
|
||||
#### Faire persister un *namespace* ? {-}
|
||||
#### Faire persister un *namespace* ? {-}
|
||||
\
|
||||
|
||||
Il n'est pas possible de faire persister un espace de noms d'un reboot à
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ Le *namespace* `mount`
|
|||
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 ?
|
||||
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
|
||||
|
|
@ -33,7 +33,7 @@ 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
|
||||
sportif car il s'agit de ne plus avoir aucune trace de l'ancienne racine. Au
|
||||
moins ici, il ne sera certainement pas possible de revenir en arrière dans
|
||||
l'arborescence\ !
|
||||
l'arborescence !
|
||||
|
||||
Pour l'instant, votre système utilise sans doute la partition d'un disque
|
||||
physique comme racine de son système de fichier. Le changement de racine, va
|
||||
|
|
@ -52,7 +52,7 @@ la racine d'un point de montage, comme l'explique `pivot_root(2)`. En effet, il
|
|||
serait encore possible hypothétiquement de remonter dans l'arborescence si l'on
|
||||
ne se trouvait pas à la racine d'une partition au moment du basculement.
|
||||
|
||||
Si vous n'avez pas de partition à disposition, vous pouvez utiliser un `tmpfs` :
|
||||
Si vous n'avez pas de partition à disposition, vous pouvez utiliser un `tmpfs` :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
|
|
@ -61,32 +61,31 @@ Si vous n'avez pas de partition à disposition, vous pouvez utiliser un `tmpfs`
|
|||
```
|
||||
</div>
|
||||
|
||||
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).
|
||||
Placez ensuite dans cette nouvelle racine le système de votre choix.
|
||||
|
||||
|
||||
### Exercice : Changer de racine -- `myswitch_root.sh`
|
||||
### Exercice : Changer de racine -- `myswitch_root.sh`
|
||||
|
||||
Voici les grandes étapes du changement de racine :
|
||||
Voici les grandes étapes du changement de racine :
|
||||
|
||||
1. S'isoler dans les *namespaces* adéquats ;
|
||||
1. S'isoler dans les *namespaces* adéquats ;
|
||||
2. Démonter ou déplacer toutes les partitions de l'ancienne racine vers la
|
||||
nouvelle racine ;
|
||||
3. `pivot_root` !
|
||||
nouvelle racine ;
|
||||
3. `pivot_root` !
|
||||
|
||||
|
||||
#### S'isoler\
|
||||
|
||||
Notre but étant de démonter toutes les partitions superflues, nous allons
|
||||
devoir nous isoler sur :
|
||||
devoir nous isoler sur :
|
||||
|
||||
* les points de montages, ça semble évident ;
|
||||
* les PIDs : car on ne pourra pas démonter une partition en cours
|
||||
* les points de montages, ça semble évident ;
|
||||
* les PIDs : car on ne pourra pas démonter une partition en cours
|
||||
d'utilisation. S'il n'y a pas de processus, il n'y a personne pour nous
|
||||
empêcher de démonter une partition !
|
||||
empêcher de démonter une partition !
|
||||
* les autres *namespaces* ne sont pas forcément nécessaires.
|
||||
|
||||
Isolons-nous :
|
||||
Isolons-nous :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
|
|
@ -97,12 +96,12 @@ Isolons-nous :
|
|||
|
||||
#### 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
|
||||
mount*.
|
||||
|
||||
Commençons donc par étiqueter tous nos points de montage (de ce *namespace*),
|
||||
comme esclaves :
|
||||
comme esclaves :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
|
|
@ -111,15 +110,15 @@ comme esclaves :
|
|||
</div>
|
||||
|
||||
|
||||
#### Démonter tout !\
|
||||
#### Démonter tout !\
|
||||
|
||||
À 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
|
||||
seconde.
|
||||
|
||||
|
|
@ -136,7 +135,7 @@ 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é
|
||||
les partitions systèmes à leur place dans la nouvelle racine.
|
||||
|
||||
L'appel de la commande sert à intervertir les deux racines ; elle prend en argument :
|
||||
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.
|
||||
|
|
@ -144,7 +143,7 @@ L'appel de la commande sert à intervertir les deux racines ; elle prend en argu
|
|||
Une fois le pivot effectué, on peut démonter l'ancienne racine.
|
||||
|
||||
Pour lancer la première commande dans la nouvelle racine, on passe généralement
|
||||
par :
|
||||
par :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ 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
|
||||
*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/).
|
||||
|
|
|
|||
|
|
@ -6,11 +6,11 @@ Le *namespace* `network` {#net-ns}
|
|||
### Introduction
|
||||
|
||||
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.
|
||||
|
||||
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">
|
||||
```
|
||||
|
|
@ -25,7 +25,7 @@ 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
|
||||
dans l'espace principal, ne le sont plus dans le conteneur : il est donc
|
||||
possible de lancer un serveur web sans qu'il n'entre en conflit avec celui d'un
|
||||
autre espace de noms.
|
||||
|
||||
|
|
@ -33,9 +33,9 @@ autre espace de noms.
|
|||
### Premiers pas avec `ip netns`
|
||||
|
||||
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 noms :
|
||||
Nous pouvons tout d'abord créer un nouvel espace de noms :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
|
|
@ -45,17 +45,17 @@ Nous pouvons tout d'abord créer un nouvel espace de noms :
|
|||
|
||||
La technique utilisée ici pour avoir des *namespaces* nommés est la même que
|
||||
celle que nous avons vue dans
|
||||
[la première partie sur les *namespaces*](#ns-lifetime) : via un `mount --bind`
|
||||
[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éé, nous pouvons regarder s'il contient
|
||||
des interfaces :
|
||||
des interfaces :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
42sh# ip netns exec virli ip link
|
||||
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT group default qlen 1
|
||||
1: lo: <LOOPBACK> mut 65536 qdisc noop state DOWN mode DEFAULT group default
|
||||
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
|
||||
```
|
||||
</div>
|
||||
|
|
@ -64,7 +64,7 @@ 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 :
|
||||
via la commande :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
|
|
@ -92,7 +92,7 @@ interface physique par conteneur, d'autant plus si l'on a plusieurs
|
|||
centaines de conteneurs à gérer.
|
||||
|
||||
Une technique couramment employée consiste à créer une interface virtuelle de
|
||||
type `veth` :
|
||||
type `veth` :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
|
|
@ -100,16 +100,16 @@ type `veth` :
|
|||
```
|
||||
</div>
|
||||
|
||||
Une interface `veth` se comporte comme un tube bidirectionnel : tout ce qui
|
||||
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
|
||||
créé deux interfaces `veth0` et `veth1` : les paquets envoyés sur `veth0` sont
|
||||
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é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` :
|
||||
Pour déplacer `veth1` dans notre *namespace* `virli` :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
|
|
@ -117,7 +117,7 @@ Pour déplacer `veth1` dans notre *namespace* `virli` :
|
|||
```
|
||||
</div>
|
||||
|
||||
Il ne reste maintenant plus qu'à assigner une IP à chacune des interfaces :
|
||||
Il ne reste maintenant plus qu'à assigner une IP à chacune des interfaces :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
|
|
@ -126,7 +126,7 @@ Il ne reste maintenant plus qu'à assigner une IP à chacune des interfaces :
|
|||
```
|
||||
</div>
|
||||
|
||||
Dès lors[^linkdown], nous pouvons `ping`er chaque extrêmité :
|
||||
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`.
|
||||
|
|
@ -140,7 +140,7 @@ Dès lors[^linkdown], nous pouvons `ping`er chaque extrêmité :
|
|||
</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
|
||||
|
|
@ -171,9 +171,9 @@ derrière notre machine.
|
|||
<!-- 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
|
||||
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 quatre modes : *private*, VEPA, *bridge* ou *passthru*.
|
||||
des quatre modes : *private*, VEPA, *bridge* ou *passthru*.
|
||||
|
||||
Quel que 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
|
||||
|
|
@ -189,7 +189,7 @@ 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 :
|
||||
Pour construire une nouvelle interface de ce type :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
|
|
@ -217,11 +217,11 @@ conteneur de la même machine.
|
|||
##### *Bridge*
|
||||
|
||||
À 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
|
||||
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 :
|
||||
Pour construire une nouvelle interface de ce type :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
|
|
@ -233,9 +233,9 @@ Pour construire une nouvelle interface de ce type :
|
|||
### Aller plus loin {-}
|
||||
|
||||
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).
|
||||
|
||||
Appliqué à Docker, vous apprécierez cet article : [Understanding Docker
|
||||
Appliqué à Docker, vous apprécierez cet article : [Understanding Docker
|
||||
Networking Drivers and their use
|
||||
cases](https://www.docker.com/blog/understanding-docker-networking-drivers-use-cases/).
|
||||
|
|
|
|||
|
|
@ -18,9 +18,9 @@ pas de PID en cours de route, puisqu'il dépend du *namespace* dans lequel il se
|
|||
trouve.
|
||||
|
||||
|
||||
### Isolons !
|
||||
### Isolons !
|
||||
|
||||
Première étape s'isoler :
|
||||
Première étape s'isoler :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
|
|
@ -45,9 +45,9 @@ notre système initial. Pour s'en sortir, il est nécessaire de s'isoler dans un
|
|||
*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 :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
|
|
@ -65,11 +65,11 @@ Cette fois, `top` et `ps` nous rapportent bien que l'on est seul dans notre
|
|||
### Arborescence à l'extérieur du *namespace*
|
||||
|
||||
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
|
||||
son nouveau *namespace*) était présent dans l'arborescence de l'espace initial
|
||||
avec un PID dans la continuité des autres processus, étonnant !
|
||||
avec un PID dans la continuité des autres processus, étonnant !
|
||||
|
||||
En fait, l'isolation consiste en une virtualisation des numéros du processus :
|
||||
En fait, l'isolation consiste en une virtualisation des numéros du processus :
|
||||
la plupart des processus du système initial ne sont pas accessibles, et ceux qui
|
||||
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.
|
||||
|
|
@ -85,12 +85,12 @@ 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.
|
||||
|
||||
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 noms.
|
||||
|
||||
[^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
|
||||
de l'arborescence. Le processus au PID 1 hérite forcément de cette propriété\ ;
|
||||
de l'arborescence. Le processus au PID 1 hérite forcément de cette propriété\ ;
|
||||
il va donc récupérer tous les orphelins, si aucun de leurs parents n'ont la
|
||||
propriété définie.
|
||||
|
||||
|
|
@ -104,4 +104,4 @@ l'intérieur pour conserver un comportement cohérent.
|
|||
### Aller plus loin {-}
|
||||
|
||||
N'hésitez pas à jeter un œil à la page de manuel consacrée à cet espace de
|
||||
noms : `pid_namespaces(7)`.
|
||||
noms : `pid_namespaces(7)`.
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ Projet et rendu
|
|||
notation de ce cours.**
|
||||
|
||||
Vous allez continuer aujourd'hui le projet qui s'étendra depuis le TP précédent
|
||||
et qui consistera à réaliser la partie d'isolation de la moulinette des ACUs !
|
||||
et qui consistera à réaliser la partie d'isolation de la moulinette des ACUs !
|
||||
|
||||
Cette semaine, il faudra faire en sorte de restreindre un groupe de processus
|
||||
pour qu'il s'exécute indépendemment de votre système.
|
||||
|
|
@ -17,8 +17,8 @@ pour qu'il s'exécute indépendemment de votre système.
|
|||
Il n'y a pas de restriction sur le langage utilisé, vous pouvez tout aussi bien
|
||||
utiliser du C, du C++, du Python, du shell, etc.
|
||||
|
||||
L'usage de bibliothèques **non relatives** au projet est autorisé : le but de
|
||||
L'usage de bibliothèques **non relatives** au projet est autorisé : le but de
|
||||
ce sujet est d'évaluer votre compréhension et votre utilisation de la
|
||||
tuyauterie bas-niveau du noyau liée à la virtualisation légère. À partir du
|
||||
moment où vous n'utilisez pas une bibliothèque qui abstrait complètement cette
|
||||
plomberie, n'hésitez pas à l'utiliser !
|
||||
plomberie, n'hésitez pas à l'utiliser !
|
||||
|
|
|
|||
|
|
@ -3,9 +3,9 @@
|
|||
Projet et rendu
|
||||
===============
|
||||
|
||||
Est attendu d'ici le TP suivant :
|
||||
Est attendu d'ici le TP suivant :
|
||||
|
||||
- le rendu des exercice de ce TP ;
|
||||
- le rendu des exercice de ce TP ;
|
||||
- vos réponses à [l'évaluation du cours](https://virli.nemunai.re/quiz/15).
|
||||
|
||||
Pour les GISTRE (et en bonus pour les SRS), [un
|
||||
|
|
@ -40,7 +40,7 @@ RAR, ...).
|
|||
|
||||
Voici une arborescence type (adaptez les extensions et les éventuels
|
||||
fichiers supplémentaires associés au langage que vous aurez choisi
|
||||
pour chaque exercice) :
|
||||
pour chaque exercice) :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#### Exemple C\
|
||||
|
||||
Voici un exemple de code C utilisant `setns(2)` :
|
||||
Voici un exemple de code C utilisant `setns(2)` :
|
||||
|
||||
<div lang="en-US">
|
||||
```c
|
||||
|
|
@ -38,7 +38,7 @@ main(int argc, char *argv[])
|
|||
|
||||
#### Exemple shell\
|
||||
|
||||
Dans un shell, on utilisera la commande `nsenter(1)` :
|
||||
Dans un shell, on utilisera la commande `nsenter(1)` :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ l'autre, d'une version du noyau à l'autre, il est normal d'avoir une liste de
|
|||
aurons les mêmes.
|
||||
|
||||
Ces fichiers sont en fait des liens symboliques un peu particuliers, car ils ne
|
||||
pointent pas vers une destination valide :
|
||||
pointent pas vers une destination valide :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
|
|
@ -52,7 +52,7 @@ On ne peut pas afficher tel quel les structures, mais on peut l'ouvrir avec
|
|||
`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.
|
||||
lien symbolique : la commande se chargera d'`open(2)` le fichier.
|
||||
|
||||
|
||||
#### `*_for_children`\
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
Pour pouvoir suivre les exercices ci-après, vous devez disposez d'un noyau
|
||||
Linux, idéalement dans sa version 5.6 ou mieux. Il doit de plus être compilé
|
||||
avec les options suivantes (lorsqu'elles sont disponibles pour votre version) :
|
||||
avec les options suivantes (lorsqu'elles sont disponibles pour votre version) :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
|
|
@ -28,7 +28,7 @@ Device Drivers --->
|
|||
```
|
||||
</div>
|
||||
|
||||
Les variables de configuration correspondantes sont :
|
||||
Les variables de configuration correspondantes sont :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
|
|
@ -62,13 +62,13 @@ Nous allons utiliser des programmes issus des
|
|||
[`procps-ng`](https://gitlab.com/procps-ng/procps) ainsi que ceux de la
|
||||
[`libcap`](https://sites.google.com/site/fullycapable/).
|
||||
|
||||
Sous Debian et ses dérivés, ces paquets sont respectivement :
|
||||
Sous Debian et ses dérivés, ces paquets sont respectivement :
|
||||
|
||||
* `util-linux`
|
||||
* `procps`
|
||||
* `libcap2-bin`
|
||||
|
||||
Sous ArchLinux et ses dérivés, ces paquets sont respectivement :
|
||||
Sous ArchLinux et ses dérivés, ces paquets sont respectivement :
|
||||
|
||||
* `util-linux`
|
||||
* `procps-ng`
|
||||
|
|
@ -79,17 +79,17 @@ Sous ArchLinux et ses dérivés, ces paquets sont respectivement :
|
|||
|
||||
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 :
|
||||
à ce sujet :
|
||||
|
||||
* [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/) ;
|
||||
* <http://marc.info/?l=linux-kernel&m=135543612731939&w=2> ;
|
||||
* [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/) ;
|
||||
* <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`.
|
||||
[^userns-caps]: Sont nécessaires, conjointement : `CAP_SYS_ADMIN`, `CAP_SETUID` et `CAP_SETGID`.
|
||||
|
||||
De nombreuses distributions ont choisi d'utiliser un paramètre du noyau pour
|
||||
adapter le comportement.
|
||||
|
|
@ -99,7 +99,7 @@ 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 :
|
||||
explicitement cette utilisation non-privilégiée :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ utilisateur, on obtient les privilèges requis pour créer tous les autres types
|
|||
de *namespaces*.
|
||||
|
||||
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
|
||||
en grande partie sur cela.
|
||||
|
||||
|
||||
|
|
@ -34,11 +34,11 @@ garder dans le nouvel espace, que les utilisateurs et les groupes utiles au
|
|||
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
|
||||
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*.
|
||||
|
||||
-1 étant réservé pour indiquer une erreur dans le retour d'une commande, ou la
|
||||
|
|
@ -53,7 +53,7 @@ Pour établir la correspondance, une fois que l'on a créé le nouveau
|
|||
|
||||
##### `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
|
||||
en question.
|
||||
|
|
@ -62,7 +62,7 @@ Sur chaque ligne, on doit indiquer :
|
|||
- La taille de la plage.
|
||||
|
||||
|
||||
Par exemple, le *namespace* `user` initial défini la correspondance suivante :
|
||||
Par exemple, le *namespace* `user` initial défini la correspondance suivante :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
|
|
@ -75,7 +75,7 @@ Cela signifie que les utilisateurs dont l'identifiant court de 0 à `MAX_INT -
|
|||
2` inclus, dans cet espace de noms, correspondent aux utilisateurs allant de 0 à
|
||||
`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 :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
|
|
@ -99,18 +99,18 @@ des groupes au lieu des utilisateurs.
|
|||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
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 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 niveaux de validation qui entrent en
|
||||
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 n'agit pas en dehors.
|
||||
|
||||
|
||||
### Aller plus loin {-}
|
||||
|
||||
N'hésitez pas à jeter un œil à la page du manuel consacrée à ce *namespace* :
|
||||
N'hésitez pas à jeter un œil à la page du manuel consacrée à ce *namespace* :
|
||||
`user_namespaces(7)`.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue