From b459443d9e97171f8258aae6ec78b8f9cfe47b22 Mon Sep 17 00:00:00 2001 From: Pierre-Olivier Mercier Date: Wed, 5 Oct 2016 22:49:08 +0200 Subject: [PATCH] Work on tuto 3 --- tutorial/3/capabilities.md | 149 +++++++++++++++++++++++++- tutorial/3/cgroups.md | 89 ++++++++++----- tutorial/3/chroot.md | 6 +- tutorial/3/lxc.md | 214 ------------------------------------- tutorial/3/namespaces.md | 133 ----------------------- tutorial/3/project.md | 91 ++++++++++++---- tutorial/3/pseudofs.md | 49 +++++++-- tutorial/4/cgroups.md | 195 --------------------------------- tutorial/4/installation.md | 55 ---------- 9 files changed, 325 insertions(+), 656 deletions(-) delete mode 100644 tutorial/3/lxc.md delete mode 100644 tutorial/3/namespaces.md delete mode 100644 tutorial/4/cgroups.md delete mode 100644 tutorial/4/installation.md diff --git a/tutorial/3/capabilities.md b/tutorial/3/capabilities.md index ed65705..52bb090 100644 --- a/tutorial/3/capabilities.md +++ b/tutorial/3/capabilities.md @@ -5,13 +5,156 @@ Les capabilities ## Présentation -## La `libcap` +Historiquement, dans la tradition UNIX, on distingue deux catégories de +processus : -## Les attributs étendus +* les processus *privilégiés* : dont l'identifiant de son utilisateur est 0 ; +* les processus *non-privilégiés* : dont l'identifiant de son utilisateur n'est + pas 0. + +Lors des différents tests de permission fait par le noyau, les processus +privilégiés outrepassaient ces tests, tandis que les autres devaient passer les +tests de l'effective UID, effective GID, et autres groupes supplémentaires... + +Depuis Linux 2.2 (en 1998), les processus privilégiés peuvent activer ou +désactiver des *capabilities*, chacune donnant accès à un groupe d'actions +privilégiées au sein du noyau. + +On trouve par exemple : + +* `CAP_CHOWN` : permet de modifier le propriétaire d'un fichier de manière + arbitraire ; +* `CAP_KILL` : permet de tuer n'importe quel processus ; +* `CAP_SYS_BOOT` : permet d'arrêter ou de redémarrer la machine ; +* `CAP_SYS_MODULE` : permet de charger et décharger des modules ; +* et beaucoup d'autres, il y en a environ 39 en tout ! + + +### `ping` + +Pour émettre un ping, il est nécessaire d'envoyer des paquets ICMP. À la +différence des datagrammes UDP ou des segments TCP, il n'existe pas d'interface +exposée par le noyau aux utilisateurs pour envoyer des paquets ICMP. Pour le +faire, il est nécessaire de pouvoir écrire directement sur l'interface ; ça, +seul le super-utilisateur peut le faire. + +Pour permettre à tous les utilisateurs de pouvoir envoyer des ping, le +programme est donc généralement Setuid root. Cela permet à n'importe quel +utilisateur de prendre les droits du super-utilisateur, le temps de l'exécution +du programme. + +Les problèmes surviennent lorsque l'on découvre des vulnérabilités dans les +programmes Setuid root. En effet, s'il devient possible à un utilisateur +d'exécuter du code arbitraire, ce code sera exécuté avec les privilèges de +l'utilisateur root ! Dans le cas de ping, on se retrouverait alors à pouvoir +lire l'intégralité de la mémoire, alors que l'on avait juste besoin d'écrire +sur une interface réseau. + +C'est donc à ce moment que les *capabilities* entrent en jeu : un processus (ou +même un thread) privilégié peut décider, à son lancement, de réduire ses +*capabilities*, pour ne garder que celles dont il a réellement besoin. Ainsi, +`ping` pourrait se contenter de `CAP_NET_RAW`. + + +## Les attributs de fichier étendus + +Une grosse majorité des systèmes de fichiers (ext[234], XFS, btrfs, ...) +permettent d'enregistrer, pour chaque fichier, des attributs (dits attributs +*étendus*, par opposition aux attributs *réguliers* qui sont réservés à l'usage +du système de fichiers). + +Sous Linux, les attributs sont regroupés dans des espaces de noms : + +* *security* : espace utilisé par les modules de sécurité du noyau, tel que + SELinux, ... ; +* *system* : espace utilisé par le noyau pour stocker des objets système, tels + que les ACL POSIX ; +* *trusted*: espace dont la lecture et l'écriture est limité au + super-utilisateur ; +* *user* : modifiable sans restriction, à partir du moment où l'on est le + propriétaire du fichier. + +Par exemple, on peut définir un attribut sur un fichier comme cela : + +```shell +42sh$ echo 'Hello World!' > toto +42sh$ setfattr -n user.foo -v bar toto +42sh$ getfattr -d toto +# file: toto +user.foo="bar" +``` + +Encore plus fort, vous pouvez utiliser les ACL POSIX : + +```shell +42sh$ sudo chown root:root toto && sudo chmod o-r toto +42sh$ cat toto +cat: toto: Permission denied +42sh$ sudo setfattr -m u:$USER:r toto +42sh$ cat toto +Hello World! +``` + +Bien que les droits UNIX traditionnels ne vous donne pas accès au fichier, les +ACL POSIX vous autorisent à lire le contenu du fichier. + +Vous pouvez voir ces attributs avec la commande : + +```shell +42sh$ getfattr -d -m "^system" toto +# file: toto +system.posix_acl_access=0sgAAEAD/////AgAEOgDAEAA/////xAABAD////8= +``` + + +### `ping` + +De la même manière que l'on peut définir de manière plus fine les droits +d'accès par utilisateur, un attribut de l'espace de nom *security* peut être +définit pour accroître les *capabilities* d'un processus lorsqu'il est lancé +par un utilisateur non-privilégié. On peut alors voir le Setuid root comme +l'utilisation de cet attribut auquel on accroîtrait l'ensemble des +*capabilities*. + +Si votre distribution profite de ces attributs étendus, vous devriez obtenir : + +```shell +42sh$ getfattr -d -m "^security" $(which ping) +# file: bin/ping +security.capability=0sAQAAAgAgAAAAAAAAAAAAAAAAAAA= +``` + +Ou, dans sa version plus lisible : + +```shell +42sh$ getcap $(which ping) +/bin/ping = cap_net_raw+ep +``` -`getcap` et `setcap` sur `ping` ## Exercice : visualisateur de capabilities d'un processus +Écrivons maintenant un script permettant de voir les *capabilities* d'un +processus : + ```shell ``` + +## Rendu + + + + +## Aller plus loin + +Je vous recommande la lecture des *man* suivants : + +* `capabilities(7)` : énumérant tous les capabilities, leur utilisation, etc. ; +* `xattrs(7)` : à propos des attributs étendus. + +Et de ces quelques articles : + +* [https://www.freedesktop.org/wiki/CommonExtendedAttributes/](Guidelines for + extended attributes) +* [https://lwn.net/Articles/211883/](File-based capabilities) +* [http://lwn.net/Articles/199004/](A bid to resurrect Linux capabilities) diff --git a/tutorial/3/cgroups.md b/tutorial/3/cgroups.md index 0634fef..177ff2b 100644 --- a/tutorial/3/cgroups.md +++ b/tutorial/3/cgroups.md @@ -14,11 +14,12 @@ de ressources ou altérer leurs priorités. Nous allons commencer par faire quelques tests avec le *cgroup* freezer, qui permet d'interrompre l'exécution d'un groupe de processus et de la reprendre. + ### Montage du *cgroup* En fonction de la configuration de votre système, il est possible que les *cgroup*s ne soient pas montés au démarrage dans `/sys/fs/cgroup/`. Si vous n'avez -pas de dossier `freezer` ou si celui-ci est vide, monter-le en suivant la +pas de dossier `freezer` ou si celui-ci est vide, montez-le en suivant la procédure suivante : ``` @@ -27,8 +28,9 @@ mount -t cgroup -o freezer none /sys/fs/cgroup/freezer/ ``` Cette dernière commande monte le groupe de processus racine, pour le *cgroup* -freezer. Tous les dossiers contenu dans cette racine sont des sous-groupes de -cette dernière. +freezer. Tous les dossiers contenu dans cette racine sont donc des +sous-groupes. + ### Création d'un nouveau groupe @@ -47,6 +49,7 @@ Vous avez maintenant un nouveau groupe de processus `virli` dans le *cgroup* Freezer. Comme il s'agit d'une hiérarchie, le groupe `virli` hérite des propriétés de son (ses) père(s). + ### Rattachement de processus Pour le moment, ce nouveau groupe ne contient aucune tâche. @@ -64,22 +67,24 @@ echo $PID > /sys/fs/cgroup/freezer/virli/tasks Il faut ici remplacer `$PID` par le PID du shell que l'on a relevé juste avant. En validant cette commande, vous avez déplacé le processus dans ce groupe, il -n'est alors plus dans aucun autre groupe (dans ce *cgroup*, il ne bouge pas +n'est alors plus dans aucun autre groupe (pour ce *cgroup*, il ne bouge pas dans les autres *cgroup*s). + ### Consultation de l'état -En affichant le contenu du dossier `virli`, nous avons pu constater que -celui-ci contenait déjà un certain nombre de fichiers. Certain d'entre-eux sont -en lecture seule et permettent de lire des statistiques instantanées sur le -groupe ; tandis que d'autres sont des propriétés que vous pouvez modifier. +En affichant le contenu du dossier `virli`, nous pouvons constater que celui-ci +contenait déjà un certain nombre de fichiers. Certain d'entre-eux sont en +lecture seule et permettent de lire des statistiques instantanées sur le groupe +; tandis que d'autres sont des propriétés que vous pouvez modifier. Nous pouvons consulter l'état de gel du groupe en affichant le contenu du fichier\newline `/sys/fs/cgroup/freezer/virli/freezer.state`. Pour plus d'information sur les différents fichiers présents dans ce *cgroup*, -consulter la documentation, accessible ici : - +consulter +[la documentation associée](https://www.kernel.org/doc/Documentation/cgroup-v1/freezer-subsystem.txt). + ### Changement d'état @@ -105,11 +110,28 @@ echo THAWED > /sys/fs/cgroup/freezer/virli/freezer.state ``` -## Script de monitoring +## Exercice : script de monitoring + +À nous maintenant de concevoir un script qui va enregistrer vers une base de +données des statistiques issues des *cgroup*s. + + +### Rappel d'InfluxDB + +Commençons par lancer le conteneur Docker d'InfluxDB (pour éviter de +l'installer sur notre machine) : + +```shell +docker run -d -p 8086:8086 -p 8083:8083 influxdb +``` + +Il nous faut ensuite créer une base de données pour y stocker les métriques, +rendez-vous à puis entrez la requête : + +```sql +CREATE DATABASE metrics; +``` -À nous maintenant de concevoir un script qui va enregistrer vers la base de -données créée (*metrics*) dans la partie précédente, des statistiques issues -des *cgroup*s. ### Monitoring instantané vers la console @@ -125,30 +147,29 @@ mémoire utilisée par le groupe monitoré. Vous pouvez utiliser un programme comme `memhog` pour remplir rapidement votre mémoire. -Si vous n'avez pas le *cgroup* memory, il est possible qu'il ne soit -pas activé par défaut par votre système. Si vous êtes dans ce cas, essayez d'ajouter +Si vous n'avez pas le *cgroup* memory, il est possible qu'il ne soit pas activé +par défaut par votre système. Si vous êtes dans ce cas, essayez d'ajouter +`cgroup_enable=memory` à la ligne de commande de votre noyau. -``` -cgroup_enable=memory -``` ### Monitoring vers InfluxDB Maintenant, envoyons nos données vers la base - : + : ``` -curl -i -XPOST 'http://172.23.42.2:8086/write?db=metrics' --data-binary \ +curl -i -XPOST 'http://localhost:8086/write?db=metrics' --data-binary \ "$my_cgroup_name memory.usage_in_bytes=$(cat .../my_cgroup_name/memory.usage_in_bytes)" ``` -Pour vérifier que les données sont bien ajoutées, vous pouvez effectuez la +Pour vérifier que les données ont bien été ajoutées, vous pouvez effectuez la requête suivante dans l'interface web d'InfluxDB : ``` SELECT * from "$my_cgroup_name"; ``` + ### Monitorer davantage de données Liste non exhaustive de données à monitorer : @@ -159,7 +180,8 @@ Liste non exhaustive de données à monitorer : * trafic réseau généré ; * ... - + + ### Permettre à l'utilisateur de monitorer des process @@ -172,7 +194,7 @@ bons droits, tandis que le deuxième va utiliser effectuer le monitoring, sans #### Exemple ``` -42sh# ./monitor_init my_cgroup_name +42sh$ sudo ./monitor_init my_cgroup_name 42sh$ ./monitor my_cgroup_name memhog 500 ``` @@ -181,8 +203,7 @@ bons droits, tandis que le deuxième va utiliser effectuer le monitoring, sans ### Script de monitoring -Rendez la révision la plus avancée de vos scripts de monitoring de process via -les *cgroup*s. +Rendez la révision la plus avancée de vos scripts de monitoring de processus. ### Questions @@ -194,3 +215,19 @@ les *cgroup*s. 1. Actuellement, comment peut-on limiter le nombre de processus lancés par un utilisateur ou un groupe ? + + +## Pour aller plus loin + +Depuis les noyaux 4.5, il est possible d'utiliser la nouvelle version du +pseudo système de fichiers des *CGroup*s. Le principal changement vient du +regroupement au sein d'une seule hiérarchie des différents *CGroup*s que l'on +avait dans la v1. Davantage d'informations sont disponibles : + +* [https://lwn.net/Articles/679786/](Understanding the new control groups API) + ; +* [https://www.kernel.org/doc/Documentation/cgroup-v2.txt](Kernel Document + about Control Group v2). + +Pour tout connaître en détails, [la série d'articles de Neil Brown sur les +Control groups](https://lwn.net/Articles/604609/) est excellente ! diff --git a/tutorial/3/chroot.md b/tutorial/3/chroot.md index 261e4c3..f3b48ce 100644 --- a/tutorial/3/chroot.md +++ b/tutorial/3/chroot.md @@ -1,7 +1,7 @@ \newpage -L'isolation du pauvre -===================== +L'isolation ... du pauvre +========================= Depuis les premières version d'Unix, il est possible de changer le répertoire vu comme étant la racine du système de fichiers. @@ -74,7 +74,7 @@ Dans le nouvel environnement, vous ne devriez pas pouvoir faire : cat ../foo ``` -Mais une fois votre programme exécuté, vous devriez pouvoir ! +Mais une fois votre programme `escape` exécuté, vous devriez pouvoir ! ```shell ./escape diff --git a/tutorial/3/lxc.md b/tutorial/3/lxc.md deleted file mode 100644 index 834acff..0000000 --- a/tutorial/3/lxc.md +++ /dev/null @@ -1,214 +0,0 @@ -\newpage - -# Utiliser `lxc` - -Le but de cette première partie est d'appréhender la virtualisation légère au -travers d'un programme, `lxc`, qui va mettre en place pour nous tout un -environnement distinct. - - -## Lancer un conteneur - -Avec le paquet `lxc` que nous avons précédemment installé, nous avons également -récupéré un certain nombre de *modèles* de système (souvent installés dans le -dossier `/usr/share/lxc/templates/`) : il s'agit d'une suite de commandes -(principalement des `wget`, `chroot` ou `debootstrap`) permettant d'obtenir un -système basic fonctionnel, en suivant les étapes d'installation habituelle de -la distribution. - -La méthode la plus simple pour lancer un conteneur `lxc` est d'utiliser l'un de -ces modèles pour obtenir un nouveau système. On utilise pour cela la commande -`lxc-create` : - -``` -lxc-create --name toto_first --template debian -``` - -Ce modèle va créer un dossier dans `/var/lib/lxc/` (pouvant varier d'une -distribution à l'autre) portant le nom que nous avons précisé. Ce dossier va -contenir la configuration `lxc` du conteneur (`config`), la table des -partitions (`fstab`) s'il y a besoin de faire des montages particuliers et -enfin le dossier `rootfs` contenant le système en lui-même. - -Une fois l'installation terminée, on peut démarrer le conteneur : - -``` -lxc-start --name toto_first -``` - -`lxc` va appeler `/sbin/init` et démarrer tous les services que l'on peut -s'attendre à trouver dans n'importe quelle machine virtuelle (et même physique) -plus classique (la seule différence réside donc dans le fait que le noyau est -partagé avec l'hôte). - -Généralement on lance `lxc-start` avec l'option `--daemon`, car on n'a pas -vraiment envie d'avoir un conteneur bloquant un terminal. En mode daemon, on va -utiliser la commande `lxc-console` pour nous attacher aux conteneurs. À tout -moment, nous pouvons nous détacher de la console (sans que cela n'affecte -l'état du conteneur) en pressant les touches : `^A q`. - -Connectons-nous, lancons quelques commandes puis éteignons la machine en -lançant la commande `poweroff` dans le conteneur. Il est également possible de -lancer la commande `lxc-stop --name toto_first` dans un autre terminal, depuis -la machine hôte. - - -## Le réseau - -Le modèle *Debian*, que nous avons utilisé, préremplit un fichier de -configuration sans définir de paramètre pour le réseau. Il n'y a donc pas -d'interface dans le conteneur pour le connecter : - -``` -lxc.network.type = empty -``` - -Un excellent article détaillant les différents types de configuration réseau -est accessible à -. - -N'ayant qu'une seule interface physique sur la machine et n'ayant pas accès à -la configuration des VLAN de la pièce, il ne nous reste que deux méthodes pour -obtenir du réseau dans nos conteneurs : Virtual Ethernet ou MACVLAN. - -### MACVLAN - -Cette méthode est la plus simple : le noyau va orienter les paquets en fonction -de leur adresse MAC de destination. Le conteneur sera donc comme une machine -supplémentaire sur le réseau. - -Modifions notre fichier de configuration afin qu'il ressemble à quelque chose -comme : - -``` -lxc.network.type = macvlan -lxc.network.macvlan.mode = bridge -lxc.network.flags = up -lxc.network.link = eth0 -``` - -Après avoir démarré le conteneur, il devrait avoir obtenu une IP du serveur -DHCP de l'école. L'inconvénient dans cette configuration est qu'il faille un -client netsoul dans chaque conteneur, puisque chacun est considéré comme une -machine différente aux yeux du routeur. - - -### Virtual Ethernet - -Virtual Ethernet est la configuration la moins optimale, mais sans doute la -plus flexible. - -Voici un extrait de configuration correspondant au paramétrage d'une interface -virtuelle pour un conteneur donné : - -``` -lxc.network.type = veth -lxc.network.ipv4 = 172.23.42.2/24 -lxc.network.flags = up -``` - -Dans cette situation, au démarrage du conteneur, `lxc` va créer une interface -veth, avec un côté placé dans la machine hôte et l'autre côté placé dans le -conteneur. `lxc` configure l'interface dans le conteneur, il nous appartient -ensuite de configurer la machine hôte. - -Commençons par attribuer une IP à cette nouvelle interface, en adaptant à votre -identifiant d'interface : - -``` -ip addr add 172.23.42.1/24 dev vethYJWD6R -``` - -À partir de là, nous devrions pouvoir pinger notre conteneur depuis notre -machine hôte : `ping 172.23.42.2`. - -Notre conteneur ne peut cependant pas encore accéder à Internet. Pour cela, la -machine hôte doit faire office de routeur et donc router les paquets d'un -réseau à l'autre : en l'occurence, du réseau 172.23.42.1 vers Internet -via 10.0.0.0/8, le réseau de l'école. - -Pour que notre machine hôte route les paquets, exécuter la commande : - -``` -sysctl -w net.ipv4.ip_forward=1 -``` - -Cette variable, que nous retrouvons dans `/proc/sys/net/ipv4/ip_forward`, -indique au noyau qu'il peut faire passer les paquets réseau d'une interface à -l'autre. Sans plus de directives, les paquets vont conserver leur adresse -source (172.23.42.2 pour les paquets en provenance du conteneur). Cette adresse -est une adresse privée, non routable sur Internet, ni même par le bocal. Il -faut donc ajouter une couche de NAT/PAT pour réécrire les adresses sources -avant d'envoyer les paquets sur internet : - -``` -iptables -t nat -A POSTROUTING ! -o vethYJWD6R -s 172.23.42.0/24 -j MASQUERADE -``` - -Dernière étape, dans notre conteneur, nous devons indiquer la route à utiliser -pour accéder à internet : - -``` -ip route add default via 172.23.42.1 -``` - -Nous avons maintenant internet dans notre conteneur ! - - -## Utilisation du conteneur - -### Installation de InfluxDB - -``` -apt-get update -apt-get install wget -wget https://s3.amazonaws.com/influxdb/influxdb_0.9.4.2_amd64.deb -dpkg -i influxdb_0.9.4.2_amd64.deb -``` - -### Test de l'installation - -``` -/opt/influxdb/influxd -``` - -Une fois que le service est démarré, vous devriez pouvoir accéder à l'interface -à : - -Créons une nouvelle base de données "metrics", elle nous servira dans la partie suivante. - - -## Rendu - -### Configuration du conteneur - -En plus des modifications que vous avez effectuées durant le TP, modifiez la -configuration du conteneur afin qu'il ne puisse pas utiliser plus que 256 MB de -RAM et 512 MB de swap. - -Limitez ensuite les `capabilities(7)` de ce conteneur afin qu'il s'exécute avec -le strict minimum de droits, nécessaire au bon fonctionnement des programmes -installés. - -**Rendez le fichier `config` de ce premier conteneur.** N'hésitez pas à laisser - des commentaires justifiant vos éventuels choix. - -### Questions - -1. Quels sont les autres types de virtualisation réseau existants ? Expliquez - en chacun une phrase leurs particularités. - -1. Quel fichier de configuration devriez-vous changer pour rendre persistante la - valeur d'`ip_forward` ? - -1. Dans quel langage InfluxDB a-t-il été écrit ? Quelle est la particularité - des binaires générés par ce langage ? - -1. Quels sont les avantages et les inconvénients associés au linkage statique - et au linkage dynamique ? (pas forcément que dans le cadre de la - virtualisation légère). - -1. J'ai utilisé la méthode *Virtual Ethernet* pour relier mes conteneurs à - Internet, via l'interface `br0`. Quelle(s) règle(s) `iptables` devrais-je - écrire sur mon hôte afin de permettre l'accès à InfluxDB depuis une autre - machine ? diff --git a/tutorial/3/namespaces.md b/tutorial/3/namespaces.md deleted file mode 100644 index 32092d9..0000000 --- a/tutorial/3/namespaces.md +++ /dev/null @@ -1,133 +0,0 @@ -\newpage - -# Utiliser les *namespaces* - -## Comparaison de *namespace* - -Écrivez un script ou un programme, `cmpns`, dans le langage courant de votre -choix, permettant de déterminer si deux programmes s'exécutent dans les mêmes -*namespaces*. - -### Exemples - -```sh -42sh$ cmpns $(pgrep influxdb) $(pgrep init) - - ipc: differ - - mnt: differ - - net: differ - - pid: differ - - user: same - - uts: same -``` - -```sh -42sh$ cmpns $(pgrep init) self - - ipc: same - - mnt: same - - net: same - - pid: same - - user: same - - uts: same -``` - -Ici, `self` fait référence au processus actuellement exécuté. - - -## Rejoindre un *namespace* - -Dans le langage courant de votre choix, écrivez un programme : `setns`, -permettant, à la manière de `unshare(1)` et `unshare(2)`, d'utiliser `setns(2)` -via votre interpréteur. - -Les options attendues sont : - -* rejoindre un *namespace* IPC : `-i`, `--ipc` ; -* rejoindre un *namespace* mount : `-m`, `--mount` ; -* rejoindre un *namespace* net : `-n`, `--net` ; -* rejoindre un *namespace* PID : `-p`, `--pid` ; -* rejoindre un *namespace* UTS : `-u`, `--uts` ; -* rejoindre un *namespace* user : `-U`, `--user`. - -### Exemples - -```sh -42sh# setns /bin/bash -bash# _ -``` - -#### IPC and PID Namespaces - -```sh -42sh# setns --ipc=/proc/42/ns/ipc -p /proc/42/ns/pid /bin/echo toto -toto -``` - -#### Net Namespace - -```sh -42sh# setns --net=/proc/42/ns/net ip a -1: lo: mtu 65536 qdisc noqueue state UNKNOWN group default - link/loopback 00:00:00:00:00:00 brd 00:00:00:00::00 - inet 127.0.0.1/8 brd 127.255.255.255 scope lo - valid_lft forever preferred_lft - inet6 ::1/128 scope host - valid_lft forever preferred_lft forever -``` - -#### UTS Namespace - -```sh -42sh# hostname --fqdn -koala.zoo.paris -42sh# setns --uts=/proc/42/ns/uts hostname --fqdn -lynx.zoo.paris -``` - - -## My Little Container - -En utilisant le langage courant de votre choix, concevez l'exécutable `mlc`, -permettant de lancer une application dans un environnement différent (comme un -`chroot`, mais sans permettre de s'en échapper) et avec des privilèges réduits. - -Votre solution doit créer au moins un nouveau *namespace* mount et PID. - -Vous aurez sans doute besoin de : `clone(2)`, `capabilities(7)`, `capset(2)`, `pivot_root(2)`, - -### Exemples - -```sh -42sh# ls newroot -bin etc home usr root proc var - -42sh# mlc newroot/ /bin/bash - bash# ls ../../../ - bin etc home usr root proc var - - bash# escape_chroot ls - bin etc home usr root proc var - - bash# ls -ld /proc/[0-9]* | wc -l - 2 - - bash# curl http://www.linuxcontainers.org/ | md5sum - 0123456789abcdef - - bash# ping 8.8.8.8 - Operation not permitted -``` - - -## Rendu - -Pour chaque exercice de cette partie, vous pouvez rendre un seul fichier s'il -s'agit d'un script ; sinon, vous devez rendre une tarball contenant un -`Makefile` permettant de générer les éventuels exécutables et/ou un `README` -expliquant comment s'en servir. - -Vous devez donc rendre 3 fichiers : `cmpns` ou `cmpns.tar.bz2`, `setns` ou -`setns.tar.bz2` et `mlc` ou `mlc.tar.bz2`. - -\vspace{3em} - -Bon courage ! diff --git a/tutorial/3/project.md b/tutorial/3/project.md index 14a2972..c01f178 100644 --- a/tutorial/3/project.md +++ b/tutorial/3/project.md @@ -5,6 +5,9 @@ Projet et rendu ## Sujet +**Ce projet, étalé sur ce TP et le TP suivant, constitue le cœur de la notation + de ce cours.** + Vous allez commencer aujourd'hui un projet qui s'étendra au prochain TP et qui consistera à réaliser la partie d'isolation de la moulinette des ACUs ! @@ -26,36 +29,82 @@ principalement question de faire des appels système. ### Stage 1 : Restreindre l'environnement -Après avoir mis en place les bases de votre programme, +Après avoir mis en place les bases de votre programme, commencez par créer les +différentes hiérarchies (si vous avez un noyau récent, vous pouvez les +cgroups-v2) dont vous allez avoir besoin pour limiter l'utilisation de +ressources. + +Puis, mettez en place ces limites : + +* pas plus d'1 GB de mémoire utilisée ; +* 1 seul CPU au maximum ; +* ... -### Stage 2 : Réduire les capabilities +### Stage 2 : Réduire les *capabilities* + +Réduisez au maximum les capabilities, de telle sorte qu'il ne soit pas possible +de faire un ping dans l'environnement restreint : + +```shell +42sh# ping 8.8.8.8 +PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data. +64 bytes from 8.8.8.8: icmp_seq=1 ttl=56 time=3.93 ms +64 bytes from 8.8.8.8: icmp_seq=2 ttl=56 time=3.97 ms +^C +--- 8.8.8.8 ping statistics --- +2 packets transmitted, 2 received, 0% packet loss, time 1002ms +rtt min/avg/max/mdev = 3.931/3.954/3.978/0.067 ms + +42sh# ./mymoulette /bin/bash + bash# curl http://www.linuxcontainers.org/ | md5sum + 59e714c4331e71ac3529a6502994ef1d + + bash# ping 8.8.8.8 + Operation not permitted +``` + +Astuces : `prctl(2)`, `capabilities(7)`, `capget(2)`, `capset(2)`, ... -### Stage 3 : Script d'initialisation +### Stage 3 : Utilisable par un utilisateur + +Jouez avec les attributs étendus pour qu'un utilisateur non-privilégié puisse +exécuter votre moulinette. Ajouter la/les commande(s) à votre Makefile ou +script d'installation. -### Stage 4 : Utilisable par un utilisateur +### Création d'un environnement d'exécution minimal -Une autre solution +Plutôt que d'utiliser votre système hôte au complet, avec tous ses programmes +et toutes ses bibliothèques, il faudrait utiliser un système contenant le +strict minimum. Recréez un environnement minimaliste, comme on a pu en voir +dans la partie sur les *chroot*. + +**Ne rendez pas cet environnement, il vous sera seulement utile pour faire des + tests.** -### Stage 5 : Création de l'environnement d'exécution - -Plutôt que d'utiliser votre système hôte complet, il faudrait utiliser un -système contenant le struct minimum. - - -### Stage 6 : Isolation du pauvre +### Stage 4 : Isolation du pauvre Nous n'avons pas encore vu de meilleure méthode pour mieux isoler l'environnement que de faire un `chroot`, ajouter à votre programme cette -isolation rudimentaire. +isolation rudimentaire. Et rendez-vous au prochain cours pour avoir de +moyen d'isolation ! -### Stage 7 (bonus) : automatisation de l'environnement +### Stage 5 (bonus) : automatisation de la création de l'environnement -LVM +Pour moulinéter plusieurs étudiants en parallèle, vous allez avoir besoin de +plusieurs environnements identiques. Plutôt que de recopier cet environnement, +de le nettoyer, de le recréer, pour chaque étudiant, ajoutez à votre moulinette +un support pour LVM : utiliser des *snapshots* pour figer votre environnement +et le dupliquer facilement pour chaque étudiant. + +L'usage est laissé à votre discrétion : vous pouvez ajouter un/des paramètres à +votre moulette pour indiquer le volume LVM à utiliser ou le définir en dur ou +encore séparer la création de l'environnement et de la snapshot initiale dans +un programme distinct. ## Modalité de rendu @@ -82,8 +131,12 @@ Voici une arborescence type: ``` login_x-TP3/questions.txt -login_x-TP3/ +login_x-TP3/chroot/escape.c +login_x-TP3/pseudofs/rev_kdb_leds.sh +login_x-TP3/pseudofs/procinfo +login_x-TP3/caps/view_caps +login_x-TP3/cgroups/monitor +login_x-TP3/cgroups/monitor_init +login_x-TP3/mymoulette/README +login_x-TP3/mymoulette/... ``` - - -## Astuces diff --git a/tutorial/3/pseudofs.md b/tutorial/3/pseudofs.md index 13c8f25..933d8a9 100644 --- a/tutorial/3/pseudofs.md +++ b/tutorial/3/pseudofs.md @@ -53,6 +53,32 @@ exemple, pour modifier les paramètres du noyau, on passe par le fichier ## Exercice +### `rev_kdb_leds.sh` + +Explorons le pseudo système de fichiers `/sys` pour écrire un script +qui va inverser l'état des diodes de notre clavier. + +Si vous avez : + +* numlock On, +* capslock Off, +* scrolllock Off ; + +Après avoir exécuté le script, nous devrions avoir : + +* numlock Off, +* capslock On, +* scrolllock On. + +Voici un exemple d'utilisation : + +```shell +42sh$ ./rev_kdb_leds.sh input20 +``` + + +### `procinfo` + Explorons le pseudo système de fichiers `/proc` pour écrire un script qui va afficher des informations sur un processus donné : @@ -60,7 +86,7 @@ afficher des informations sur un processus donné : 42sh$ ./procinfo $$ PID: 4242 Path: /bin/bash -Arguments: +Command line: bash Working directory: /home/nemunaire/virli/ Root: / State: S (sleeping) @@ -83,11 +109,18 @@ CGroups Namespaces ========== -cgroup -> cgroup:[4026531835] -ipc -> ipc:[4026531839] -mnt -> mnt:[4026531840] -net -> net:[4026531969] -pid -> pid:[4026531836] -user -> user:[4026531837] -uts -> uts:[4026531838] +cgroup:[4026531835] +ipc:[4026531839] +mnt:[4026531840] +net:[4026531969] +pid:[4026531836] +user:[4026531837] +uts:[4026531838] ``` + + +## Rendu + +### Fichiers + +Rendez vos scripts `rev_kdb_leds.sh` et `procinfo`. diff --git a/tutorial/4/cgroups.md b/tutorial/4/cgroups.md deleted file mode 100644 index 3be710b..0000000 --- a/tutorial/4/cgroups.md +++ /dev/null @@ -1,195 +0,0 @@ -\newpage - -# Utiliser les *cgroup*s - -Les *cgroup*s (pour *Control Group*s) permettent de collecter des statistiques -sur des groupes de processus (appelés tâches) et de leur attribuer des -propriétés, comme par exemple pour leur imposer des limitations d'utilisation -de ressources ou altérer leurs priorités. - - -## Premiers tests - -Nous allons commencer par faire quelques tests avec le *cgroup* freezer, qui -permet d'interrompre l'exécution d'un groupe de processus et de la reprendre. - -### Montage du *cgroup* - -En fonction de la configuration de votre système, il est possible que les -*cgroup*s ne soient pas montés au démarrage dans `/sys/fs/cgroup/`. Si vous n'avez -pas de dossier `freezer` ou si celui-ci est vide, monter-le en suivant la -procédure suivante : - -``` -mkdir /sys/fs/cgroup/freezer/ -mount -t cgroup -o freezer none /sys/fs/cgroup/freezer/ -``` - -Cette dernière commande monte le groupe de processus racine, pour le *cgroup* -freezer. Tous les dossiers contenu dans cette racine sont des sous-groupes de -cette dernière. - -### Création d'un nouveau groupe - -La première étape dans l'utilisation d'un *cgroup* est de créer un nouveau -groupe. - -Pour créer un groupe, il suffit de créer un nouveau dossier dans un groupe -existant, par exemple la racine : - -``` -mkdir /sys/fs/cgroup/freezer/virli/ -ls /sys/fs/cgroup/freezer/virli/ -``` - -Vous avez maintenant un nouveau groupe de processus `virli` dans le *cgroup* -Freezer. Comme il s'agit d'une hiérarchie, le groupe `virli` hérite des -propriétés de son (ses) père(s). - -### Rattachement de processus - -Pour le moment, ce nouveau groupe ne contient aucune tâche. - -Ouvrons un nouveau terminal (c'est lui que l'on va freezer), et récupérons son -PID : `echo $$`. - -La liste des processus rattachés à un *cgroup* se trouve dans le fichier `task` -du groupe. Pour ajouter une tâche à ce groupe, cela se passe de cette manière : - -``` -echo $PID > /sys/fs/cgroup/freezer/virli/tasks -``` - -Il faut ici remplacer `$PID` par le PID du shell que l'on a relevé juste avant. - -En validant cette commande, vous avez déplacé le processus dans ce groupe, il -n'est alors plus dans aucun autre groupe (dans ce *cgroup*, il ne bouge pas -dans les autres *cgroup*s). - -### Consultation de l'état - -En affichant le contenu du dossier `virli`, nous avons pu constater que -celui-ci contenait déjà un certain nombre de fichiers. Certain d'entre-eux sont -en lecture seule et permettent de lire des statistiques instantanées sur le -groupe ; tandis que d'autres sont des propriétés que vous pouvez modifier. - -Nous pouvons consulter l'état de gel du groupe en affichant le contenu du -fichier\newline `/sys/fs/cgroup/freezer/virli/freezer.state`. - -Pour plus d'information sur les différents fichiers présents dans ce *cgroup*, -consulter la documentation, accessible ici : - - -### Changement d'état - -Faisons exécuter à notre interpréteur une commande pour voir effectivement -l'exécution s'arrêter. Si vous manquez d'inspiration, utilisez : - -``` -for i in $(seq 9999); do echo -n $i; sleep .1; echo -n " - "; sleep .1; done -``` - -Maintenant, nous avons donné l'ordre au noyau de ne plus allouer de temps de -calcul à notre shell et ses fils : - -``` -echo FROZEN > /sys/fs/cgroup/freezer/virli/freezer.state -``` - -À cet instant, vous devriez voir votre compteur s'arrêter. Pour reprendre -l'exécution : - -``` -echo THAWED > /sys/fs/cgroup/freezer/virli/freezer.state -``` - - -## Script de monitoring - -À nous maintenant de concevoir un script qui va enregistrer vers la base de -données créée (*metrics*) dans la partie précédente, des statistiques issues -des *cgroup*s. - -### Monitoring instantané vers la console - -Dans un premier temps, commençons par afficher dans la console la quantité de -mémoire utilisée par le groupe monitoré. - -* Arguments de la ligne de commande : - - premier fils à lancer dans le groupe, - - intervalle de temps entre deux rafraîchissement ; -* *cgroup* `memory`; -* `memory.usage_in_bytes`. - -Vous pouvez utiliser un programme comme `memhog` pour remplir rapidement votre -mémoire. - -Si vous n'avez pas le *cgroup* memory, il est possible qu'il ne soit -pas activé par défaut par votre système. Si vous êtes dans ce cas, essayez d'ajouter - -``` -cgroup_enable=memory -``` - -### Monitoring vers InfluxDB - -Maintenant, envoyons nos données vers la base - : - -``` -curl -i -XPOST 'http://172.23.42.2:8086/write?db=metrics' --data-binary \ - "$my_cgroup_name memory.usage_in_bytes=$(cat .../my_cgroup_name/memory.usage_in_bytes)" -``` - -Pour vérifier que les données sont bien ajoutées, vous pouvez effectuez la -requête suivante dans l'interface web d'InfluxDB : - -``` -SELECT * from "$my_cgroup_name"; -``` - -### Monitorer davantage de données - -Liste non exhaustive de données à monitorer : - -* Nombre d'IOs effectué ; -* nombre d'octets lu/écrit sur les disques ; -* temps de calcul utilisé ; -* trafic réseau généré ; -* ... - - - -### Permettre à l'utilisateur de monitorer des process - -Maintenant, séparer votre script en deux parties afin qu'un utilisateur normal -(non-root) puisse utiliser la partie monitoring de notre script. - -Un premier script doit s'occuper de créer le(s) *cgroup*s et lui attribuer les -bons droits, tandis que le deuxième va utiliser effectuer le monitoring, sans - -#### Exemple - -``` -42sh# ./monitor_init my_cgroup_name -42sh$ ./monitor my_cgroup_name memhog 500 -``` - - -## Rendu - -### Script de monitoring - -Rendez la révision la plus avancée de vos scripts de monitoring de process via -les *cgroup*s. - -### Questions - -1. Un même processus peut-il être dans plusieurs *cgroup*s de type différents - (freezer et cpuacct par exemple) ? - -1. Que sera-t-il possible de limiter via un nouveau *cgroup* dans la prochaine - version du noyau (4.3) ? - -1. Actuellement, comment peut-on limiter le nombre de processus lancés par un - utilisateur ou un groupe ? diff --git a/tutorial/4/installation.md b/tutorial/4/installation.md deleted file mode 100644 index 6b64372..0000000 --- a/tutorial/4/installation.md +++ /dev/null @@ -1,55 +0,0 @@ -\newpage - -# Installation - -## Noyau Linux - -Ce TP requiert un noyau Linux 3.8 au minimum. De plus, il doit être -compilé avec les options suivantes : - -``` -General setup ---> - [*] Control Group support ---> - [*] Freezer cgroup subsystem - [*] Device controller for cgroups - [*] Cpuset support - [*] Include legacy /proc//cpuset file - [*] Simple CPU accounting cgroup subsystem - [*] Group CPU scheduler ---> - [*] Group scheduling for SCHED_OTHER - [*] Group scheduling for SCHED_RR/FIFO - <*> Block IO controller - -*- Namespaces support - [*] UTS namespace - [*] IPC namespace - [*] User namespace - [*] PID Namespaces - [*] Network namespace -[*] Networking support ---> - Networking options ---> - <*> 802.1d Ethernet Bridging - 802.1Q VLAN Support - [*] Network priority cgroup - [*] Network classid cgroup -Device Drivers ---> - [*] Network device support ---> - MAC-VLAN support - <*> Virtual ethernet pair device - Character devices ---> - -*- Unix98 PTY support - [*] Support multiple instances of devpts -``` - -Une fois que vous aurez installé LXC, vous pouvez vérifier la compatibilité de -la configuration de votre noyau en utilisant la commande `lxc-checkconfig`. - - -## LXC - -Pour installer LXC, utilisez le gestionnaire de paquets de votre -distribution. Toute les bonnes distributions fournissent un paquet -`lxc`. Vérifiez que la version installée est au moins la 1.0. - -Aucune configuration ne devrait vous être demandé durant l'installation. Une -fois installé, exécutez la commande `lxc-checkconfig` pour vérifier que votre -noyau possède bien toutes les options nécessaires.