lunes, 8 de agosto de 2011

Punk Fluid, the Shorewall


 Para los que ya se cansaron de saber que sus máquinas están abiertas al mundo y no se animaron a jugar con las herramientas que Netfilter posee, en este artículo veremos algunos conceptos iniciales sobre la teoría de filtrado de paquetes en GNU/Linux, apuntando a una implementación del producto Shorewall para una instalación muy típica.



La problemática

El escenario planteado comienza a tomar forma cuando vemos el estado inicial de nuestra instalación, y el punto al que queremos llegar. De esa forma veremos cómo encarar un proyecto en el cual tengamos que implementar un sistema del tipo firewall, utilizando la mayor cantidad de filtros, redireccionamientos, y demás juguetes posibles. Y todo esto lo haremos implementando el producto Shorewall para simplificar nuestra dura vida.

Originalmente nuestra red sólo tiene una salida a internet, con dirección IP pública variable o fija (no modifica mucho el contenido de este artículo que esto varíe, ya que en el caso de no tener una dirección IP fija, de seguro se podrá utilizar algún servicio de DNS dinámico para los casos de IP variable, como ser dyndns, o no-ip). A través de un pequeño equipo basado en GNU/Linux con dos tarjetas de red, una que se conecta con esta salida pública, y otra apuntando a la red privada, es que todos los integrantes de nuestra empresa están obteniendo salida a Internet utilizando un proxy (léase Squid, o lo que se prefiera. En nuestro caso pensamos en Squid) configurado en el puerto 8008.

Veamos este diagrama esquemático para tener una idea más acabada de la instalación existente:



El desafío planteado incluye varios elementos a tener en cuenta, como ser:

  1. Todo cliente que quiera salir a Internet directamente, y sin configurar su proxy en su sistema, deberá ser redirigido automáticamente al puerto 8008.
  2. Todo protocolo de red diferente de la navegación por Internet deberá salir al mundo utilizando enmascaramiento de direcciones IP.
  3. Sólo habrá un cliente que tendrá permitido salir a Internet sin pasar por el proxy, y tendrá la dirección IP 10.100.100.10.
  4. La red interna continuará utilizando el rango de direcciones IP 10.100.100.0/24.
  5. Se implementará un servidor Web interno, que no deberá ser accedido desde afuera de la red. Su dirección IP será 10.100.100.50.
  6. Se deberá implementar un servidor de aplicaciones que utilice los datos de la base que se encuentra en un servidor con dirección IP 10.100.100.100. El servidor es PostgreSQL, por lo que se accede a sus datos a través del puerto 5432. El software del servidor de aplicaciones es un Tomcat, que usa el puerto TCP 8080 para funcionar.
  7. La puerta de enlace predeterminada de todos los puestos clientes será 10.100.100.1, es decir, será el servidor que ahora es un proxy.

De acuerdo a estas premisas, vemos que el esquema de red original al menos a nivel físico no cambiaría demasiado. Sólo hay un punto que es fundamental y que se modificará, que es el correspondiente a dónde se pondrá el servidor de aplicaciones.

Como se pretende que dicho servidor sea visible desde el mundo exterior, y que se conecte con un servidor de bases de datos, tenemos que pensar en que si lo ubicamos dentro de la red interna, quien ingrese a él desde Internet, también estará en posición de violar las demás máquinas de la red interna. Para ello, tendremos que crear una nueva red que permitirá sólo el ingreso desde Internet a través del puerto 80, y sólo el contacto con el servidor de bases de datos a través del puerto 5432. Así es como aparece el concepto de zona desmilitariada, o DMZ.

La DMZ es una red que permitirá esta comunicación, de forma que si alguien pudiera ingresar y romper nuestro servidor de aplicacciones, no podría acceder a más que el puerto 5432 de nuestro servidor de bases de datos. Desde afuera de nuestra red, los clientes deberán apuntar a un URL normal, sin invocar el puerto 8080, por lo que de alguna forma tendré que redirigir el puerto 80 al 8080 del servidor de aplicaciones.

Por otro lado, si estamos hablando de una nueva red, tendremos que pensar, también, en un nuevo rango de direcciones IP. Necesitamos que estas direcciones sean privadas, por lo que hemos definido que las mismas se encuentren en el rango 10.100.150/0. La pata del servidor firewall tendrá la dirección 10.100.150.1, y el servidor Tomcat tendrá la dirección 10.100.150.10.

Con estos puntos en mente, entonces, el esquema de nuestra red queda modificado para tomar esta forma:



Si se quiere pasar a meter mano, no hace falta leer las secciones con la teoría de lo que implementaremos. Aún así, recomiendo dejar de lado el pragmatismo por un instante, y leerlas para comprender qué es lo que estaremos haciendo, y así poder modificar lo que se exponga en este artículo de forma acorde a nuestra instalación.

Conceptos

Netfilter es el nombre que recibe el conjunto de porciones de código que están dentro del kernel de GNU/Linux y que le permiten registrar el comportamiento de las funciones de red utilizadas por cada paquete cuando pasa por un sistema y hace uso de ellas.
Por ejemplo, si un usuario ejecuta el comando “ping” para verificar la existencia de un sistema en la red, la máquina de destino de ese comando debe tener un programa que escuche el protocolo que usa el “ping” (ICMP), y por lo tanto algunas funciones en el kernel que registren el uso de los recursos de red para esta tarea.
A través de Netfilter podré modificar el comportamiento de cada paquete de red que llegue o salga de una máquina.
Lo más común del mundo es conocer Netfilter no por su mismo nombre, sino por la implementación de programas como “iptables” en los kernels 2.4 y 2.6, por “ipchains” en los kernels 2.2, y por “ipfwadm” en los kernels 2.0.

¿Cómo es que funciona, entonces, algo como iptables, y cómo nos ayudará a realizar nuestra tarea? Sencillo, iptables conservará una serie de reglas de coincidencia que permitirán la ejecución de determinadas acciones cada vez que un paquete de red cumpla con alguna de ellas. Entonces, de seguro nos encontraremos con dos partes bien definidas en cada regla:

  • Una regla de coincidencia, donde podré especificar protocolo, puerto, dirección IP de origen y de destino, y conjunto de reglas a la que quiero agregarla.
  • Una acción o serie de acciones a ejecutar sobre los paquetes de red que coincidan con dicha regla.

Por ejemplo, para el caso que queremos implementar, algunas reglas serían:

  • Si un paquete de red quiere ingresar vía Internet, y apunta al puerto 80, redirigirlo al puerto 8080 del servidor 10.100.150.10 que se encuentra en la DMZ.
  • Si un paquete de red tiene origen en la red interna, tiene dirección IP diferente de 10.100.100.10, y quiere acceder a Internet, redirigirlo al puerto 8008.
  • Impedir el ingreso de cualquier paquete de red, no importa su origen, al firewall o cualquier otra red interna, a menos que no ingrese explícitamente por el puerto 80.

La lista de reglas en “pseudocódigo” siguen para representar la realidad de nuestras premisas. He escrito sólo algunas aquí, que repasaremos en el momento de realizar la implementación.

Ahora bien, iptables tiene una sintáxis que no es exáctamente amigable a la hora de generar reglas. Puede ser engorroso, algo confuso, y muchas veces un error nos lleva a tener un problema de seguridad grave. Aquí es donde el programa Shorewall hace su aparición, demostrándonos que todo se puede simplificar considerablemente cuando se quiere.



Shorewall

Shorewall, una abreviatura de “Shoreline Firewall”, como comentamos más arriba, viene a ser la herramienta que simplificará la configuración de iptables al punto de volverse casi documentada por sí misma. Lo que antes es una serie de reglas larguísima, ahora es sólo unas cuantas líneas en algunos archivos. Cuando Shorewall se ejecuta lee estas líneas de configuración, y con la ayuda de iptables genera todas las reglas necesarias para hacer lo que hemos definido. Y iptables, como vimos más arriba, hace uso de Netfilter para ello. Ahora las piezas del rompecabezas comienzan a encastrar, ¿no?.

Un punto importante a tener en cuenta es que Shorewall no es un proceso demonio que estará en ejecución todo el tiempo, sino que se ejecuta para realizar sus configuraciones, y luego finaliza, por lo que carece de sentido verificar si está o no en ejecución, y sí el verificar si las reglas que hemos configurado están activas. Para esto último, una mirada rápida al archivo /var/log/messages o /var/log/kern.log serán suficientes, así como la ejecución de “iptables -L”.

Shorewall se instala muy fácilmente. Se utilizará “apt-get” o “rpm” de esta forma:

# apt-get install shorewall
(para los sistemas operativos basados en Debian, como ser el mismo Debian o Ubuntu)

Los paquetes para Red Hat, CentOS, Fedora, Suse y demás distros basadas en .rpm se pueden bajar directamente de la página de Shorewall (http://shorewall.net), e instalar con el comando “rpm -Uvh PAQUETE.rpm”.

Una vez instalados los paquetes, encontraremos ciertos archivos y directorios nuevos, a saber:

  • Directorio /etc/shorewall: en él encontraremos todos los archivos de configuración de este paquete a nivel de reglas.
  • Archivo /etc/default/shorewall: ciertas configuraciones de caracter más general se encontrarán en este archivo, como ser la orden de ejecutar o no Shorewall cuando se invoque. Sirve para generar la configuración sabiendo que nadie va a ejecutarlo y, por error, dejarnos por ejemplo sin acceso al servidor firewall.
  • Archivo /etc/init.d/shorewall: este archivo estará relacionado por medio de links simbólicos con los correspondientes en los directorios /etc/rcX.d.
  • Archivo /var/log/kern.log: en este archivo, típicamente, se dejarán los mensajes correspondientes a las acciones que se han ejecutado a nivel de kernel cuando un paquete de red coincidió con alguna regla.

Con todo esto instalado, comenzaremos a transformar nuestras premisas en reglas reales.


Reglas y escuadras

Shorewall utiliza para su proceso de configuración una serie de alias que permiten asociar zonas de red a tarjetas o conexiones de red. Una zona de red será aquella que tenga determinada condición común, como ser “Red Interna”, “Red Externa”, “Zona Desmilitarizada”, etc.

En nuestro ejemplo, consideraremos tres zonas de red diferentes; la red interna, que será la que corresponde a todo lo que está dentro de nuestra propia red y que queremos proteger del mundo exterior; la red externa, que comprende ni más ni menos que a todo Internet; y finalmente la zona desmilitariada, que será aquella que contendrá sólo los servidores que queremos exponer parcialmente hacia la red externa, y parcialmente hacia la red interna, sin disminuir por ello el nivel de seguridad.

Sus nombres de zona serán, entonces, “lan” para la red interna, “wan” para la red externa, y “dmz” para la zona desmilitarizada.

Suponemos que nuestro equipo firewall dispone de tres tarjetas de red, denominadas:

  • eth0: corresponde a la red interna, o zona “lan”.
  • eth1: corresponde a la red externa, o zona “wan”.
  • eth2: corresponde a la red intermedia, o zona “dmz”.
  • fw: si bien no es una tarjeta de red, se podrán realizar conexiones hacia y desde él.

Debemos, entonces, asociar cada tarjeta o conexión de red a una zona dentro de los archivos de configuración de Shorewall. Para ello, editaremos o crearemos el archivo /etc/shorewall/interfaces con el siguiente contenido:

lan eth0
wan eth1
dmz eth2

Sencillo, ¿no? Ahora bien, como Shorewall soporta tanto zonas configuradas con Ipv4, como aquellas con Ipv6, procederemos a editar o crear el archivo /etc/shorewall/zones, donde definiremos cuál de las dos usaremos, o si una zona se trata del mismo firewall. En nuestro caso, será Ipv4:

fw firewall
lan ipv4
wan ipv4
dmz ipv4

El motivo por el cual se debe dar de alta el firewall dentro de las zonas es que se podrían generar reglas que se apliquen sólo cuando determinado tráfico de red es hacia o desde el firewall, y no a través de él.

Teniendo las asociaciones listas, veremos cuál es el formato que tienen dos archivos importantes: /etc/shorewall/policy y /etc/shorewall/rules.

En general, el formato será basado en columnas que definirán:

  • Resultado esperado: es el resultado que pretendemos cuando un paquete de red coincide con una determinada regla. Por ejemplo, podríamos especificar:
  • ACCEPT: el paquete de red es aceptado.
  • DROP: el paquete de red es descartado.
  • REJECT: el paquete de red es denegado. Difiere del anterior en que quien lo envía toma conocimiento de esta acción.
  • DNAT: Se ejerce “NAT” sobre la dirección de destino. En nuestro caso, todo lo que llegue al puerto 80 del servidor firewall, será redirigido al puerto 8080 del servidor de aplicaciones, y las respuestas de dicho servidor saldrán como si nunca hubiera habido un redireccionamiento. Por eso se llama “Destination NAT”.
  • SNAT: si un cliente de la red interna debe realizar un pedido a un servidor en la red externa, su dirección será reescrita de forma tal que cuando el servidor responda, dicha respuesta llegue nuevamente al cliente en cuestión. Por eso se llama “Source NAT”.
  • Cliente: es el punto donde se genera la comunicación de red. Por ejemplo, en el caso de una conexión desde Internet hacia nuestro equipo, la máquina que hace el llamado por medio de su navegador será el cliente.
  • Servidor: es el punto al cual llegarán los paquetes de red. En el caso del servidor del proxy, por ejemplo, el cliente será cualquiera de los puestos de trabajo, y el servidor estará en algún lugar de internet.
  • Familia de protocolos: en este caso, la familia de protocolos podrá ser “tcp”, “udp”, “icmp”, etc.
  • Puerto: en este caso, se registrará el puerto al cual se invoca desde el lado del cliente. En el ejemplo del servidor de aplicaciones, el puerto sería 80.
  • Comentarios: en este campo se colocarán comentarios que nos guíen sobre qué afecta esa regla. Por ejemplo, documentar nuestros archivos con algo del estilo “Sólo pasan desde Internet hacia 10.100.150.10” puede ser muy útil si queremos en algún momento modificar las reglas.

Existe un archivo importante que es /etc/shorewall/masq. En ese archivo configuraremos las diferentes redes que enmascararán sus direcciones IP cuando deban acceder a otras. En nuestro caso, lo haremos con los puestos que salgan a Internet y que utilicen un puerto diferente del 80, redirigido al proxy que tenemos en el puerto 8008.

El formato de este archivo también se basa en el uso de columnas, o campos, y sus usos son los siguientes:

  • Interface: se especifica en este caso cuál será el destino del cual se espera recibir respuestas cuando se enmascare una dirección o rango de direcciones IP. Por ejemplo, si pensamos en todo Internet, tendremos que colocar 0.0.0.0/0.
  • Dirección o rango de origen: aquí configuraremos la dirección o rango de direcciones IP que serán enmascaradas cuando deban acceder alguna dirección especificada en el campo anterior. Por ejemplo, para los puestos cliente, tendremos que colocar 10.100.100.0/0.

Por último, veremos un archivo más, que también se debiera editar o crear, y que es el /etc/shorewall/policy. Este archivo contendrá políticas generales, fuera de lo que son las reglas, que se aplicarán al firewall en general. Su formato en sí es muy parecido al /etc/shorewall/rules, también basado en columnas:

  • Cliente: como vimos antes, desde donde se generan las conexiones.
  • Servidor: ídem, hacia donde van las conexiones.
  • Política: qué se hará en forma predeterminada. Las acciones también podrán ser “ACCEPT”, “DROP”, etc.
  • Nivel de log: en este campo definiremos si queremos que se genere un registro en el log cada vez que se produzca un error (“err”), sólo por cuestiones informativas (“info”), u otros casos. Tengamos en cuenta que puede ser bastante grande un archivo de log cuando el tráfico es fuerte, por lo que esto se debe regular bien.

Ahora, definiremos qué es lo que se hará en cada zona, dependiendo de las premisas de que partimos. Para ello, editaremos o crearemos el archivo /etc/shorewall/rules. Veamos cada una de estas premisas.

Premisas 1 y 3: Todo cliente que quiera salir a Internet directamente, y sin configurar su proxy en su sistema, deberá ser redirigido automáticamente al puerto 8008. Sólo habrá un cliente que tendrá permitido salir a Internet sin pasar por el proxy, y tendrá la dirección IP 10.100.100.10.

Para lograr esto, tendremos que pensar que el cliente será cualquier máquina de la red 10.100.100.0/24 que quiera salir a internet. Por lo tanto, el cliente será “lan”, el servidor será el puerto 8008, el protocolo será de la familia “tcp”, el puerto será el 80, y la acción a realizar será “REDIRECT” con todos ellos, a excepción del cliente 10.100.100.10, que podrá salir a Internet sin pasar por este proxy. La regla resultante será, entonces:

REDIRECT lan:!10.100.100.10 8008 tcp www

Notemos que en la sección del cliente, estamos agregando todo lo que provenga de “lan”, y exceptuando la dirección 10.100.100.10 colocándole un “!” antes. Si tuviéramos más máquinas que exceptuar, las agregaríamos separadas por comas, sin espacios. Si por ejemplo, tuviéramos que exceptuar las direcciones 10.100.100.10 y 10.100.100.9, esa expresión se vería reemplazada por “!10.100.100.10,10.100.100.9”.

Premisa 2: Todo protocolo de red diferente de la navegación por Internet deberá salir al mundo utilizando enmascaramiento de direcciones IP.

Para lograrlo, veamos cómo configurar el archivo /etc/shorewall/masq siguendo los lineamientos que vimos antes:

0.0.0.0/0 10.100.100.0/0

Así de sencillo es configurar el enmascaramiento de direcciones IP.

Premisa 5: Se implementará un servidor Web interno, que no deberá ser accedido desde afuera de la red. Su dirección IP será 10.100.100.50.

En este caso, tendremos que realizar, como acción un NAT en el destino, por lo que la acción se llamará “DNAT”. El cliente será Internet en general, el servidor estará en la zona dmz, específicamente en la dirección 10.100.150.10, el puerto invocado por el cliente será el 80, pero el sistema tendrá que enviar los pedidos desde este puerto al 8080. La regla entonces quedará así:

DNAT wan dmz:10.100.105.10:8080 tcp 80

Premisa 6: Se deberá implementar un servidor de aplicaciones que utilice los datos de la base que se encuentra en un servidor con dirección IP 10.100.100.100. El servidor es PostgreSQL, por lo que se accede a sus datos a través del puerto 5432. El software del servidor de aplicaciones es un Tomcat, que usa el puerto TCP 8080 para funcionar.

En este caso el tema se pone un poco, y solo un poco más complicado. El cliente, como vemos, es el servidor de aplicaciones que tiene la dirección 10.100.150.10 y está ubicado en la zona “dmz”, y el servidor se encuentra en el puerto 5432 de la dirección IP 10.100.100.100 de la zona “lan”. Lo que se hará a nivel de acción será aceptar estos pedidos. La regla entonces quedará así:

ACCEPT dmz:10.100.150.10 lan:10.100.100.100 tcp 5432

Bueno, tal parece que ya tenemos todas las reglas en su lugar. Sólo nos queda una sección de la configuración que tocar a nivel de reglas, y es el archivo /etc/shorewall/policy.

Una de las cosas que deberé especificar es que todo lo que no esté explícitamente aceptado, cuando se trate de una conexión desde Internet hacia la red interna, o hacia el mismo firewall, estará denegado. Eso se hace sólo con declarar lo siguiente:

wan all DROP err

Al agregar como servidor “all” le especificamos a Shorewall que no importa a qué zona un paquete de red se esté dirigiendo, deberá ser eliminado.

Si lo que deseo es un nivel de logueo exhaustivo, en este archivo declararé las reglas:

lan all ACCEPT info
fw all ACCEPT err

Con estas reglas, ya no queda mucho más por configurar para lograr las premisas que fueron planteadas.

Ahora, podremos modificar el archivo /etc/default/shorewall cambiando la entrada:

startup=0

...por:

startup=1
IMPORTANTE: Veamos que no hemos habilitado el SSH hacia nuestro firewall desde ninguna zona. Si lo queremos dejar habilitado para conectarnos desde nuestra red interna, deberemos agregar una entrada como la siguiente en /etc/shorewall/rules:

ACCEPT lan fw tcp 22

...y si queremos acceder a nuestro firewall desde Internet, la regla cambiará para tomar esta forma:

ACCEPT wan fw tcp 22

Con esto configurado, sólo debemos ejecutar Shorewall con el comando:

# /etc/init.d/shorewall start

Interfases gráficas

Si bien vemos que la configuración de un firewall profesional, gracias a Shorewall es notablemente sencilla, podría ocurrir que un fanático de los navegadores se encuentre en medio de nuestra tropa de sysadmins, por lo que tendremos que implementar alguna ventana que lo haga felíz.

Una de las aplicaciones difundidas, y de mucho uso, es el denominado “Webmin”, que posee un módulo específico para la administración de firewalls basados en Shorewall.
Recordemos que Webmin usa generalmente el puerto 10000 para funcionar, por lo que antes de activar el firewall debemos agregar una regla que nos permita conexiones desde una determinada red hacia él.

Esto lo lograremos agregando a /etc/shorewall/rules una línea como la siguiente si queremos que se acceda Webmin desde la red interna:

ACCEPT lan fw tcp 10000

...o como la siguiente si queremos que se acceda desde Internet:

ACCEPT wan fw tcp 10000

Ahora instalamos el paquete webmin, su módulo de control de Shorewall, relanzamos los procesos de shorewall con:

# /etc/init.d/shorewall restart

Y con esto terminamos nuestra tarea, dejando a nuestro sysadmin amigo con una sonrisa en su cara, y una ventanita como ésta en nuestro navegador:



Conclusión

Con estos pocos comandos, como vimos más arriba, hemos configurado un firewall de características profesionales. Con él tenemos protegida nuestra red interna, redirigida nuestra red externa, y hasta contamos con una zona desmilitarizada donde podremos colocar nuestro servidor de aplicaciones conectado a una base de datos sólo por un puerto.

Un aspecto también importante de este tipo de configuraciones es que salvo un consumo demasiado elevado a nivel de tráfico de red, máquinas muy chicas, y que sólo posean la capacidad de tener varias tarjetas de red genéricas pueden servir para armar un verdadero sistema de seguridad perimetral. Espero que hayan disfrutado de los conceptos aquí volcados, y de la configuración de ejemplo que hemos realizado.

Los espero el mes que viene, con más artículos técnicos para depilarnos el flequillo. ¡Nos vemos!