15.6. Uso de las jaulas

15.6.1. Jaulas “de servicio”

Escrito por Daniel Gerzo.

Esta sección está basada en una idea que Simon L. Nielsen presentó por primera vez en http://simon.nitro.dk/service-jails.html y en un artículo con contenido adicional escrito por Ken Tom . En esta sección se detalla cómo configurar un sistema FreeBSD que añade una capa adicional de seguridad mediante el uso de jail(8). Para su verdadero aprovechamiento se asume que el sistema en el que se vaya a aplicar ejecuta al menos RELENG_6_0 y que la información que contienen las secciones previas de este capítulo se ha comprendido totalmente.

15.6.1.1. Diseño

Uno de los mayores problemas de las jaulas es la gestión de su proceso de actualización. Este proceso tiene a ser un problema porque cada jaula tiene que recompilarse íntegramente desde el código fuente cada vez que hay que actualizarla. Esto no es un gran problema si tenemos una sola jaula puesto que el proceso de actualización es bastante simple, pero si hay muchas jaulas será un trabajo largo y tedioso.

Aviso: Esta configuración requiere mucha experiencia con FreeBSD y el uso de sus características. Si los pasos que se detallan a continuación le parecen demasiado complicados puede echar un vistazo a sistemas más sencillos como sysutils/ezjail, que le permitirá acceder a un método de administración de jaulas en FreeBSD más sencillo y no es tan sofisticado como el que le proponemos a continuación.

El origen de esta idea es resolver los problemas antes descritos compartiendo el máximo posible entre distintas jaulas, de un modo seguro (utilizando montajes using read-only mount_nullfs(8) mounts) para que la actualización sea más sencilla y el ubicar servicios aislados en jaulas sea más interesante. Además, se presenta una forma sencilla de añadir o borrar jaulas así como una forma de actualizarlas.

Nota: Los ejemplos de servicios en este contexto son: un servidor HTTP,un servidor DNS, un servidor SMTP, etc.

Los objetivos de la configuración descrita en esta sección son:

  • Crear una estructura de jaulas simple y fácil de entender. Esto implica no tener que ejecutar un “installworld” completo en todas y cada una de las jaulas.

  • Facilitar la creación de nuevas jaulas o el borrado de jaulas previamente existentes.

  • Facilitar la actualización de jaulas ya existentes.

  • Hacer posible el uso de una rama de FreeBSD personalizada.

  • Ser paranoico en cuanto a seguridad, reduciendo todo lo posible la posibilidad de que los sistemas se vean comprometidos.

  • Ahorrar todo el espacio e inodos que sea posible.

Como ya se ha dicho, este diseño se basa en gran medida en el disponer de una única plantilla en modo de sólo lectura (a la que llamaremos nullfs) montada en cada jaula y un dispositivo en modo lectura-escritura por cada jaula. El dispositivo puede ser otro disco físico adicional, una partición o un dispositivo md(4) basado en un vnode. En este ejemplo utilizaremos montajes nullfs en modo lectura-escritura.

La estructura del sistema de ficheros se detalla en la siguiente lista:

  • Cada jaula se montará bajo /home/j.

  • /home/j/mroot será la plantilla para cada jaula y la partición de sólo lectura para todas las jaulas.

  • Se creará un directorio vacío para cada jaula bajo el directorio /home/j.

  • Cada jaula tendrá un directorio /s que estará enlazado con la parte de lectura-escritura del sistema.

  • Cada jaula tendrá su propio sistema en modo lectura-escritura basado en /home/j/skel.

  • Cada parte de lectura-escritura correspondiente a cada jaula se creará en /home/js.

Nota: Se asume que las jaulas se instalarán bajo la partición /home. Por supuesto esto no es en absoluto obligatorio, pero hay que tener en cuenta que debe hacerse el mismo cambio en cada uno de los ejemplos que se muestran más adelante.

15.6.1.2. Creación de la plantilla

En esta sección se describen los pasos necesarios para crear la plantilla maestra que conformará la parte de sólo lectura que usarán las jaulas.

Siempre es recomendable actualizar el sistema FreeBSD a la última rama -RELEASE. Consulte el capítulo correspondiente de este libro si necesita más información. En caso de que la actualización no sea posible tendrá que usar “buidworld” para poder seguir adelante. También necesitará el paquete sysutils/cpdup. Usaremos portsnap(8) para descargar la Colección de Ports de FreeBSD. El capítulo sobre Portsnap es siempre una lectura muy recomendable para quienes no tengan experiencia con su funcionamiento.

  1. Lo primero que haremos será crear una estructura de directorios para el sistema de ficheros de sólo lectura que contendrá los binarios de nuestras jaulas, luego iremos al directorio que contiene el árbol de código de FreeBSD e instalaremos el sistema de ficheros de sólo lectura en la plantilla de las jaulas:

    # mkdir /home/j /home/j/mroot
    # cd /usr/src
    # make installworld DESTDIR=/home/j/mroot
    
  2. Una vez hecho esto, prepararemos la Colección de Ports de FreeBSD para nuestras jaulas así como un árbol de código FreeBSD, necesario para usar mergemaster:

    # cd /home/j/mroot
    # mkdir usr/ports
    # portsnap -p /home/j/mroot/usr/ports fetch extract
    # cpdup /usr/src /home/j/mroot/usr/src
    
  3. Crear la estructura de directorios necesaria para la parte de lectura-escritura del sistema:

    # mkdir /home/j/skel /home/j/skel/home /home/j/skel/usr-X11R6 /home/j/skel/distfiles
    # mv etc /home/j/skel
    # mv usr/local /home/j/skel/usr-local
    # mv tmp /home/j/skel
    # mv var /home/j/skel
    # mv root /home/j/skel
    
  4. Usamos mergemaster para instalar los ficheros de configuración que falten. Después nos libramos de los directorios adicionales que haya creado mergemaster:

    # mergemaster -t /home/j/skel/var/tmp/temproot -D /home/j/skel -i
    # cd /home/j/skel
    # rm -R bin boot lib libexec mnt proc rescue sbin sys usr dev
    
  5. Ahora enlazamos simbólicamente el sistema de ficheros de lectura-escritura con el sistema de ficheros de sólo lectura. Por favor, asegúrese de que los enlaces simbólicos se crean en las ubicaciones correctas: s/. Si se usan directorios reales o directorios erróneos la instalación no funcionará.

    # cd /home/j/mroot
    # mkdir s
    # ln -s s/etc etc
    # ln -s s/home home
    # ln -s s/root root
    # ln -s ../s/usr-local usr/local
    # ln -s ../s/usr-X11R6 usr/X11R6
    # ln -s ../../s/distfiles usr/ports/distfiles
    # ln -s s/tmp tmp
    # ln -s s/var var
    
  6. Como último paso, cree un /home/j/skel/etc/make.conf genérico con el siguiente contenido:

    WRKDIRPREFIX?=  /s/portbuild
    

    El tener WRKDIRPREFIX configurado de este modo hará posible compilar ports de FreeBSD dentro de cada jaula. Recuerde que el el directorio de los ports es de sólo lectura. La ruta personalizada por WRKDIRPREFIX permite ejecutar compilaciones en la parte de sólo lectura de cada jaula.

15.6.1.3. Creación de las jaulas

Ya tenemos una plantilla de jaulas de FreeBSD completa, así que podemos configurar nuestras jaulas en /etc/rc.conf. En este ejemplo crearemos 3 jaulas: “NS”, “MAIL” y “WWW”.

  1. Introduzca las siguientes lineas en el fichero /etc/fstab; con esto cada jaula tendrá acceso a la plantilla de sólo lectura y al espacio de lectura-escritura:

    /home/j/mroot   /home/j/ns     nullfs  ro  0   0
    /home/j/mroot   /home/j/mail   nullfs  ro  0   0
    /home/j/mroot   /home/j/www    nullfs  ro  0   0
    /home/js/ns     /home/j/ns/s   nullfs  rw  0   0
    /home/js/mail   /home/j/mail/s nullfs  rw  0   0
    /home/js/www    /home/j/www/s  nullfs  rw  0   0
    

    Nota: Las particiones que tienen un 0 en la columna “pass” no serán revisadas por fsck(8) durante el arranque y las que tienen un 0 en la columna “dump” no serán copiadas por dump(8). No nos interesa que fsck compruebe la integridad de montajes nullfs ni que dump haga copias de seguridad de montajes nullfs de sólo lectura de las jaulas. Por esta razón el ejemplo de fstab tiene en las dos últimas columnas “0 0”.

  2. Configure las jaulas en /etc/rc.conf:

    jail_enable="YES"
    jail_set_hostname_allow="NO"
    jail_list="ns mail www"
    jail_ns_hostname="ns.ejemplo.org"
    jail_ns_ip="192.168.3.17"
    jail_ns_rootdir="/usr/home/j/ns"
    jail_ns_devfs_enable="YES"
    jail_mail_hostname="mail.ejemplo.org"
    jail_mail_ip="192.168.3.18"
    jail_mail_rootdir="/usr/home/j/mail"
    jail_mail_devfs_enable="YES"
    jail_www_hostname="www.ejemplo.org"
    jail_www_ip="62.123.43.14"
    jail_www_rootdir="/usr/home/j/www"
    jail_www_devfs_enable="YES"
    

    Aviso: La razón por la que jail_nombre_rootdir contiene /usr/home y no /home es que la ruta física del directorio/home en una instalación de FreeBSD por omisión es /usr/home. La variable jail_nombre_rootdir no debe apuntar a una ruta que contenga un enlace simbólico porque sería imposible arrancar las jaulas. Utilice la herramienta realpath(1) para asegurarse del valor exacto que debe asignar a la variable. Por favor, consulte el aviso de seguridad FreeBSD-SA-07:01.jail para más información.

  3. Creamos los puntos de montaje de sistemas de ficheros de sólo lectura correspondientes a cada jaula:

    # mkdir /home/j/ns /home/j/mail /home/j/www
    
  4. Instalamos la plantilla de lectura-escritura dentro de cada jaula. Observe que utilizamos sysutils/cpdup para asegurarnos de que se hace una copia exacta de cada directorio:

    # mkdir /home/js
    # cpdup /home/j/skel /home/js/ns
    # cpdup /home/j/skel /home/js/mail
    # cpdup /home/j/skel /home/js/www
    
  5. Llegados a este punto las jaulas están configuradas y listas para arrancar. Monte los sistemas de ficheros de cada jaula y luego arránquelas con el script /etc/rc.d/jail:

    # mount -a
    # /etc/rc.d/jail start
    

Las jaulas deberían haber arrancado. Asegúrese de ello con jls(8). La salida que verá debe parecerse a esta:

# jls
   JID  IP Address      Hostname                      Path
     3  192.168.3.17    ns.ejemplo.org                /home/j/ns
     2  192.168.3.18    mail.ejemplo.org              /home/j/mail
     1  62.123.43.14    www.ejemplo.org               /home/j/www

En este punto debería ser posible entrar a cada una de las jaulas, añadir nuevos usuarios o configurar dæmons. La columna JID indica el número de identificación de cada jaula que esté funcionando en el sistema. Con el siguiente comando puede ejecutar tareas administrativas en la jaula cuyo JID sea 3:

# jexec 3 tcsh

15.6.1.4. Actualización

Llegará el momento en el que sea necesario actualizar el sistema, bien por seguridad o porque sea útil para las jaulas disponer de alguna nueva característica del sistema. El diseño de esta configuración facilita una forma fácil de actualizar sus jaulas. Además, minimiza la pérdida de servicio, puesto que las jaulas deben apagarse sólamente al final de todo el proceso. Se ofrece también la posibilidad de volver a la versión anterior en caso de que algo salga mal.

  1. El primer paso es actualizar el servidor que aloja las jaulas de la forma habitual. Después creamos una plantilla de sólo lectura temporal en /home/j/mroot2.

    # mkdir /home/j/mroot2
    # cd /usr/src
    # make installworld DESTDIR=/home/j/mroot2
    # cd /home/j/mroot2
    # cpdup /usr/src usr/src
    # mkdir s
    

    La ejecución de installworld crea unos cuantos directorios innecesarios que debemos borrar:

    # chflags -R 0 var
    # rm -R etc var root usr/local tmp
    
  2. Creamos de nuevo los enlaces simbólicos de lectura-escritura del sistema de ficheros principal:

    # ln -s s/etc etc
    # ln -s s/root root
    # ln -s s/home home
    # ln -s ../s/usr-local usr/local
    # ln -s ../s/usr-X11R6 usr/X11R6
    # ln -s s/tmp tmp
    # ln -s s/var var
    
  3. Ha llegado el momento de parar las jaulas:

    # /etc/rc.d/jail stop
    
  4. Desmontamos los sistemas de ficheros originales:

    # umount /home/j/ns/s
    # umount /home/j/ns
    # umount /home/j/mail/s
    # umount /home/j/mail
    # umount /home/j/www/s
    # umount /home/j/www
    

    Nota: Los sistemas de ficheros de lectura-escritura cuelgan del sistema de sólo lectura /s y por tanto deben desmontarse antes.

  5. Movemos el sistema de ficheros de sólo lectura viejo y lo reemplazamos por el nuevo. Nos servirá de copia de seguridad y como archivo en caso de que haya problemas. Para darle un nombre usamos la fecha en la que se creado una nueva copia del sistema de ficheros de sólo lectura. Movemos también la Colección de Ports de FreeBSD al sistema de ficheros nuevo para ahorrar un poco más de espacio e inodos:

    # cd /home/j
    # mv mroot mroot.20060601
    # mv mroot2 mroot
    # mv mroot.20060601/usr/ports mroot/usr
    
  6. Una vez llegados a este punto la nueva plantilla de sólo lectura está lista, de manera que lo único que nos queda por hacer es montar los sistemas de ficheros y arrancar las jaulas:

    # mount -a
    # /etc/rc.d/jail start
    

Compruebe con jls(8) si las jaulas han arrancado sin contratiempos. No olvide ejecutar mergemaster en cada jaula. Tendrá que actualizar tanto los ficheros de configuración como los scripts rc.d.

Puede descargar éste y muchos otros documentos desde ftp://ftp.FreeBSD.org/pub/FreeBSD/doc/.

Si tiene dudas sobre FreeBSD consulte la documentación antes de escribir a la lista <questions@FreeBSD.org>.
Envíe sus preguntas sobre la documentación a <doc@FreeBSD.org>.