GNU/Linux >> Tutoriels Linux >  >> Linux

Pourquoi Podman sans racine ne peut-il pas extraire mon image ?

L'une des nouvelles fonctionnalités les plus intéressantes de Podman est les conteneurs sans racine. Rootless permet à presque tous les conteneurs d'être exécutés en tant qu'utilisateur normal, sans privilèges élevés et avec des avantages de sécurité majeurs. Cependant, l'exécution de conteneurs sans privilèges root s'accompagne de limitations.

Un utilisateur a posé une question à propos de l'un d'entre eux :pourquoi n'ont-ils pas pu extraire une image spécifique avec Podman sans racine ?

Leur image lançait des erreurs après le téléchargement, comme celle ci-dessous :

ERRO[0005] Error pulling image ref //testimg:latest: Error committing the finished image: error adding layer with blob "sha256:caed8f108bf6721dc2709407ecad964c83a31c8008a6a21826aa4ab995df5502": Error processing tar file(exit status 1): there might not be enough IDs available in the namespace (requested 4000000:4000000 for /testfile): lchown /testfile: invalid argument

J'ai expliqué que leur problème était que leur image avait des fichiers appartenant à des UID supérieurs à 65536. En raison de ce problème, l'image ne rentrerait pas dans le mappage UID par défaut de Podman sans racine, ce qui limite le nombre d'UID et de GID disponibles.

Les questions de suivi étaient, naturellement :

  • Pourquoi cette limitation existe-t-elle ?
  • Pourquoi ne pouvez-vous pas utiliser une image qui fonctionne sur un Podman normal en mode sans racine ?
  • Pourquoi les UID et GID exacts utilisés sont-ils importants ?

Je commencerai par expliquer pourquoi nous devons utiliser des UID et des GID différents de ceux de l'hôte, puis j'expliquerai pourquoi la valeur par défaut est 65536 et comment modifier ce nombre.

Mapper l'espace de noms de l'utilisateur

Les conteneurs sans racine s'exécutent à l'intérieur d'un espace de noms d'utilisateur , qui est un moyen de mapper les utilisateurs et les groupes de l'hôte dans le conteneur. Par défaut, nous mappons l'utilisateur qui a lancé Podman en tant qu'UID/GID 0 dans les conteneurs sans racine.

Sur mon système, mon utilisateur (mheon ) est UID 1000. Lorsque je lance un conteneur sans racine en tant que mheon avec podman run -t -i --rm fedora bash , puis exécutez top à l'intérieur du conteneur, je semble être l'UID 0—root.

Cependant, sur l'hôte, le bash Le processus appartient toujours à mon utilisateur. Vous pouvez voir ce résultat lorsque j'exécute podman top sur mon système hôte :

mheon@Agincourt code/podman.io (release_blog_1.5.0)$ podman top -l user group huser hgroup

USER GROUP HUSER HGROUP

root root 1000 1000

Le USER et GROUP les options sont l'utilisateur et le groupe tels qu'ils apparaissent dans le conteneur , tandis que le HUSER et HGROUP les options sont l'utilisateur et le groupe tels qu'ils apparaissent sur l'hôte .

Montrons un exemple simple. Je vais monter /etc/ , qui contient plein de fichiers appartenant à root, dans un conteneur sans racine. Ensuite, je montrerai son contenu avec ls :

mheon@Agincourt code/libpod (master)$ podman run -t -i -v /etc/:/testdir --rm fedora sh -c 'ls -l /testdir 2> /dev/null | head -n 10'

total 1700

-rw-r--r--. 1 nobody nobody 4664 May 3 14:39 DIR_COLORS

-rw-r--r--. 1 nobody nobody 5342 May 3 14:39 DIR_COLORS.256color

Je n'ai pas la permission de modifier ces fichiers, malgré le fait que je sois root dans le conteneur. Je ne peux même pas en voir beaucoup :notez le 2> /dev/null après ls pour écraser les erreurs car j'obtiens de nombreuses erreurs d'autorisation même en essayant de les répertorier.

Sur l'hôte, ces fichiers appartiennent à root, UID 0, mais dans le conteneur, ils appartiennent à nobody . C'est un nom spécial que le noyau Linux utilise pour dire que l'utilisateur qui possède réellement les fichiers n'est pas présent dans l'espace de noms de l'utilisateur. UID et GID 0 sur l'hôte ne sont pas mappés dans le conteneur, donc au lieu que les fichiers appartiennent à 0:0 , ils appartiennent à nobody:nobody du point de vue du conteneur.

Quel que soit l'utilisateur que vous semblez être dans un conteneur sans racine, vous agissez toujours comme votre propre utilisateur et vous ne pouvez accéder qu'aux fichiers auxquels votre utilisateur sur l'hôte peut accéder. Cette configuration est une grande partie de l'attrait des conteneurs sans racine pour la sécurité :même si un attaquant peut sortir d'un conteneur, il est toujours confiné à un compte d'utilisateur non root.

Allocation d'UID/GID supplémentaires

J'ai dit plus tôt qu'un espace de noms d'utilisateur mappe les utilisateurs sur l'hôte en utilisateurs dans le conteneur, et j'ai décrit un peu comment ce processus fonctionne pour root dans le conteneur. Mais les conteneurs ont généralement des utilisateurs autres que root, ce qui signifie que Podman doit mapper des UID supplémentaires pour permettre aux utilisateurs un et au-dessus d'exister dans le conteneur.

En d'autres termes, tout utilisateur requis par le conteneur doit être mappé. Ce problème a provoqué l'erreur d'origine ci-dessus, car l'image utilisait un UID/GID qui n'était pas défini dans son espace de noms d'utilisateur.

Le newuidmap et newgidmap exécutables, généralement fournis par les shadow-utils ou uidmap packages, sont utilisés pour mapper ces UID et GID dans l'espace de noms d'utilisateur du conteneur. Ces outils lisent les mappages définis dans /etc/subuid et /etc/subgid et utilisez-les pour créer des espaces de noms d'utilisateurs dans le conteneur. Ces setuid les binaires utilisent des privilèges supplémentaires pour donner à nos conteneurs sans racine l'accès à des UID et GID supplémentaires, ce pour quoi nous n'avons normalement pas l'autorisation. Chaque utilisateur exécutant Podman sans racine doit avoir une entrée dans ces fichiers s'il doit exécuter des conteneurs avec plusieurs UID. Chaque conteneur utilise tous les UID disponibles par défaut, bien que les mappages exacts puissent être ajustés avec --uidmap et --gidmap .

Un utilisateur normal et non root sous Linux n'a généralement accès qu'à son propre utilisateur - un UID. L'utilisation des UID et GID supplémentaires dans un conteneur sans racine vous permet d'agir en tant qu'utilisateur différent, ce qui nécessite normalement des privilèges root (ou de vous connecter en tant qu'autre utilisateur avec son mot de passe). Les exécutables de mappage newuidmap et newgidmap utiliser leurs privilèges élevés pour nous accorder l'accès à des UID et GID supplémentaires selon les mappages configurés dans /etc/subuid et /etc/subgid sans être root ou avoir la permission de se connecter en tant qu'utilisateurs.

Chaque utilisateur exécutant Podman sans racine doit avoir une entrée dans ces fichiers s'il doit exécuter des conteneurs contenant plusieurs UID.

Modification du nombre d'ID par défaut

Passons maintenant à la question du nombre par défaut d'UID et de GID disponibles dans un conteneur :65536. Ce nombre n'est pas une limite stricte et peut être ajusté à la hausse ou à la baisse à l'aide du /etc/subuid susmentionné. et /etc/subgid fichiers.

Par exemple, sur mon système :

mheon@Agincourt code/libpod (master)$ cat /etc/subuid
mheon:100000:65536

Ce fichier est au format <username>:<start_uid>:<size> , où start_uid est le premier UID ou GID disponible pour l'utilisateur, et size est le nombre d'UID/GID disponibles (en commençant par start_uid , et se terminant à start_uid + size - 1 ).

Si je devais remplacer ce 65536 par, disons, 123456, j'aurais 123456 UID disponibles dans mes conteneurs sans racine.

"Pourquoi choisir 65536 par défaut ?" est une question pour les mainteneurs de l'outil de création d'utilisateur Linux, useradd , car les valeurs par défaut initiales sont renseignées lors de la création d'un utilisateur, et non par Podman. Cependant, je risquerai de supposer que ce paramètre est suffisant pour que la plupart des applications fonctionnent sans modifications (les très anciennes versions de Linux n'avaient que des UID/GID 16 bits, et des valeurs plus élevées sont encore quelque peu rares).

Remarque : Le /etc/subuid et /etc/subgid les fichiers sont destinés à ajuster les utilisateurs qui existent déjà. Les valeurs par défaut pour les nouveaux utilisateurs sont ajustées ailleurs.

La valeur par défaut 65536 que les nouveaux utilisateurs reçoivent n'est pas codée en dur. Cependant, cela n'affectera pas les utilisateurs existants. Il est défini dans le /etc/login.defs fichier, avec le SUB_UID_COUNT et SUB_GID_COUNT options. Nous avons en fait eu des discussions sur la baisse de la valeur par défaut, car il semble que la plupart des conteneurs fonctionneront probablement correctement avec un peu plus de 1 000 UID/GID, et plus après cela, ils seront perdus.

L'important est que cette valeur représente un ensemble d'UID/GID alloués sur l'hôte qui sont disponibles pour un utilisateur spécifique pour exécuter des conteneurs sans racine. Si je devais ajouter un autre utilisateur à ce système, il obtiendrait une autre série d'UID, commençant probablement à 165536, encore 65536 de large par défaut.

Root a les autorisations pour modifier ces limites, mais pas les utilisateurs normaux. Sinon, je pourrais changer un peu le mappage en mheon:0:65536 et mapper le véritable utilisateur root sur le système dans mes conteneurs sans racine, qui peuvent ensuite facilement être pivotés vers un accès root à l'échelle du système.

Éviter le chevauchement d'UID et de GID

En règle générale, pour des raisons de sécurité, évitez de laisser des UID/GID système (généralement numérotés en dessous de 1000), et idéalement tout UID/GID utilisé sur le système hôte, dans un conteneur. Cette pratique empêche les utilisateurs d'accéder aux fichiers système sur l'hôte lorsqu'ils créent des conteneurs sans racine.

Nous souhaitons également que chaque utilisateur dispose d'une plage unique d'UID/GID par rapport aux autres utilisateurs. Je pourrais ajouter un utilisateur alice à mon /etc/subuid avec exactement le même mappage que mon utilisateur (alice:100000:65536 ), mais alors Alice aurait accès à mes conteneurs sans racine, et moi aux siens.

Il est possible d'augmenter la taille de l'allocation de votre utilisateur, comme indiqué précédemment, mais vous devez suivre ces règles de sécurité. Je vais les énumérer à nouveau :

  • Aucun UID/GID inférieur à 1 000.
  • Aucun UID ou GID n'entre dans le conteneur s'il est utilisé sur l'hôte.
  • Ne chevauchez pas les mappages entre les utilisateurs.

La dernière est la principale raison pour laquelle nous ne voulons pas mapper dans des allocations UID et GID plus élevées. Nous pourrions potentiellement donner à un utilisateur une plage massive, allant de 100 000 à UID_MAX , et rendre un peu plus de 4,2 millions d'UID disponibles, mais il n'en restera plus pour les autres utilisateurs.

Conclusion

Avec Podman 1.5.0 et supérieur, nous avons ajouté une nouvelle option expérimentale (--storage-opt ignore_chown_errors ) pour écraser tous les UID et GID, exécutant ainsi les conteneurs en tant qu'utilisateur unique (l'utilisateur qui a lancé le conteneur). Ce paramètre résout le problème initial de l'article, mais il impose un ensemble de restrictions supplémentaires sur le conteneur. Il est préférable de laisser les détails à un autre article.

Les restrictions UID et GID placées sur les conteneurs sans racine peuvent être gênantes, mais vous les rencontrerez rarement. La plupart des images et des conteneurs utilisent beaucoup moins que les 65 536 UID et GID disponibles. Ces limitations sont quelques-uns des compromis des conteneurs sans racine, où nous sacrifions un peu de commodité et de convivialité pour des améliorations majeures de la sécurité.


Linux
  1. Que se passe-t-il dans les coulisses d'un conteneur Podman sans racine ?

  2. Aperçu technologique :Exécution d'un conteneur à l'intérieur d'un conteneur

  3. Utilisation de fichiers et d'appareils dans des conteneurs sans racine Podman

  4. Pourquoi setuid est-il ignoré sur les répertoires ?

  5. Quel système d'exploitation s'exécute dans mon conteneur Docker ?

Exécuter Podman sans racine en tant qu'utilisateur non root

Accélérer la création d'images de conteneurs avec Buildah

Comment Cirrus CLI utilise Podman pour réaliser des versions sans racine

Comment utiliser Podman à l'intérieur d'un conteneur

Conteneur Openldap en 4 étapes Podman Easy

1 conteneur de serveur DNS Podman sale facile