Introducción
En la entrada de hoy les proponemos “cacharrear” un poco con OpenBSD, un sabor de UN*X descendiente de 4.4BSD, y ALIX, una placa de bajo consumo fabricada por PC Engines. El objetivo es montar un cortafuegos barato y de bajo consumo.
Ingredientes
La ISO de instalación de OpenBSD 4.9:
$ wget http://mirror.cdmon.com/pub/OpenBSD/4.9/i386/install49.iso $ sha256sum install49.iso 5e3f9e961c0f37fd12f2d0719df50cfa9a0fdcac93e337f7bb5a52ea1de0f485 install49.iso
Un placa ALIX 2C3, aunque las instrucciones que siguen deberían funcionar con los demás modelos sin demasiados cambios. El sabor 2C3 lleva una CPU AMD Geode LX800 a 500 MHz, 256 MB de RAM y 3 interfaces Ethernet a 10/100. Además, le podemos pinchar…
… una tarjeta Compact Flash de al menos 512 MB de capacidad. En nuestro caso, hemos utilizado una Kingston de 4 GB.
… un lector/grabador de tarjetas Compact Flash. Hemos utilizado un modelo “todo-en-uno” USB estándar.
… un PC con Linux y qemu, para instalar OpenBSD en la tarjeta. Hemos utilizado un i386 con Debian Squeeze y el qemu de paquete.
… un cable serie (RS-232) “null modem” DB9-DB9 (hembra-hembra), para acceder a la consola de la ALIX desde el PC.
Instalación de OpenBSD en la tarjeta
En primer lugar, pinchamos el lector/grabador Compact Flash en el PC. Con un dmesg, podemos obtener el dispositivo que el núcleo le ha asignado. En nuestro caso, ha sido /dev/sdb:
[ 5887.266604] scsi 3:0:0:0: Direct-Access Generic- Compact Flash 1.00 PQ: 0 ANSI: 0 CCS [ 5887.272963] scsi 3:0:0:1: Direct-Access Generic- SM/xD-Picture 1.00 PQ: 0 ANSI: 0 CCS [ 5887.279209] scsi 3:0:0:2: Direct-Access Generic- SD/MMC 1.00 PQ: 0 ANSI: 0 CCS [ 5887.285457] scsi 3:0:0:3: Direct-Access Generic- MS/MS-Pro 1.00 PQ: 0 ANSI: 0 CCS [ 5887.286191] sd 3:0:0:0: Attached scsi generic sg2 type 0 [ 5887.286483] sd 3:0:0:1: Attached scsi generic sg3 type 0 [ 5887.286765] sd 3:0:0:2: Attached scsi generic sg4 type 0 [ 5887.287063] sd 3:0:0:3: Attached scsi generic sg5 type 0 [ 5888.309508] sd 3:0:0:2: [sdd] Attached SCSI removable disk [ 5888.310136] sd 3:0:0:3: [sde] Attached SCSI removable disk [ 5888.310742] sd 3:0:0:1: [sdc] Attached SCSI removable disk [ 5888.311131] sd 3:0:0:0: [sdb] 7806960 512-byte logical blocks: (3.99 GB/3.72 GiB) [ 5888.312523] sd 3:0:0:0: [sdb] Write Protect is off [ 5888.312533] sd 3:0:0:0: [sdb] Mode Sense: 03 00 00 00 [ 5888.312539] sd 3:0:0:0: [sdb] Assuming drive cache: write through [ 5888.315375] sd 3:0:0:0: [sdb] Assuming drive cache: write through [ 5888.315388] sdb: sdb1 [ 5888.323744] sd 3:0:0:0: [sdb] Assuming drive cache: write through [ 5888.323754] sd 3:0:0:0: [sdb] Attached SCSI removable disk
A continuación, la idea es lanzar un qemu que use como disco duro el anterior dispositivo, y arranque desde el CD-ROM, que será la ISO de instalación:
$ qemu -boot d -cdrom install49.iso -hda /dev/sdb
El instalador de OpenBSD arranca. Le indicamos que queremos llevar a cabo una nueva instalación:
Utilizamos un teclado español estándar:
Indicamos diversas opciones; a saber:
- No queremos configurar ningún interfaz de red de momento
- Utilizamos el nombre de dominio por defecto
- No configuramos servidores DNS por el momento
- No configuramos de forma manual la red
- La clave para root: por ejemplo, una segura como alix ;-)
- No queremos que se levante el demonio SSH de momento
- No queremos que se levante el demonio NTP de momento
- No queremos correr X Window
- Importante: queremos la consola en COM0, i.e. el puerto serie
- Importante: 38400 bps es la velocidad por defecto en las ALIX
- No queremos añadir un usuario sin privilegios al sistema
Utilizamos toda la tarjeta para OpenBSD:
Creamos una única partición con todo el espacio para el sistema de ficheros raíz (el esquema de particionado final se explica más adelante):
Instalaremos únicamente los sets bsd, bsd.rd, base49.tgz y etc49.tgz. Esto nos proporciona un sistema base binario mínimo: sin páginas del manual, sin compiladores, sin juegos y sin X Window.
Una vez los paquetes especificados se han instalado, el sistema nos da un prompt:
Por supuesto, lo vamos a aprovechar ;-) Buen momento para tomar un café antes de seguir :-)
Unos pasos más atrás, creamos una única partición con todo el espacio en la tarjeta para el sistema de ficheros raíz. La idea es montar ese sistema de ficheros en modo sólo lectura, de forma que podamos apagar en frío la ALIX sin que se nos corrompa el filesystem. Además, no es conveniente escribir demasiado en memorias Compact Flash, sobretodo si son baratas: se acaban estropeando.
Pero entonces ¿dónde metemos los datos que el sistema escribe a disco? Montaremos /var en un sistema de ficheros en memoria (de tipo mfs, “memory filesystem”) de 65 MB. El truco es copiar el /var “prototipo” en otro directorio (que hemos llamado /protovar) y que el sistema monte su contenido en memoria en /var durante el inicio. Lo hacemos con los siguientes comandos:
Como se observa, también hemos movido los ficheros de dispositivo de pseudo-terminal en los que el sistema escribe (/dev/?typ?) a /protovar/dev y hemos creado los correspondientes enlaces simbólicos para que el sistema los encuentre utilizando la ruta habitual.
La base de datos de paquetes (/var/db/pkg) la pasamos a /etc para que persista entre reinicios. También pasamos /tmp a /var/tmp, para tener un único punto de montaje donde el sistema escribe.
Al final, /etc/fstab queda como sigue:
/dev/wd0a / ffs rw 1 1 swap /var mfs rw,-P=/protovar,-s=65535 0 0
Es decir, un sistema de ficheros raíz (de momento en modo lectura y escritura) y un sistema de ficheros /var que se monta en un espacio de memoria de 65 MB a partir del contenido de /protovar. Al estar en memoria, los cambios hechos a /var no sobreviven a reinicios. Como se observa, no hemos definido memoria swap, ya que el código de firewalling se ejecuta en el núcleo y no produce swapping. Con los más o menos 200 MB de memoria libres que nos quedan, los procesos en modo usuario no deberían producir intercambio.
Por último, paramos el sistema para sincronizar el filesystem con la tarjeta:
Tareas post instalación
Una vez instalado el operativo en la tarjeta, ya podemos extraerla del lector/grabador y pincharla en la ALIX. Antes de encenderla, conectamos el puerto serie del PC con el de la ALIX con el cable “null modem” y lanzamos un programa de terminal en el PC. Así podremos ver el arranque del sistema. Lanzamos por ejemplo un screen (hay gente que prefiere el minicom) contra /dev/ttyS0 (aka COM0, que es el puerto del PC donde hemos conectado el cable) a 38400 bps:
$ screen /dev/ttyS0 38400 /dev/rwd0a: file system is clean; not checking mount_mfs: reduced number of fragments per cylinder group from 8184 to 8112 to enlarge last cylinder group setting tty flags pf enabled starting network starting system logger starting initial daemons:. savecore: /dev/wd0b: Device not configured checking quotas: done. building ps databases: kvm dev. clearing /tmp starting pre-securelevel daemons:. setting kernel security level: kern.securelevel: 0 -> 1 creating runtime link editor directory cache. preserving editor files. starting network daemons: sendmail inetd. starting local daemons:. standard daemons: cron. Fri Sep 23 12:01:19 CEST 2011 OpenBSD/i386 (alix.my.domain) (tty00) login:
Una vez el sistema ha arrancado, iniciamos sesión como root y llevamos a cabo varias tareas post instalación. En primer lugar, deshabilitamos el demonio inetd; ya que no lo vamos a utilizar, que no chupe recursos:
# pkill inetd # echo inetd=NO >> /etc/rc.conf.local
Truncamos el fichero /etc/fbtab:
# mv /etc/fbtab /etc/fbtab.orig # : > /etc/fbtab
Reescribimos /etc/fstab para que el sistema de ficheros raíz se monte en modo sólo lectura al inicio, tal como se ha explicado antes:
# tmp=`tail -1 /etc/fstab` # echo /dev/wd0a / ffs ro 1 1 > /etc/fstab # echo $tmp >> /etc/fstab # tmp= # cat /etc/fstab /dev/wd0a / ffs ro 1 1 swap /var mfs rw,-P=/protovar,-s=65535 0 0
Y lo montamos en modo sólo lectura para esta sesión:
# mount -ur /
Importante: a partir de ahora, para llevar a cabo cambios de configuración sobre /etc, habrá que remontar el sistema de ficheros raíz en modo lectura y escritura, de la siguiente forma:
# mount -uw /
Al escribir nuestros cambios, debemos volver a montarlo en modo sólo lectura:
# mount -ur /
Por último, hemos de tener en cuenta que el reloj de la ALIX es impreciso y no dispone de batería. Para solucionar este problema, podemos planificar una tarea en cron que sincronice el reloj cada hora:
58 * * * * rdate -ncav 1.europe.pool.ntp.org | logger -t rdate
Notar que para que esto funcione, debemos configurar servidores DNS en el sistema. También habría que añadir el anterior comando a /etc/rc.local para que se ejecute durante el arranque.
Configuración de la red
Lo primero es activar el IP forwarding para poder pasar paquetes de un interfaz de red a otro:
# echo net.inet.ip.forwarding=1 >> /etc/sysctl.conf # sysctl net.inet.ip.forwarding=1 net.inet.ip.forwarding: 0 -> 1
Los interfaces de red son vr0, vr1 y vr2. En nuestro sistema, vr0 se ha asignado al interfaz más cercano al conector de la fuente de alimentación, vr1 al central, y vr2 al que resta. La configuración de los interfaces habrá que realizarla por lo tanto, tal como se explica en la documentación, mediante los ficheros /etc/hostname.vr0, /etc/hostname.vr1, y /etc/hostname.vr2.
Por ejemplo, le ponemos la IP 192.168.1.1/24 a vr0 (interfaz que toca con Internet), y la IP 192.168.2.1/24 a vr1 (interfaz que toca con nuestra red interna. La puerta de enlace (192.168.1.254) se especifica en /etc/mygate:
# mount -uw / # echo inet 192.168.1.1 255.255.255.0 NONE > /etc/hostname.vr0 # echo inet 192.168.2.1 255.255.255.0 NONE > /etc/hostname.vr1 # echo 192.168.1.254 > /etc/mygate # sh /etc/netstart # mount -ur / # netstat -rn | head Routing tables Internet: Destination Gateway Flags Refs Use Mtu Prio Iface default 192.168.1.254 GS 0 0 - 8 vr0 127/8 127.0.0.1 UGRS 0 0 33200 8 lo0 127.0.0.1 127.0.0.1 UH 0 0 33200 4 lo0 192.168.1/24 link#1 C 1 0 - 4 vr0 192.168.1.254 link#1 HLc 1 0 - 4 vr0 192.168.2/24 link#2 C 0 0 - 4 vr1 # ifconfig vr0 | grep 'inet ' inet 192.168.1.1 netmask 0xffffff00 broadcast 192.168.1.255 # ifconfig vr1 | grep 'inet ' inet 192.168.2.1 netmask 0xffffff00 broadcast 192.168.2.255
Firewalling
La configuración de Packet Filter (PF), el motor de firewalling de OpenBSD, está excelentemente documentada en el FAQ de PF y en diversas páginas del manual. Básicamente, las reglas se guardan en /etc/pf.conf. Para cargarlas (tanto si PF está activo como si no), se haría un
# pfctl -f /etc/pf.conf
Para activar el firewall (por defecto ya se activa durante el arranque), un:
# pfctl -e
y para desactivarlo (no descarga las reglas), un:
# pfctl -d
El siguiente conjunto de reglas básico, basado en el del FAQ, bloquea(y registra) todo el tráfico excepto el proveniente de la red interna, el SSH a la propia ALIX y los ICMP echo request.
# interfaz que conecta con Internet ext_if="vr0" # interfaz que conecta con la red interna int_if="vr1" # no aplicar filtros sobre loopback set skip on lo # por defecto, bloquear y registrar todo lo entrante block in log # si ya ha entrado, permitir que salga pass out quick # antispoofing para la interna y la loopback antispoof quick for { lo $int_if } # permitir la conexion por SSH a la propia ALIX pass in on egress inet proto tcp from any to (egress) \ port 22 # permitir ICMP echo request pass in inet proto icmp all icmp-type echoreq # permitir todo lo que llegue desde la interna pass in on $int_if
Otras opciones
Distribuciones como m0n0wall o pfSense (ambas basadas en FreeBSD) soportan placas ALIX y permiten montar un cortafuegos con interfaz web (entre otras cosas) de forma cómoda y rápida. También existen “embebedores” de OpenBSD en tarjetas flash como flashdist o flashrd.
Excelente post, muy chulo! Un motivo más para ponerme un día a trastear con *bsd.
Mola¡