SafeChildren Banner

Havoc Oracle Solaris Experts

viernes, 4 de febrero de 2011

Cómo montar un CHROOT en tiempos de Virtualización

Intdoducción
Con la llegada de Solaris 10 y sus containers, muchos de nosotros comenzamos a "migrar" nuestros servicios a contenedores y, por ello, dejamos de utilizar -y hablar- de los chroot. Es cierto que un "container" o "LDOM" nos proporciona una gestión mucho más fina, y por lo tanto, podemos definir los recursos, usuarios, etc. y sobre todo, aislar totalmente un entorno de otro.

Sin embargo, cuando nuestros recursos físicos están muy limitados -pensemos en un appliance, por ejemplo-, y debemos tratar de tener nuestro "servicio" lo más aislado posible podemos seguir utilizando esta "reliquia del pasado", que, funciona a la perfección.

Nota: Este post es una adaptación a la respuesta que hice en StackOverFlow sobre Cómo crear un SandBox en Unix

Qué es un ChRoot
Bueno, técnicamente es ejecutar un proceso con un "/" diferente a nuestro sistema principal, es decir, por ejemplo "/chroot_example/", por lo tanto, para nuestro "proceso" su "/" será "/chroot_example" y no podrá acceder a aquellas partes que necesitamos asegurar

Para Qué un ChRoot en Tiempos de Containers
Bueno, como os decía en la introducción, depende sobre todo de los recursos que dispongamos, así que si no tenemos muchos, deberemos utilizar técnicas como esta para tratar de aislar -en la medida de lo posible- nuestro proceso

ChRoot o Container
Bueno, esta es una pregunta un poco "compleja de responder", aunque intentaré salir "airoso" diciendo: depende. ¿De qué depende? Principalmente de recursos, tipos de servicios y administración. Mi recomendación es, si es posible utilizar Solaris Containers -o LDOMs- para servicios complejos -PostgreSQL, Hadoop, etc.- pero si necesitáis tener un "mini proceso" -o varios- no vais a crear un montón de Containers para cada uno de ellos. Es ahí donde entra nuestro ChRoot, además siempre podemos unir las dos opciones: ChRoot dentro de Containers

Un Ejemplo Completo
Después de todo este "lío", vamos a verlo claro con un ejemplo. Para ello, necesitamos ejecutar un comando -en nuestro caso ls- que nos devuelva el listado de nuestro "directorio /etc" -no el de sistema- donde tenemos la licencia de nuestro aplicativo.

La estructura de nuestro "chroot" sería la siguiente:
    /
    /etc
     + license
    /bin
     + ls
    /lib
     + ...
Creación de la Estructura de ChRoot
Hemos comentado que un "ChRoot" es definir un nuevo "root" para el sistema de archivos de un proceso, y por lo tanto, deberemos "reproducir" el sistema principal con, al menos los directorios básicos: /etc, /bin, /lib

    itily@openzooey:~$ mkdir chroot_example
    itily@openzooey:~$ cd chroot_example/
    itily@openzooey:~/chroot_example$ mkdir -p usr/lib lib bin etc
    itily@openzooey:~/chroot_example$ cd bin/
    itily@openzooey:~/chroot_example/bin$ cp /bin/ls .
Ahora vamos a copiar las "shared lib" que nuestro binario necesita -en nuestro caso ls-, para ello, utilizaremos el comando: <ldd>
itily@openzooey:~/chroot_example/bin$ ldd ls
            libsec.so.1 =>       /lib/libsec.so.1
            libnvpair.so.1 =>    /lib/libnvpair.so.1
            libcmdutils.so.1 =>  /lib/libcmdutils.so.1
            libcurses.so.1 =>    /lib/libcurses.so.1
            libc.so.1 =>         /lib/libc.so.1
            libavl.so.1 =>       /lib/libavl.so.1
            libidmap.so.1 =>     /usr/lib/libidmap.so.1
            libnsl.so.1 =>       /lib/libnsl.so.1
            libuutil.so.1 =>     /lib/libuutil.so.1
            libmp.so.2 =>        /lib/libmp.so.2
            libmd.so.1 =>        /lib/libmd.so.1
            libm.so.2 =>         /lib/libm.so.2

Vamos a copiar las bibliotecas utilizando un pequeño script. Desde el directorio <bin> de nuestro <chroot> hacemos:
itily@openzooey:~/chroot_example/bin$ ldd ls |awk '{print "cp "$3" .."$3}'
cp /lib/libsec.so.1 ../lib/libsec.so.1
cp /lib/libnvpair.so.1 ../lib/libnvpair.so.1
cp /lib/libcmdutils.so.1 ../lib/libcmdutils.so.1
cp /lib/libcurses.so.1 ../lib/libcurses.so.1
cp /lib/libc.so.1 ../lib/libc.so.1
cp /lib/libavl.so.1 ../lib/libavl.so.1
cp /usr/lib/libidmap.so.1 ../usr/lib/libidmap.so.1
cp /lib/libnsl.so.1 ../lib/libnsl.so.1
cp /lib/libuutil.so.1 ../lib/libuutil.so.1
cp /lib/libmp.so.2 ../lib/libmp.so.2
cp /lib/libmd.so.1 ../lib/libmd.so.1
cp /lib/libm.so.2 ../lib/libm.so.2
Una vez verificado, ya podemos copiar las bibliotecas
itily@openzooey:~/chroot_example/bin$ ldd /bin/ls |awk '{print "cp "$3" .."$3}'|bash
itily@openzooey:~/chroot_example/bin$ 
Ahora tenemos nuestra  estructura completa, y tiene la siguiente forma:
itily@openzooey:~/chroot_example$ ls -l
total 12
drwxr-xr-x   2 itily  staff          3 dic 22 14:37 bin
drwxr-xr-x   2 itily  staff          5 ene 10 20:43 etc
drwxr-xr-x   2 itily  staff         14 ene 10 20:48 lib
drwxr-xr-x   3 itily  staff          3 ene 10 20:40 usr
Añadimos los archivos de <group> y <passwd> con el usuario que será el encargado de ejecutar el proceso -en mi caso itily- y creamos nuestra "licencia"
itily@openzooey:~/chroot_example$ echo "this is a test" > etc/license
itily@openzooey:~/chroot_example$ cd etc/
itily@openzooey:~/chroot_example/etc$ cat /etc/group |grep staff > group
itily@openzooey:~/chroot_example/etc$ cat /etc/passwd |grep itily > passwd
Ejecutar el comando <chroot>
Por último, ya sólo nos queda ejecutar el comando < que tiene el siguiente formato:
chroot rootdir command [arg ...]
Debemos tener en cuenta que si ejecutamos el comando <chroot> con un usuario sin privilegios de "root", tendremos el siguiente mensaje
itily@openzooey:~$ chroot chroot_example bin/ls /etcchroot: cannot change root directory to chroot_example: Not owner
Así que utilizaremos <pfexec> -si tenemos asignado el rol de root, o nos cambiaremos a root- para ejecutarlo:
itily@openzooey:~$ pfexec chroot chroot_example /bin/ls -l /etc    total 6
    -rw-r--r--   1 101  10         11 Jan 10 19:43 group
    -rw-r--r--   1 101  10         18 Jan 10 19:42 license
    -rw-r--r--   1 101  10         49 Jan 10 19:43 passwd

Ya está! Hemos conseguido que nuestro comando <ls> nos muestre nuestro directorio </chroot_example/etc> como </etc>

Conclusiones
Aunque a veces parezca que las tecnologías antiguas ya no sirven, puede que en circunstancias nos ayuden, además, <chroot> nos permite montar sin "muchas" complicaciones algunas tareas sencillas sin tener que estar creando cientos de Containers para ello.


Referencias

1 comentario:

  1. Llevo un tiempo dándole vueltas a este asunto, pero no consigo que la jaula sea inexpugnable, es decir, si en vez del comando 'ls /' pones 'ls /../' qué ocurre? porque a mi ya con eso se me escapa de la jaula.

    Hay alguna forma de evitar esto? Un saludo

    ResponderEliminar