Normalmente, si tenemos una raspberry pi en casa para nuestros cacharreos, ésta no suele estar expuesta directamente a Internet, sino que el router es el encargado de filtrar en cierta medida qué le llega y no desde el exterior. Pero cuando tenemos una máquina como puede ser un VPS sencillito, no disponemos de ese nivel de seguridad, sino que lo tenemos completamente expuesto al exterior. Es por ello que nos es más que necesario contar con la ayuda de un cortafuegos (firewall) que nos haga de muro de contención, junto con otras medidas como es, por ejemplo, fail2ban.

En este artículo veremos cómo podemos montar y gestionar de manera sencilla un cortafuegos en nuestro servidor, haciendo uso para ello de UFW.

UFW (Uncomplicated FireWall) es un cortafuegos diseñado para ser de fácil uso y desarrollado para Ubuntu. Utiliza la línea de comandos para configurar las iptables usando un pequeño número de comandos simples. Se encuentra escrito en python y nos abstrae de la, en muchas ocasiones, excesiva complejidad que pueden llegar a suponer el manejo directo de iptables.

Aquí trataremos su uso y cómo configurarlo para nuestro servidor de manera que sea lo más seguro posible, pero si queréis ver más información o profundizar más en su uso, podéis consultar su wiki (en inglés).

Configuración de UFW para nuestro servidor

Para instalar nuestro cortafuegos, tan sólo tenemos que teclear la orden sudo apt install ufw2 (en sistemas basados en Debian). Una vez instalado, por defecto se encontrará inhabilitado, por lo que antes de habilitarlo configuraremos todo lo necesario (ya que, en cuanto lo habilitemos, si tenemos algún puerto por el que estemos conectados, como el SSH, y no lo hemos habilitado antes, se nos cortará la conexión y no podremos entrar).

Empezamos la configuración editando el fichero /etc/default/ufw con la configuración por defecto, y añadiremos o modificaremos las siguientes líneas:

IPV6=no # Lo pondremos a yes si nuestro servidor soporta IPv6

DEFAULT_FORWARD_POLICY="ACCEPT" # Habilitamos el forward por defecto, para poder navegar desde una conexión VPN al exterior.
Configuración modificada del fichero /etc/default/ufw

A continuación, habilitaremos el IP forwarding añadiendo o descomentando la línea net/ipv4/ip_forward=1 en el fichero /etc/ufw/sysctl.conf.

Para que nos funcionen las reglas con el forwarding, deberemos modificar el fichero de /etc/ufw/before.rules y añadir al principio del todo la siguiente configuración:

# nat Table rules

*nat:POSTROUTING ACCEPT [0:0]

# Forward traffic from eth1 through eth0.
-I POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADE -m comment --comment openvpn-nat-rule
-A POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADE

# don't delete the 'COMMIT' line or these nat table rules won't be processed
COMMIT
Configuración del fichero /etc/ufw/before.rules

Con estos pasos, tenemos nuestro cortafuegos preparado para gestionar las conexiones hacia el exterior desde nuestra VPN y viceversa. A continuación, pasamos a añadir las reglas que queremos que lo gobiernen.

Gestionar las reglas de UFW

Comportamiento por defecto

UFW tiene un comportamiento por defecto para los flujos de entrada y salida que podemos definir de manera estándar. En un servidor privado como el nuestro, lo ideal es permitir todas las conexiones salientes (ya que estará gestionado y usado por nosotros y ya) y denegar, por defecto, todas las entrantes (mayor seguridad). Para ello, ejecutaremos las siguientes órdenes:

sudo ufw default deny incoming
sudo ufw default allow incoming

Permitir conexiones

Para permitir conexiones entrantes (ya que, por defecto, hemos denegado todas), usaremos el comando sudo ufw allow, seguido de lo que queramos permitir (todas las conexiones entrantes, todas las que vengan de una IP o subnet, a un puerto específico...). A modo de ejemplo para este post, haremos la siguiente configuración:

  • Permitiremos todas las conexiones de la red local (para que el servidor no tenga impedimentos en sus peticiones a localhost).
  • Abriremos el puerto SSH al exterior para poder conectarnos desde cualquier lado. ¡¡¡MUCHO OJO CON ESTO!!!
  • Abriremos el puerto 443 por TCP para las conexiones por HTTPS a nuestro servidor web y el 80 para las HTTP.
  • Permitiremos todas las conexiones de la subnet de nuestra VPN, para poder navegar sin impedimentos desde ella.
  • Habilitaremos la conexión del puerto en el que tengamos nuestra VPN escuchando (¡o de lo contrario no podremos conectarnos!).

Con este esquema en mente, deberemos ejecutar los siguientes comandos:

sudo ufw allow from 127.0.0.1
sudo ufw allow ssh # Abrirá el puerto configurado en el servicio SSH
sudo ufw allow 443/tcp
sudo ufw allow 80/tcp
sudo ufw allow from 10.8.0.0/24
sudo ufw allow 3000 # Si nuestra VPN está escuchando en otro puerto, aquí lo especificaríamos
Reglas para permitir conexiones en UFW

Con esta configuración hemos cubierto los puntos detallados justo encima de ella. Como veis, apenas necesitan explicación adicional, se entienden bastante bien y la sintaxis nos permite detallar todo el grano fino que queramos (abrir un puerto; abrirlo para una IP o subnet concreta; un puerto, una IP y un protocolo específicos...). ¡Las posibilidades son ilimitadas!

IMPORTANTE: El orden en el que se ejecutan las reglas de UFW importa, por lo que se deben crear o tener en el orden que queremos que se evalúen, normalmente de la más restrictiva a la más permisiva.

Una vez creadas las reglas, sólo nos resta activar nuestro cortafuegos, por lo que deberemos ejecutar la orden sudo ufw enable y empezará a entrar en funcionamiento.

IMPORTANTE: Recordad que, en cuanto habilitemos UFW y estamos accediendo a un servidor por SSH, si el acceso al puerto SSH no está habilitado, perderemos la conexión y ya no podremos acceder. ¡Aseguraos primero de que habéis creado bien las reglas!

Para deshabilitar UFW nos basta con ejecutar la orden sudo ufw disable y, si lo tenemos activo y hemos modificado, añadido o eliminado alguna regla, deberemos ejecutar sudo ufw reload para que tenga en cuenta la nueva configuración. Y si quieres borrar todo y empezar de cero, el comando sudo ufw reset volverá al cortafuegos al estado inicial de tablero vacío y lo desactivará.

Denegar conexiones

Al igual que permitimos ciertas conexiones, también podría ser que queramos denegar alguna específica. Por ejemplo, si quisiéramos bloquear el acceso a las conexiones HTTP, podríamos ejecutar los comandos sudo ufw deny from 10.20.30.40.

Listar el estado de las reglas de UFW

Una vez tenemos nuestro cortafuegos corriendo y configurado, con el tiempo nos hará falta modificarlo, bien porque hemos metido servicios que requieren abrir puertos, bien porque hemos retirado otros y no queremos tener el puerto abierto porque sí, bien porque queremos refinarlo... Para todo eso, lo primero que necesitamos es conocer su estado.

Mediante el comando sudo ufw status veremos un listado de todas las reglas que se están aplicando, y si ejecutamos sudo ufw status numbered veremos además un número asociado a cada una de ellas. Este número está relacionado con el orden en el que se ejecutan las reglas. Un ejemplo sería (acorde a lo que hemos configurado en el punto anterior):

foo@barmachine:~$ sudo ufw status numbered

Status: active

     To                         Action      From
     --                         ------      ----
[ 1] Anywhere                   ALLOW       127.0.0.1
[ 2] 22/tcp                     ALLOW       Anywhere
[ 3] 443/tcp                    ALLOW       Anywhere
[ 4] 80/tcp                     ALLOW       Anywhere
[ 5] Anywhere                   ALLOW       10.8.0.0/24
[ 6] 3000/tcp                   ALLOW       Anywhere
[ 7] Anywhere                   DENY IN     10.20.30.40
Ejemplo de listado de reglas en UFW activas

Si quisiéramos eliminar una de ellas, bastaría con ejecutar el comando sudo ufw delete y añadir el número de la que queremos eliminar. Por ejemplo, sudo ufw delete 6 borraría la regla que abre el puerto a nuestra VPN. Pero tan sólo lo haría del listado, para que tuviera efecto, habría que reiniciarlo con el comando sudo ufw reload o bien deshabilitando y habilitando de nuevo UFW.

El comando sudo ufw verbose nos sacará información detallada de la configuración de nuestro cortafuegos, como el estado en el que está o el comportamiento por defecto que le tenemos definido.

El orden en las reglas

Como comentaba antes, el orden es importante. Si vemos el ejemplo anterior, nuestro servidor permitiría el acceso a los puertos 22, 80, 443 y 3000 desde cualquier ubicación, aunque tengamos denegado el acceso a la IP 10.20.30.40, ya que las otras reglas se evaluarían antes y, en el momento que se evalúa una, se detiene la evaluación del resto, con lo que esta última regla no serviría de nada.

Para que fuera efectiva, debería ser de las primeras. Pero, ¿qué pasa si ya hemos creado el resto y nos hemos dado cuenta ahora? Pues borramos todas y volvemos a empezar Tenemos la opción de insertar una regla en el punto que deseemos. Para ello, en lugar de añadir la última regla, lo que haremos será ejecutar el comando sudo ufw insert 2 deny from 10.20.30.40, con lo que obtendremos el resultado siguiente:

foo@barmachine:~$ sudo ufw status numbered
Status: active

     To                         Action      From
     --                         ------      ----
[ 1] Anywhere                   ALLOW IN    127.0.0.1
[ 2] Anywhere                   DENY IN     10.20.30.40
[ 3] 22/tcp                     ALLOW IN    Anywhere
[ 4] 443/tcp                    ALLOW IN    Anywhere
[ 5] 80/tcp                     ALLOW IN    Anywhere
[ 6] Anywhere                   ALLOW IN    10.8.0.0/24
[ 7] 3000/tcp                   ALLOW IN    Anywhere
Resultado tras insertar una regla en UFW

Ahora sí, la IP 10.20.30.40 tendrá bloqueado el acceso a nuestro servidor y el resto de orígenes se verán sometidos al resto de reglas que tenemos definidas.

¡Pues ya estaría! Con esto tendríamos nuestro servidor un poquito más protegido de conexiones no deseadas, pero para que sea realmente efectivo no debemos olvidarnos de combinar esta herramienta con otras de seguridad y monitorización de nuestro sistema.

Y recordad: Ciertos puertos como el SSH nunca deberían estar en el valor por defecto (22) ni expuestos al exterior salvo que sea realmente necesario. Incluso en ese caso, tan sólo deberíamos abrirlo cuando fuera necesario si podemos. Como ejemplo, yo no lo tengo abierto al exterior, sino que sólo es accesible desde mi VPN, de tal manera que, si quiero conectarme por SSH a mi servidor, primero debo estar conectado a la VPN.