Le *namespace* `user` {#user-ns} --------------------- ### Introduction 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 super-utilisateur à partir d'un compte d'un simple utilisateur. Il nous sera alors possible d'effectuer toutes les actions privilégiées dont nous pourrions avoir besoin à l'intérieur de cet espace de noms, sans que cela ne réduise la sécurité des composants à l'extérieur de cet espace. ### Comportement vis-à-vis des autres *namespaces* Alors qu'il est normalement nécessaire d'avoir des privilèges pour créer de nouveaux espaces de noms, en commençant par demander un *namespace* 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 ; les projets [`podman`](https://podman.io/) et [Singularity](https://sylabs.io/), ... reposent en grande partie sur cela. ### Correspondance des utilisateurs et des groupes 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 au passage si besoin. #### 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 à l'utilisateur *nobody* et au groupe *nogroup*. -1 étant réservé pour indiquer une erreur dans le retour d'une commande, ou la non-modification d'un paramètre passé en argument d'une fonction. #### `uid_map` et `gid_map`\ Pour établir la correspondance, une fois que l'on a créé le nouveau *namespace*, ces deux fichiers, accessibles dans `/proc/self/`, peuvent être écrits une fois. ##### `uid_map` {-} \ Sur chaque ligne, on doit indiquer : - L'identifiant marquant le début de la plage d'utilisateurs, pour le processus en question. - L'identifiant marquant le début de la plage d'utilisateurs, pour le processus affichant le fichier. - La taille de la plage. Par exemple, le *namespace* `user` initial défini la correspondance suivante :
``` 42sh$ cat /proc/self/uid_map 0 0 4294967295 ```
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 :
``` 42sh$ cat /proc/self/uid_map 0 1000 1 ```
Dans cette situation, on comprend que notre processus considère que l'utilisateur root, dans le conteneur équivaut à l'utilisateur 1000 hors de l'espace de noms. ##### `gid_map` {-} \ Le principe est identique pour ce fichier, mais agit sur les correspondances des groupes au lieu des utilisateurs. Il y a cependant un subtilité car il faut écrire la chaîne `deny` dans le fichier `setgroups` avant de modifier `gid_map`. ### Utilisation basique de l'espace de noms Avec `unshare(1)`, voici comment, en tant que simple utilisateur, se dissocier de plusieurs *namespace*s en gardant un environnement cohérent, dans lequel on devient le super-utilisateur :
```bash 42sh$ unshare --mount --pid --mount-proc --fork --net --user \ --map-root-user bash ```
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 n'agit pas en dehors. ### Aller plus loin {-} N'hésitez pas à jeter un œil à la page du manuel consacrée à ce *namespace* : `user_namespaces(7)`.