Autor: Jorge Sánchez Escobedo
Fecha: 30/07/2009
Plataforma: FreeBSD 7.2-RELEASE
Se otorga permiso para copiar, modificar y distribuir este documento en cualquier medio siempre y cuando se mantenga el autor y esta nota.
Para mantener la seguridad en nuestro servidor es altamente recomendable crear un servidor virtual por cada servicio que deseamos ofrecer (mail, dns, http, etc) dejando el servidor real libre de cualquier programa susceptible de Bugs, evitando de esta forma que un atacante pueda explotar dichos Bugs y penetrar así nuestro sistema, en freebsd tenemos una excelente forma de lograr todo esto mediante el sistema de jails[1][2].
Es necesario mencionar que el hecho de tener servidores virtuales para cada uno de nuestros servicios no nos exenta de que un atacante penetre alguno de ellos (eso dependerá de que tan a menudo actualizamos el software de nuestros servicios aplicándoles los respectivos parches de seguridad que vayan saliendo). Sin embargo utilizando servidores virtuales para cada servicio, si alguno de ellos es comprometido, el atacante estará limitado a ese servidor virtual en particular, permaneciendo los demás servidores virtuales y el sistema real íntegros, es por tal motivo que es sumamente importante mantener el sistema real lo mas simple posible evitando instalar cualquier servicio en el, puesto que si el sistema real es comprometido tendremos que considerar todos los servidores virtualizados (que son soportados por el sistema real) comprometidos de igual forma.
ezjail[3] es un framework que permite crear y administrar servidores virtuales utilizando el sistema de jails de FreeBSD.
Este tipo de virtualizacion[4] comparte el kernel con el servidor real teniendo un userland, filesystem y subsistema de red del kernel totalmente aislado del servidor real y los demás servidores virtuales, este tipo de virtualización tiene la ventaja de ser muy rápido en comparación con otro tipo de virtualizaciones como la que lleva a cabo vmware y otros softwares de virtualización.
El Framework ezjail consiste de tres partes fundamentales.
Dos scripts, ezjail-admin y ezjail.sh:
Basejail:
Con basejail nos referimos al directorio que contiene todos los binarios y librerías del userland que utilizarán los servidores virtuales el cual será montado en modo de solo lectura en todos los entornos virtualizados mediante mount_nullfs(8), este hecho nos proporciona varias ventajas como son:
ezjail esta disponible en la colección de ports[5] así es que para instalarlo no tenemos más que ejecutar los siguientes comandos:
realsystem# cd /usr/ports/sysutils/ezjail realsystem# make realsystem# make install
El proceso anterior creará los scripts necesarios (ezjail-admin y ezjail-sh) además de crear e instalar el archivo de configuración ezjail.conf.
El archivo ezjail.conf contiene variables que controlan algunos aspectos de los scripts del Framework ezjail, por default no hace falta mover nada a este archivo de configuración para poder trabajar con ezjail sin embargo vale la pena mencionar algunas opciones de el archivo.
Existen dos formas diferentes de crear el directorio basejail, los cuales son descargándolo desde algún servidor ftp o creando el directorio y su contenido nosotros mismos, afortunadamente si decidimos crearlo nosotros mismos, ezjail nos facilita enormemente la forma de hacerlo.
Para descargar el directorio basejail junto con todo su contenido ejecutamos el comando:
ezjail-admin install
Adicionalmente podemos pasar los parámetros –s –m y –p los cuales descargarán e instalarán en el directorio basejail el código fuente del sistema, las paginas man y el árbol de ports.
Para crear el directorio basejail por nosotros mismos tenemos que ejecutar el comando siguiente:
realsystem# ezjail-admin update –b -p
El cual ejecutará todo lo necesario para construir un userland desde los archivos de código fuente de nuestro sistema (/usr/src), esto implica que el script ejecutará los comandos make world y make installworld e instalará todo dentro del directorio basejail, este procedimiento tomará un tiempo considerable dependiendo las características de nuestro hardware, el parametro –p le indica al script ezjail-admin que tambien instale el arbol de ports dentro del directorio basejail.
Adicionalmente a la creación del directorio basejail el proceso de creación de este mismo directorio creara otros dos directorios los cuales son:
Una vez creado el directorio basejail podemos crear nuestros servidores virtuales.
El único requisito que necesitamos cumplir antes de utilizar servidores virtuales es que los servicios que esta corriendo el sistema real escuchen únicamente en la dirección ip asignada a este mismo y no estar escuchando en las demás ips que serán asignadas a los servidores virtuales, si el sistema real que estamos usando acaba de ser instalado no tendremos mucho trabajo que realizar para lograr esto, de otra forma si al servidor real le hemos instalado algunos servicios (dns, http, smpt, etc) lo más recomendable será que detengamos dichos servicios y los migremos en un servidor virtual para mantener limpio y seguro el sistema real, para averiguar que servicios están escuchando en que ip haremos uso del comando sockstat(1).
Los flags que pasaremos al comando sockstat son los siguientes:
realsystem# sockstat -l4 USER COMMAND PID FD PROTO LOCAL ADDRESS FOREIGN ADDRESS root sendmail 750 4 tcp4 127.0.0.1:25 *:* root sshd 744 4 tcp4 *:22 *:* root syslogd 612 7 udp4 *:514 *:* realsystem#
Cada una de las líneas de salida de sockstat representa un socket escuchando. Del resultado que hemos obtenido nos interesan únicamente las columnas COMMAND y LOCAL ADDRESS, la primera columna indica a que servicio se refiere la salida, la columna LOCAL ADDRESS nos indica en que dirección esta escuchando el socket, simplificando tenemos:
COMMAND PROTO LOCAL ADDRESS sshd tcp4 *:22 syslogd udp4 *:514
Analizando las líneas anteriores podemos ver que tanto el servicio de ssh y de syslog están escuchando en todas las ip’s del systema real, por tanto tenemos que modificarlos para que solo escuchen en la ip asignada al servidor real (192.168.1.64).
Para lograr que el servicio de ssh escuche solo en la dirección del sistema real editamos el archivo /etc/ssh/sshd_config y editamos la linea ListenAddress para que quede de la siguiente manera:
ListenAddress 192.168.1.64
Finalmente reiniciamos el servicio de ssh:
realsystem# /etc/rc.d/sshd restart Stopping sshd. Starting sshd. realsystem#
Para lograr que el servicio syslog escuche solo en la ip del sistema real (192.168.1.64) agregamos las siguientes líneas en el archivo /etc/rc.conf
syslogd_flags=“-sS”
syslogd_flags=“-b 192.168.1.64”
Reiniciamos el servicio de syslogd para que los cambios surtan efecto:
realsystem# /etc/rc.d/syslogd restart Stopping syslogd. Starting syslogd. realsystem#
Y volvemos a verificar con sockstat:
realsystem# sockstat -l4 USER COMMAND PID FD PROTO LOCAL ADDRESS FOREIGN ADDRESS root sendmail 764 3 tcp4 127.0.0.1:25 *:* root sshd 746 3 tcp4 192.168.1.64:22 *:* root syslogd 637 6 udp4 192.168.1.64:514 *:* realsystem#
Para poder crear los entornos virtuales con ezjail es necesario tener una ip disponible para asignarle y un nombre, ya sea que tengamos varias ip’s disponibles o que podamos crear un alias para asignar una nueva dirección ip a nuestra tarjeta de red, en este caso optaremos por la segunda opción, así es que ejecutamos el siguiente comando:
realsystem# ifcofing fxp0 alias 192.168.1.100 netmask 255.255.255.0
El cual asignara la dirección 192.168.1.100 con mascara de red 255.255.255.0 a nuestra tarjeta de red fxp0.
Para que esta dirección sea persistente incluso si reiniciamos el sistema agregamos la siguiente línea al archivo /etc/rc.conf
ifcofig_fxp0_alias0=”192.168.1.100 netmask 255.255.255.0”
Ahora estamos listos para crear el primer servidor virtual, ejecutamos el siguiente comando:
realsystem# ezjail-admin create virtual01 192.168.1.100
virtual01 será tanto el nombre del jail y nombre del host de nuestro servidor virtual. 192.168.1.100 será la ip que tendrá nuestro servidor virtual.
El proceso de creación de nuestro servidor virtual colocará un archivo de configuración propio del entorno ezjail en el directorio /usr/local/etc/ezjail/{nombre} donde el “{nombre}” será el que corresponda a cada uno de nuestros servidores virtuales, dicho archivo de configuración es usado por el escript ezjail.sh que es el encargado de iniciar cada uno de nuestros servidores virtuales.
El proceso de creación también colocará un archivo fstab.{nombre} en el directorio /etc Donde “{nombre}” será el que corresponda a cada uno de nuestros servidores virtuales, este archivo indicará en donde se debe montar el basejail para que sea accesible en nuestro servidor virtual, este archivo es usado por el script ezjail.sh que es el encargado de iniciar cada uno de nuestros servidores virtuales.
El script /usr/local/etc/rc.d/ezjail.sh es el encargado de realizar esta tarea por nosotros, para que el script funcione tenemos que agregar la siguiente línea al archivo /etc/rc.conf
ezjail_enable=“YES”
Una vez que hemos agregado la línea anterior ejecutamos el siguiente comando para iniciar nuestro servidor virtual:
realsystem# /usr/local/etc/rc.d/ezjail.sh start virtual01 Configuring jails:. Starting jails: virtual01. realsystem#
Si en algún momento necesitáramos detener nuestro servidor virtual lo podemos hacer con el siguiente comando:
realsystem# /usr/local/etc/rc.d/ezjail.sh stop virtual01
Ahora cada vez que reiniciemos el sistema el script /usr/local/etc/rc.d/ezjail.sh se encargará de iniciar todos nuestros servidores virtuales.
Nota: si bien hemos dicho que el script /usr/local/etc/rc.d/ezjail.sh es el encargado de iniciar y detener los servidores virtuales tambien podemos hacer uso del comando ezjail-admin de la siguiente manera:
realsystem# ezjail-admin stop virtual01 Stopping jails: virtual01. realsystem# ezjail-admin start virtual01 Configuring jails:. Starting jails: virtual01. realsystem#
Ahora que ya tenemos creado y funcionando nuestro servidor virtual necesitamos una forma de manejarlo para poder implementar cualquier servicio que deseemos funcione dentro de nuestro servidor virtual, ezjail nos proporciona una forma sencilla de acceder a nuestro nuevo servidor virtual mediante el siguiente comando (es necesario que el servidor virtual este en ejecución):
realsystem# ezjail-admin console virtual01
El cual nos dará una shell como usuario root para poder manipular y ajustar todo lo que necesitemos en nuestro nuevo servidor virtual, en este momento podemos realizar cualquier tarea que necesitemos, incluso podemos habilitar el acceso ssh que nos permitirá entrar directamente a nuestro servidor virtual mediante la red.
El Framework ezjail nos proporciona una forma muy sencilla de ver que servidores virtuales hemos creado y cual es su estado, para hacerlo solo tenemos que ejecutar el comando siguiente:
realsystem# ezjail-admin list STA JID IP Hostname Root Directory --- ----- --------------- ---------------------------- ------------------------- DR 2 192.168.1.100 vitual01 /usr/jails/virtual01 realsystem#
La primera columna corresponde al estado de nuestro servidor virtual y esta compuesto por 2 o 3 letras independientes, el significado de cada una de las letras es el siguiente:
La segunda columna corresponde al id que identifica de forma única a nuestro servidor virtual.
La tercera columna corresponde a la ip que tiene asignada nuestro servidor virtual.
La cuarta columna representa el nombre de nuestro servidor virtual que inicialmente es el nombre de host de nuestro servidor virtual.
La quinta columna indica en donde se encuentra el directorio que contiene nuestro servidor virtual.
Si en algún momento necesitamos que alguno de nuestros servidores virtuales no se inicie automáticamente cuando el sistema real reinicie podemos especificarlo mediante el siguiente comando:
realsystem# ezjail-admin config –r norun virtual01
De esta forma el servidor virtual con nombre virtual01 quedará marcado para no ser inicializado cuando el sistema real reinicie.
Revisamos el estado del servidor virtual para verificar el cambio:
realsystem# ezjail-admin list STA JID IP Hostname Root Directory --- ----- --------------- ---------------------------- ------------------------- DRN 2 192.168.1.100 virtual01 /usr/jails/virtual01 realsystem#
Como podemos observar, en la columna STA de la salida del comando anterior el servidor virtual virtual01 aparece marcado con una letra N que indica que en el siguiente reinicio del sistema real este servidor virtual no se iniciara automáticamente.
Para revertir el proceso anterior, es decir que el servidor virtual si se inicie automáticamente cuando el sistema real reinicie ejecutamos el siguiente comando:
realsystem# ezjail-admin config -r run virtual01
Revisamos nuevamente el estado:
realsystem# ezjail-admin list STA JID IP Hostname Root Directory --- ----- --------------- ---------------------------- ------------------------- DR 2 192.168.1.100 virtual01 /usr/jails/virtual01 realsystem#
El comando ezjail-admin config nos permite realizar unas cuantas cosas más, entre ellas renombrar nuestros servidores virtuales, para renombrar el servidor virtual es necesario que no se encuentre en ejecución al momento re renombrarlo, así es que procedemos a detener nuestro servidor virtual:
realsystem# /usr/local/etc/rc.d/ezjail.sh stop virtual01 Stopping jails: virtual01. realsystem#
Procedemos a renombrar el servidor virtual:
realsystem# ezjail-admin config -n vdns.ezjailexamples.org virtual01 Jail has been renamed. You might want to check /usr/local/etc/ezjail/ vdns_ezjailexamples_org and /etc/fstab.vdns_ezjailexamples_org to ensure everything has gone smoothly. Also check settings in your Jail's /etc/ directory (especially /etc/rc.conf). realsystem#
Como podemos observar al terminar el proceso de renombre el script ezjail-admin nos arroja mensajes que debemos tener en cuenta para revisar que todo haya ido bien, si tenemos alguna configuración dentro de nuestro servidor virtual que haga uso del hostname tenemos que cambiarlo.
Para verificar que el servidor virtual ha sido renombrado, utilizaremos el comando ezjail-admin list:
realsystem# ezjail-admin list STA JID IP Hostname Root Directory --- ----- --------------- ---------------------------- ------------------------- DS N/A 192.168.1.100 vdns.ezjailexamples.org /usr/jails/vdns.ezjailexamples.org realsystem#
Como mencionamos al principio de este documento es sumamente importante estar al día con las vulnerabilidades que se van encontrando en el software que instalamos en cada uno de nuestros servidores virtuales y actualizarlas o aplicarles los respectivos parches de seguridad, en freebsd contamos con una excelente herramienta que nos reporta si hay vulnerabilidades en el software instalado en nuestro sistema via ports, se trata de la herramienta portaudit[6], si bien podemos instalar portaudit en cada uno de los servidores virtuales que vamos a manejar dentro de nuestro sistema real sería algo tardado y engorroso entrar en cada uno de esos servidores virtuales y ejecutar portaudit cada vez que queramos revisar si hay problemas en el software que hemos instalado, para facilitarnos este trabajo existe otro port llamado jailaudit[7] que podemos instalar en nuestro sistema base y que creara un reporte de vulnerabilidades por cada servidor virtual que tengamos instalado haciendo uso de poraudit instalado en el sistema base, para instalar jailaudit entramos en el directorio /usr/ports/ports-mgmt/jailaudit
realsystem# cd /usr/ports/ports-mgmt/jailaudit
y ejecutamos
realsystem# make && make install
Una vez que tengamos instalado el jailaudit (el cual instalará automáticamente portaudit) seremos capaces de generar reportes fácilmente para cada uno de nuestros servidores virtuales simplemente ejecutando el siguiente comando:
realsystem# jailaudit generate Downloading a current audit database: auditfile.tbz 100% of 56 kB 55 kBps New database installed. Database created: Mon Jul 27 15:50:01 PDT 2009 realsystem#
en este momento jailaudit habrá revisado todos nuestros servidores virtuales y habrá generado sus respectivos reportes, en mi caso tengo instalados dos servidores virtuales los cuales son:
realsystem# ezjail-admin list STA JID IP Hostname Root Directory --- ----- --------------- ---------------------------- ------------------------- DR 1 192.168.1.201 vhttp2.ezjailexamples.org /usr/jails/vhttp2.ezjailexamples.org DR 2 192.168.1.100 vdns.ezjailexamples.org /usr/jails/vdns.ezjailexamples.org realsystem#
Por lo tanto jailaudit ha generado dos reportes independientes, los cuales siempre serán colocados en la ruta /usr/local/jailaudit/reports/. viendo el contenido de ese directorio podemos ver los dos reportes creados:
realsystem# ls /usr/local/jailaudit/reports/ vdns.ezjailexamples.org_2 vhttp2.ezjailexamples.org_1 realsystem#
el nombre de cada uno de los reportes es simplemente el nombre de cada uno de los servidores virtuales mas el id que los identifica de forma única, los reportes son simplemente archivos de texto que contienen la salida de portaudit así es que podemos verlos con cualquier herramienta para visualizar texto:
realsystem# cat /usr/local/jailaudit/reports/vdns.ezjailexamples.org_2 0 problem(s) found. realsystem#
realsystem# cat /usr/local/jailaudit/reports/vhttp2.ezjailexamples.org_1 0 problem(s) found. realsystem#
En este momento no hay problemas conocidos en ninguna aplicación que hay instalada en los servidores virtuales.
Si por alguna razon ya no vamos a hacer uso de alguno de nuestros servidores virtuales podemos eliminarlos sin mayor problema con el siguiente comando:
realsystem# ezjail-admin delete -w vhttp2.ezjailexamples.org realsystem#
Nota: para eliminar los servidores virtuales estos mismos no deben estar en ejecución.
Para actualizar el árbol de ports de los servidores virtuales (que esta contenido en el directorio basejail) haremos uso del comando ezjail-update mediante el parámetro –P (en mayúscula), esta tarea puede ser realizada mientras los servidores virtuales están en ejecución sin ningún problema.
realsystem# ezjail-admin update -P Looking up portsnap.FreeBSD.org mirrors... 3 mirrors found. Fetching snapshot tag from portsnap2.FreeBSD.org... done. Fetching snapshot metadata... done. Updating from Sun Jul 26 13:04:01 PDT 2009 to Mon Jul 27 21:01:33 PDT 2009. Fetching 3 metadata patches.. done. Applying metadata patches... done. Fetching 1 metadata files... done. Fetching 78 patches.....10....20....30....40....50....60....70.... done. Applying patches... done. Fetching 3 new ports or files... done. Removing old files and directories... done. Extracting new files: /usr/jails/basejail/usr/ports/GIDs /usr/jails/basejail/usr/ports/UIDs /usr/jails/basejail/usr/ports/UPDATING . . . . Building new INDEX files... done. realsystem#
En ocasiones será necesario que actualicemos nuestro sistema operativo, ya sea para aplicar parches de seguridad o porque deseamos tener alguna nueva característica que ha sido implementada recientemente, cada vez que actualicemos nuestro sistema base del servidor real será necesario que también actualicemos el directorio basejail, si hemos actualizado nuestro sistema operativo desde las fuentes solo tendremos que ejecutar el comando ezjail-admin update con el flag –i (instalar) y ezjail realizara un make installworld sobre el directorio basejail, omitiendo realizar un make buildworld, esto nos ahorrara una gran cantidad de tiempo, si no se especifica el flag -i el comando make buildworld será invocado.
Hemos visto como crear y manipular servidores virtuales mediante el sistema de jails de FreeBSD, como pudimos darnos cuenta los servidores virtuales agregan un nivel de seguridad a todo el conjunto de servicios y sistema real que administramos, sin embargo la mejor forma de asegurarnos de correr el menor riesgo posible de una penetración es mantener actualizado el software que utilizamos y estar al pendiente de las alertas de seguridad, así como auditar regularmente nuestros sistemas.
Para terminar solo decir que cualquier comentario o critica a este documento son bienvenidos.
[1] http://www.freebsd.org/doc/en_US.ISO8859-1/books/handbook/jails.html
[2] http://en.wikipedia.org/wiki/FreeBSD_jail
[3] http://erdgeist.org/arts/software/ezjail/
[4] http://en.wikipedia.org/wiki/Operating_system-level_virtualization
[5] http://www.freebsd.org/doc/en_US.ISO8859-1/books/handbook/ports-using.html
[6] http://www.freebsd.org/doc/en/books/handbook/security-portaudit.html