Il s'agit d'un simple outil poussé à partir du simple fait que su
et sudo
ont un comportement TTY et Signal Forwing très étrange et souvent ennuyeux. Ils sont également quelque peu complexes à configurer et à utiliser (en particulier dans le cas du sudo
), ce qui permet une grande expressivité, mais tombe à plat si tout ce dont vous avez besoin est de "exécuter cette application spécifique en tant qu'utilisateur spécifique et sortir de la pipeline".
Le cœur du fonctionnement gosu
est volé directement dans la façon dont Docker / LibContainer lui-même démarre une application dans un conteneur (et en fait, utilise le code de traitement /etc/passwd
directement à partir de la base de code de LibContainer).
$ gosu
Usage: ./gosu user-spec command [args]
eg: ./gosu tianon bash
./gosu nobody:root bash -c 'whoami && id'
./gosu 1000:1 id
./gosu version: 1.1 (go1.3.1 on linux/amd64; gc)
Une fois l'utilisateur / groupe traité, nous passons à cet utilisateur, nous exec
le processus spécifié et gosu
lui-même n'est plus résident ou impliqué dans le cycle de vie du processus. Cela évite tous les problèmes de passage du signal et de TTY, et les attache au processus invoquant gosu
et le processus invoqué par gosu
, où ils appartiennent.
Le cas d'utilisation de base pour gosu
est de passer de root
à un utilisateur non priviaire pendant le démarrage du conteneur (en particulier au ENTRYPOINT
, généralement).
Les utilisations de gosu
au-delà pourraient très bien souffrir de vulnérabilités telles que CVE-2016-2779 (à partir de laquelle le cas d'utilisation de Docker nous protège naturellement); Voir tianon/gosu#37
pour une discussion sur ce point.
Étapes de haut niveau:
gosu-$(dpkg --print-architecture | awk -F- '{ print $NF }')
comme gosu
gosu-$(dpkg --print-architecture | awk -F- '{ print $NF }').asc
as gosu.asc
gpg --batch --keyserver hkps://keys.openpgp.org --recv-keys B42F6819007F00F88E364FD4036A9C25BF357DD4
gpg --batch --verify gosu.asc gosu
chmod +x gosu
Pour les instructions explicites Dockerfile
, voir INSTALL.md
.
$ docker run -it --rm ubuntu:trusty su -c ' exec ps aux '
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.0 46636 2688 ? Ss+ 02:22 0:00 su -c exec ps a
root 6 0.0 0.0 15576 2220 ? Rs 02:22 0:00 ps aux
$ docker run -it --rm ubuntu:trusty sudo ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 3.0 0.0 46020 3144 ? Ss+ 02:22 0:00 sudo ps aux
root 7 0.0 0.0 15576 2172 ? R+ 02:22 0:00 ps aux
$ docker run -it --rm -v $PWD /gosu-amd64:/usr/local/bin/gosu:ro ubuntu:trusty gosu root ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.0 7140 768 ? Rs+ 02:22 0:00 ps aux
De plus, en raison du fait que gosu
utilise le code propre de Docker pour le traitement de ces user:group
, il a une parité 1: 1 exacte avec le drapeau de Docker --user
.
Si vous êtes curieux des cas de bord que gosu
gère, voir Dockerfile.test-alpine
pour la "suite de tests" (et le script test.sh
associé qui enveloppe cela pour tester les binaires arbitraires).
(Notez que sudo
a des objectifs différents de ce projet, et il n'est pas destiné à être un remplacement sudo
; par exemple, voir cette réponse de débordement de pile pour une courte explication de la raison pour laquelle sudo
fait fork
+ exec
au lieu de simplement exec
.)
chroot
Avec le drapeau --userspec
, chroot
peut offrir des avantages / comportements similaires:
$ docker run -it --rm ubuntu:trusty chroot --userspec=nobody / ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
nobody 1 5.0 0.0 7136 756 ? Rs+ 17:04 0:00 ps aux
setpriv
Disponible dans util-linux
plus récent ( >= 2.32.1-0.2
, dans Debian; https://manpages.debian.org/buster/util-inux/setpriv.1.en.html):
$ docker run -it --rm buildpack-deps:buster-scm setpriv --reuid=nobody --regid=nogroup --init-groups ps faux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
nobody 1 5.0 0.0 9592 1252 pts/0 RNs+ 23:21 0:00 ps faux
su-exec
Dans l'écosystème alpin Linux, su-exec
est une réécriture minimale de gosu
en C, ce qui rend un binaire beaucoup plus petit et est disponible dans le référentiel de package alpin main
. Cependant, à partir de la version 0.2, il dispose d'un bug d'analyseur assez sévère qui n'a pas été dans une version depuis de nombreuses années (et quel comportement buggy est que les fautes de frappe conduisent à l'exécution du code comme root de façon inattendue?).
Je ne les connais pas très bien, mais quelques autres alternatives que je connais incluent:
chpst
(partie de runit
)