Autor: Jorge Sánchez Escobedo
Fecha: 15/01/2006
Plataforma: FreeBSD 5.4-STABLE
Se otorga permiso para copiar, modificar y distribuir este documento en cualquier medio siempre y cuando se mantenga el autor y esta nota. Introduccion:
Este documento explica como crear y configurar servidores virtuales para que puedan correr los servicios que deseamos ofrecer de una forma aislada y con una sola tarjeta de red como si se tratase de varios servidores independientes y mediante el uso de NATD redirigiremos las peticiones de cada servicio al servidor virtual correspondiente :).
Primero que nada tenemos que asegurarnos de tener las fuentes instaladas en nuestro sistema, si no es asi podemos hacer uso de /stand/sysinstall para lograrlo, una vez con las fuentes en nuestro sistema debemos hacer lo siguiente procedemos a configurar nuestro kernel con las siguientes opciones:
options IPFIREWALL options IPDIVERT options IPFIREWALL_DEFAULT_TO_ACCEPT options IPFIREWALL_VERBOSE options BRIDGE
Ahora tenemos que crear el userland de nuestro servidor virtual, creamos el directorio en donde queremos que se instale nuesto jail, por ejemplo /usr/jail y ejecutamos los siguientes comandos:
Moscu# D=/usr/jail Moscu# cd /usr/src Moscu# mkdir -p $D Moscu# make world DESTDIR=$D Moscu# cd etc Moscu# make distribution DESTDIR=$D Moscu# mount_devfs devfs $D/dev Moscu# cd $D Moscu# ln -sf dev/null kernel
Esto creara dentro de /usr/jail todo el usrland como si se tratara de un sistema independiente menos el kernel que sera compartido por ambos sistemas, el real y el virtual, todos los sistemas virtuales que creemos compartiran el kernel. No debemos olvidar montar el sistema devfs dentro del directorio /dev de nuestro jail antes de arrancar el servidor virtual cada vez que reiniciemos nuestro equipo, o agregar unas lineas al /etc/rc.conf como veremos mas adelante para que esto se haga de forma automatica.
NOTA: en FreeBSD 5.3 RELEASE Make tenia problemas con las variables de entorno, para solucionar eso tenemos que sustituir la linea:
Moscu# make world DESTDIR=$D
Por:
Moscu# buildworld Moscu# installworld DESTDIR=/usr/jail
Creamos el directorio stand dentro del directorio raiz “/” del jail y copiamos el programa sysinstall para poderlo usar dentro del servidor virtual:
Moscu# mkdir /usr/jail/stand Moscu# cp /stand/sysinstall /usr/jail/stand/sysinstall
Ahora tenemos que lograr que nuestros servicios del host anfitrion (el servidor real) escuchen solo en su ip, para esto agregaremos las siguientes lineas en el /etc/rc.conf y suponiendo que la ip del anfitrion es 172.16.1.36/16 agregamos lo siguiente:
inetd_flags="-wW -a 172.16.1.36" rcpbind_enable="NO" portmap_enable="NO" syslogd_flags="-s -S" syslogd_flags="-a 172.16.1.36"
Para apache editamos el /usr/local/etc/apache/httpd.conf y agregamos la siguente linea:
Listen 172.16.1.36:8080
Editamos el /etc/ssh/sshd_config y editamos las siguientes lineas:
ListenAddress 172.16.1.36 Port 2222
Creamos un ip alias que sera la ip en la que estara nuestro servidor virtual:
Moscu# ifconfig rl0 alias 172.16.1.100 netmask 255.255.0.0
Editamos el archivo /etc/rc.conf y agregamos lo siguiente para que el cambio sea permanente cuando iniciemos:
ifconfig_rl0_alias0="172.16.1.100 netmask 255.255.0.0"
Arrancando nuestro servidor virtual por primera vez
En este momento estamos listos para arrancar nuestro servidor virtual podemos ejecutar desde nuestro prompt:
Moscu# jail /usr/jail Svhttp 172.16.1.100 /bin/sh
Esto nos arrojara un prompt de root (#) en el cual debemos configurar algunas cosas como la clave de root, instalar sudo y crear un usuario con sudo para poder logearnos con el desde la red mediante ssh y poder manipular nuestro servidor virtual, suponiendo que tenemos acceso a internet en el servidor real tambien debemos tenerlo en el virtual, para distinguir los comandos del servidor real al del virtual antepondremos el prompt (Moscu#) y (#) respectivamente, asi es que ejecutamos:
# pkg_add -r sudo # adduser uj
cambiamos la pass de root:
# passwd
Ahora editamos el archivo /usr/local/etc/sudoers del servidor virtual y ponemos lo siguiente:
uj ALL=(ALL) ALL uj ALL=(ALL) NOPASSWD: ALL
Con esto lograremos que el usuario que creamos en el servidor virtual (uj) pueda ejecutar comandos de root sin ser root anteponiendo el comando sudo al comando a ejecutar, sudo se puede configurar de varias maneras pero eso se sale del alcance del doc, mas informacion en la page del manual de sudo. Ahora debemos editar el archivo /etc/rc.conf del servidor virtual y agregamos lo siguiete:
sshd_enable="YES" ifconfig_rl0="172.16.1.100" defaultrouter="172.16.1.36" host_name="Svhttp"
Editamos el archivo /etc/ssh/sshd.config del servidor virtual para lograr que el servicio de ssh de este servidor virtual escuche solo en su correspondiente poniendo:
port 22 ListenAddress 172.16.1.100
Nos salimos del servidor virtual con el comando exit y ahora si ya estamos listos para iniciar nuestro servidor de forma permanente, para ello utilizamos el siguiente comando:
Moscu# jail /usr/jail Svhttp 172.16.1.100 /bin/sh /etc/rc
y ya podremos logearnos como usuario uj, instalar paquetes, levantar servicios etc etc. para detener nuestro servidor virtual debemos logearnos por ssh y ejecutar el siguiente comando:
Svhttp# sudo KILL -TERM -1
Podemos crear tantos servidores virtuales como necesitemos para ofrecer los servicios que queramos asignandole a cada uno un alias ip, en nuestro caso creamos dos servidores virtuales, uno para ofrecer el servicio de web y otro para ofrecer servicio de ftp, y usaremos NATD para redirigir las peticiones que recibe el ruteador y envia a la ip del servidor real a su correspondiente servidor virtual.
Agregamos las siguientes lineas al archivo /etc/rc.conf :
firewall_enable="YES" firewall_type="/etc/firewall.rules" firewall_script="/etc/rc.firewall"
Creamos el archivo /etc/firewall.rules y agregamos lo siguiente:
-f flush add divert natd all from any to any via rl0
Debemos configurar NATD para que redirija las peticiones de los servicios que llegan al servidor real y deseamos que atienda alguno de los servidores virtuales basandonos en el puerto al que van dirigidos los paquetes para distinguir entre un servicio u otro, para lograr eso agregamos al archivo /etc/rc.conf del servidor virtual las siguientes lineas:
natd_enable="YES" natd_interface="rl0" natd_flags="-l -f /etc/rc.natd"
Creamos el archivo /etc/rc.natd y agregamos lo siguiente:
redirect_port tcp 172.16.1.100:80 80 redirect_port tcp 172.16.1.101:21 21
Lo que indican las lineas de arriba es que todo lo que vaya al puerto 21 de la maquina real (extremo derecho de la linea) sera reenviado hacia el puerto 21 de la maquina con ip 172.16.1.101 (172.16.1.101:21) y todo lo que llegue al puerto 80 de la maquina real sera reenviado al puerto 80 de la maquina con ip 172.16.1.100 :) de esta forma tendremos dos servidores perfectamente aislados ejerciendo una funcione especifica de tal forma que si alguien se apoderara de un servidor virtual solo tendria acceso a ese servidor y no a los demas o al servidor real, para los mas paranoicos incluso pueden usar chroot para asegurar aun mas el servicio que ofrece nuestro servidor virtual obteniendo asi doble seguridad ;)
Ahora ya tenemos listos los archivos necesarios para que la siguiente vez que arranque nuestra maquina este listo el NATD con la redireccion de puertos pero si no queremos esperar podemos ejecutar los siguientes comandos:
Moscu# ipfw add divert natd all from any to any via rl0 Moscu# natd -f /etc/rc.natd -n rl0
Ahora procedemos a configurar las reglas para que cuando montamos el sistema devfs dentro de nuestro servidor virtual solo se vean los dispositivos necesarios para el funcionamiento del servicio que corre nuestro servidor virtual, esto no es necesario realmente pero nos dara un poco de seguridad adicional.
Copiamos el archivo /etc/defaults/devfs.rules a el directorio /etc/ y lo editamos para que quede de la siguiente forma:
[devfsrules_hide_all=1] add hide
[devfsrules_unhide_basic=2] add path null unhide add path zero unhide add path crypto unhide add path random unhide add path urandom unhide
[devfsrules_unhide_login=3] add path 'ptyp*' unhide add path 'ptyq*' unhide add path 'ptyr*' unhide add path 'ptys*' unhide add path 'ptyP*' unhide add path 'ptyQ*' unhide add path 'ptyR*' unhide add path 'ptyS*' unhide add path 'ttyp*' unhide add path 'ttyq*' unhide add path 'ttyr*' unhide add path 'ttys*' unhide add path 'ttyP*' unhide add path 'ttyQ*' unhide add path 'ttyR*' unhide add path 'ttyS*' unhide add path stdin unhide add path stdout unhide add path stderr unhide
[devfsrules_net=4] add path cuaa0 unhide add path 'net/*' unhide add path net1 unhide add path net2 unhide add path net3 unhide
[devfsrules_jail=5] add path ad0s2e unhide add include $devfsrules_hide_all add include $devfsrules_unhide_basic add include $devfsrules_unhide_login add include $devfsrules_net
Esto establece 5 grupos de reglas de devfs que pueden ser aplicadas a nuestro sistema o a algun sistema virtual al momento de montar el sistema devfs dentro del directorio /dev, en el grupo de reglas devfsrules_net desocultamos los dispositivos que usamos para la red y en el grupo de reglas devfsrules_jail desocultamos la particion ad0s2e en la cual reciden nuestros servidores virtuales (particion /usr del servidor virtual) ademas agregamos los demas grupos de reglas ya que sera la regla devfsrules_jail la que aplicaremos a nuestros servidores virtuales.
Incluimos las siguientes lineas en /etc/rc.conf:
devfs_enable="YES" devfs_rulesets="/etc/devfs.rules" devfs_set_rulesets="devfsrules_jail"
Y ya tenemos listo todo para que al reiniciar se carguen las reglas que queremos aplicar, para poder aplicar las reglas sin reiniciar tendremos que ingresar todas las reglas de los grupos a mano con el comando devfs exceptuando los nombres de los grupos y los “include”:
Moscu# devfs rule -s 5 add hide Moscu# devfs rule -s 5 add path null unhide Moscu# devfs rule -s 5 add path zero unhide ... ... ... Moscu# devfs rule -s 5 add path net2 unhide Moscu# devfs rule -s 5 add path net3 unhide Moscu# devfs rule -s 5 add path ad0s2e unhide
Para aplicar las reglas a nuestro directorio /dev de nuestros servidores virtuales tenemos que detener el servidor virtual logeandonos y ejecutando el comando que anteriormente especificamos o si aun no montamos el sistema devfs en el directorio /dev del servidor virtual lo montamos y ejecutamos:
Moscu# devfs -m /usr/jail/dev rule -s 5 applyset Moscu# devfs -m /usr/jail/dev ruleset 5
En este momento ya podemos iniciar nuestro servidor virtual y las reglas de devfs se aplicaran. Arrancando los servidores virtuales automaticamente
Ya hemos visto como editar el archivo /etc/rc.conf para que se inicien las configuraciones que necesitamos, ahora veamos que lineas tenemos que agregar para que se inicien automaticamente los servidores virtuales al momento del arranque de nuestro FreeBSD real :)
jail_enable="YES" jail_list="Svftp Svhttp" #los nombres de los servidores virtuales #ahora las configuraciones de cada uno de los servidores virtuales jail_Svhttp_rootdir="/usr/jail" jail_Svhttp_hostname="moscuhttp.org" jail_Svhttp_ip="172.16.1.100" #el primer ip alias jail_Svhttp_exec_start="/bin/sh /etc/rc" jail_Svhttp_devfs_enable="YES" jail_Svhttp_devfs_ruleset="devfsrules_jail" #la regla de devfs.rules jail_Svftp_rootdir="/usr/jail2" jail_Svftp_hostname="moscuftp.org" jail_Svftp_ip="172.16.1.101" #el segundo ip alias jail_Svftp_exec_start="/bin/sh /etc/rc" jail_Svftp_devfs_enable="YES" jail_Svftp_devfs_ruleset="devfsrules_jail"
No se olviden de poner las lineas de /etc/rc.conf para natd y devfs que especificamos en sus respectivas secciones
Algunos servicios necesitan opciones especiales para correr dentro de jail ,tal es el caso de Postgresql, si tenemos pensado correr un servidor postgresql dentro de alguno de nuestros servidores virtuales tendremos que setear la variable del kernel security.jail.sysvipc_allowed con el comando sysctl:
Moscu# sysctl security.jail.sysvipc_allowed=1
La variable security.jail.sysvipc_allowed determina si los procesos que estan dentro del jail tienen o no acceso a las primitivas IPC de System V. Aunque esto podria permitir que los procesos de nuestro jail afecten otros procesos fuera del jail.
Otras variables del kernel referentes a jail que podemos manipular son las siguientes:
Actualmente no existe un mecanismo para aplicar estas caracteristicas de forma individual a cada uno de los jails que tengamos asi es que si activamos alguna de estas variables el cambio sera para todos.
Si en algun momento queremos eliminar el jail porque ya no lo vamos a usar y queremos borrar el directorio donde reside el userland de nuestro servidor virtual, primero tendremos que eliminar el flag de inmutable que el proceso de creacion del userland del jail agrega a algunos archivos, esto lo logramos mediante el comando chflags.
Moscu# chflags noschg -R /usr/jail Moscu# rm -r /usr/jail
Cualquier comentario o critica son bienvenidos.
A ACMhUnTeR y todo el equipo de LinuxReal por toda la ayuda con FreeBSD y demas cosas.
A todo el equipo de artec-system.
A los amigos del irc por las platicas siempre tan instructivas/divertidas.