gosu frente a sudo

Sin lugar a dudas Docker, los contenedores, es una de esas tecnologías que están revolucionando todo. De eso no tengo dudas. Y esta es una de las razones por las que cada vez le dedico mas artículos. No solo se trata de tener tus propios servios, sino que además te adentra en lo más profundo de Linux. Desde luego te permite verlo desde otro punto de vista. Sea como fuere, el crear imágenes para tus propios contenedores, tiene su encanto. No solo por lo que he comentado hasta el momento, sino porque tienes que preocuparte de pequeños detalles que es posible que hasta el momento, no hubieras caído en ellos. Por ejemplo el uso de sudo. Así surgen herramientas que hasta la fecha probablemente no se habían planteado su necesidad. Una de estas herramientas es gosu, una alternativa a sudo pero con un comportamiento mas predecible en la consola. Pero no solo, esto.

Así el objetivo de este artículo es, por un lado, mostrarte que es gosu, indicarte las posibilidades, y algunos ejemplos de uso.

gosu frente a sudo

gosu frente a sudo

En muchos de los Dockerfile que te puedes encontrar a lo largo y ancho de internet, verás que aparece la figura de USER para ejecutar un determinado comando como un usuario específico. Sin embargo, muchas de las operaciones se ejecutan como ROOT.

Así, en algunas de estos Dockerfile es posible que te encuentres la herramienta gosu para des escalar los privilegios de administración, ejecutando una determinada instrucción como un usuario sin tanto privilegio.

Sin embargo, en la guía de mejores prácticas de Docker se indica que si un proceso puede ser ejecutado sin privilegios, lo mejor es utilizar USER, para cambiar a un usuario sin derechos de administrador.

Así la recomendación general es que empieces creando un usuario y un grupo en el Dockerfile, como por ejemplo puedes ver en la siguiente instrucción,

RUN groupadd -r usuario && \
    useradd --no-log-init -r -g usuario usuario

Otra interesante recomendación, es que no solo definas un usuario y un grupo, sino que además establezcas su UID y GID. Esto es algo realmente muy interesante, y que probablemente aborde en otro artículo.

Por otro lado, en esa guía de buenas prácticas, se indica que evites instalar y utilizar sudo y en el caso de que necesites ganar derechos de administrador, utilices gosu.

La razón para esta recomendación es que sudo tiene un comportamiento impredecible respecto al TTY y esto te puede causar problemas. Así, si necesitas, por ejemplo, inicializar el demonio como root pero ejecutarlo sin derechos de administrador, ese es el momento de ejecutarlos utilizando gosu.

Otra de las recomendaciones que encontrarás en la guía, y otra de las razones para utilizar gosu es, precisamente, que recomienda seas comedido con el uso de USER. Esto es así para reducir el número y la complejidad de las capas de tu imagen.

Pero, ¿que es gosu?

gosu es una herramienta muy sencilla que viene a simplificar, o facilitar, el uso de sudo y su. Se trata de una herramienta que te permite ejecutar un comando como si fueras otro usuario.

Un interesante script para utilizar con ENTRYPOINT, un archivo entrypoint.sh, sería el siguiente,

#!/bin/bash

# Add local user
# Either use the LOCAL_USER_ID if passed in at runtime or
# fallback

USER_ID=${LOCAL_USER_ID:-9001}

echo "Starting with UID : $USER_ID"
useradd --shell /bin/bash -u $USER_ID -o -c "" -m user
export HOME=/home/user

exec gosu user "$@"

¿Que es lo que hace este script?. El primer paso es crear un usuario, con un UID como el que le indiquemos, preferiblemente el del usuario local. En el caso de que no le asignemos ninguno toma por defecto 9001.

El siguiente paso, es ejecutar nuestro proceso como ese usuario, de esta manera estaremos utilizando un usuario con un UID e incluso, si también lo definimos, con un GID conocidos, que pueden ser los de nuestro usuario local. De esta forma, los volúmenes que montes en el host serán propiedad de tu usuario, y no tendrás que hacer cosas raras para utilizarlos.

Instalación y uso

Actualmente gosu, lo puedes encontrar tanto en Debian, como en Ubuntu, con lo que puedes instalarlo en tu imagen con un apt-get install gosu. A partir de aquí su uso es tremendamente sencillo,

gosu <usuario[:grupo]> comando [args]

Algunos ejemplos,

gosu lorenzo bash
gosu lorenzo:root bash
gosu 1000:0 bash

Como ves, con esta herramienta, puedes especificar con detalle el usuario y grupo que ejecuta un comando.

Algunos ejemplos autoexplicativos

Si todavía no tienes claro, la razón para utilizar gosu, fíjate en los siguientes ejemplos,

$ 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

Fíjate en las dos primeras ejecuciones. Aparenta como si se hubieran lanzado dos procesos distintos, cuando realmente solo has ejecutado uno solo.

Si quieres, puedes instalar gosu en tu equipo y jugar un poco con el para entender su comportamiento. Instalarlo es tan se sencillo como ejecutar sudo apt install gosu. Una vez instalado, tendrás que ser administrador para empezar a utilizarlo, para ello utiliza sudo -i, y a continuación, ejecuta ps -ef como lorenzo (o tu usuario).

En particular, yo he ejecutado la siguiente instrucción, su lorenzo -c "ps -ef" | grep "ps -ef" | grep -v grep, que me arroja el siguiente resultado,

root       55327   55244  0 07:22 pts/1    00:00:00 su lorenzo -c ps -ef
lorenzo    55330   55327  0 07:22 ?        00:00:00 ps -ef

Por el contrario, si ejecutas gosu lorenzo ps -ef | grep "ps -ef" | grep -v grep, el resultado es seguro el que te esperarías, sin sorpresas,

lorenzo    55337   55244  0 07:24 pts/1    00:00:00 ps -ef

Conclusión

Son varios aspectos interesantes los que he tratado. Por un lado, la ventaja de utilizar los volúmenes montados con el usuario local, y por supuesto todos los archivos que allí se contenienen. Por otro lado, el inconveniente de ejecutar los procesos como usuario root en lugar de un usuario con menos privilegios. Esto es algo que sabes de sobra, cuantos cuantos menos privilegios, menos posibilidad de daños colaterales.


Más información,

Imagen de portada de Carson Masterson en Unsplash

Deja una respuesta

Tu dirección de correo electrónico no será publicada.