Aller au contenu
  1. Notes/

TIL : le mapping d'UID derrière Podman rootless

·4 mins
Ixonae
Auteur
Ixonae

Avertissement : Cet article a été traduit de l’anglais par un LLM. La précision n’est pas garantie. Vous pouvez lire l’article original en anglais.

Cela fait un bon moment que j’utilise Podman en mode rootless. Au début, l’une des choses qui m’ont surpris était de voir certains volumes montés sur mon système de fichiers appartenir à des UID étranges, qui n’existaient pas sur mon système Linux.

Il s’avère que cela est dû aux fonctionnalités de user namespace de Linux. Plus précisément, aux subuid et aux subgid.

Mais de quoi s’agit-il ? En gros, lorsqu’on exécute un conteneur rootless, on veut quand même que ce qui s’exécute à l’intérieur du conteneur se considère comme root, mais sans utiliser l’UID 0, l’UID root du système, afin d’ajouter une couche de sécurité en cas d’évasion du conteneur.

On veut également que le conteneur puisse représenter plusieurs utilisateurs. Un conteneur peut avoir son propre root, ses propres comptes de service, ses propres utilisateurs applicatifs et ses propres groupes. Les plages d’UID et de GID subordonnées permettent à ces identités internes de correspondre à des ID non privilégiés distincts sur l’hôte, plutôt que de tout ramener à l’utilisateur qui exécute le conteneur.

Pour permettre cela, le système crée des mappings dans /etc/subuid et /etc/subgid. Ces fichiers ressemblent à ceci :

$ cat /etc/subuid
ixonae:100000:65536
user2:165536:65536
$ cat /etc/subgid
ixonae:100000:65536
user2:165536:65536

Le premier nombre indique le début du mapping d’UID, et le second le nombre de sous-ID qui peuvent être créés. Pour une plage subordonnée contiguë simple, le mapping est uid_hôte = début_subuid + uid_conteneur. Par exemple, root correspondrait à 100000 sur le système hôte, et si un utilisateur est créé dans Podman avec l’ID 1000, il correspondra à 101000 sur le système hôte.

Ainsi, sur le système hôte, ce qui s’exécute depuis Podman reste non privilégié, tandis qu’à l’intérieur du conteneur, cela peut s’exécuter comme si c’était privilégié.

D’où vient 65536, me direz-vous ? Sur de nombreux systèmes, cette valeur par défaut est définie dans /etc/login.defs. Plus précisément : SUB_UID_MIN, SUB_UID_MAX, SUB_UID_COUNT. Vous remarquerez que ce fichier définit également UID_MIN et UID_MAX, utilisés par useradd. Les plages par défaut sont généralement fixées de façon à éviter tout chevauchement avec les ID d’utilisateurs classiques.

Lors de l’exécution de commandes et de conteneurs Podman rootless, les utilitaires newuidmap et newgidmap sont appelés pour initialiser le user namespace et aider à écrire le fichier /proc/<pid>/uid_map, qui sera ensuite utilisé par le noyau pour la gestion des permissions et tout ce qui touche aux ID d’utilisateurs.

On peut observer ces permissions comme suit :

# Les trois colonnes affichées par la commande ci-dessous sont :
#  - l'ID à l'intérieur du user namespace
#  - l'ID à l'extérieur du namespace
#  - la longueur du mapping.
[user2@myhost ~]$ podman unshare cat /proc/self/uid_map
         0       1001          1
         1     165536      65536
$ id user2
uid=1001(user2) gid=1001(user2) groups=1001(user2)
$ cat /etc/subuid | grep user2
user2:165536:65536

Notez que dans ce cas, le root du conteneur correspond à l’utilisateur qui exécute Podman sur l’hôte. Tous les autres utilisateurs seront liés à un subuid. C’est le comportement par défaut de Podman, mais il peut être modifié.

Par exemple, comme ceci si vous utilisez Podman Compose :

services:
  app:
    userns_mode: auto # par défaut : "" (non défini)

Notez que changer ce comportement nécessitera un remapping des permissions. Utiliser :U sur les chemins montés dans un fichier Podman Compose peut s’en charger automatiquement.

Quelques commandes utiles à ce sujet :

  • getsubids user2 renvoie le contenu du fichier subuid pour cet utilisateur
  • podman system migrate s’assure que les mappings de conteneurs concernés sont mis à jour si le fichier subuid de l’utilisateur venait à changer
  • podman unshare [votre commande] permet d’exécuter une commande dans le même user namespace que Podman, vous donnant ainsi accès aux fichiers qui n’appartiennent pas à l’utilisateur hôte

Ressources supplémentaires