Uncomplicated Firewall (ufw)

Este es uno de los interfaces de firewall mas usados en linux. Al igual que FirewallD, su uso nos facilita muchísimo la configuración de iptables. Ya sabemos por el anterior capítulo que el verdadero firewall de linux es iptables y que desde firewalld, ufw y muchos otros interfaces lo que hacemos realmente es crear tablas o reglas dentro de iptables pero con mucha menos dificultal.

Una duda que puede surgirnos es si ufw es una interfaz de iptables, ¿qué ocurre si habilitamos UFW después de crear reglas con IPTABLES?

La respuesta es que se sobreescriben las reglas nuevas que tengas al activar UFW anulando cualquier otra regla que se tuviera con IPTABLES.

Explicado con un ejemplo: tenemos un servidor por iptables con los puertos 22 y 80 abiertos. A continuación creo una regla de ufw para abrir el puerto 80. En el momento que habilitemos ufw el único puerto abierto será el 80 porque la lista de reglas de iptables se sobreescribe con la nueva lista de reglas de ufw que únicamente permite el tráfico por el puerto 80. Teoricamente, el puerto 22 estaría filtrado y perderíamos la conexión SSH y tendriamos complicado volver a tener el control.

También es importante saber que si ya tenemos ufw habilitado con ciertas reglas y lo desactivamos, volverán a prevalecer las reglas que teníamos inicialmente con iptables.

Las técnicas y comandos que mostraré están todas comprobadas en un VPS con Ubuntu 20.04 servido por Oracle Cloud. Trae ufw instalado por defecto pero no está activo. Antes de levantarlo, como ya hemos explicado abriremos unos puertos mínimos para no perder el control por SSH.

Vamos a verlo en un entorno real. Abrimos sesión remota con putty y comprobamos el estado de ufw.

ubuntu@instance-20220131-1641:~$ sudo ufw status
Status: inactive

La respuesta de Status: inactive nos demuestra que ufw ya se encuentra instalado aunque no activo. Si tenemos cualquier otro servidor sin ufw lo podemos instalar con:

# Antes de instalar el nuevo paquete, primero actualizar paquetes del sistema                         
sudo apt-get update && sudo apt-get upgrade -y
# instalar el paquete ufw
sudo apt install ufw
                        

Si está instalado pero existe una versión mas moderna servirá para actualizarlo. En mi caso, no ha hecho nada. Solo me informa que ya se encuentra instalado en su última versión.

Reading package lists... Done
Building dependency tree
Reading state information... Done
ufw is already the newest version (0.36-6ubuntu1).
0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.

Ufw en su configuración inicial permite todas las salidas y cierra todas las entradas. Antes de activarlo debemos asegurarnos de abrir al menos un puerto SSH para poder conectarnos. Un servidor remoto con todos los puertos de entrada bloqueados es una puerta cerrada de la que no tenemos la llave.

Abrir puertos. Comando ufw allow

Para abrir puertos indicando el número de puerto o rango

#abrir puerto 5555
sudo ufw allow 5555
#abrir los puertos entre 2000 y 2100
sudo ufw allow 2000:2100

Para abrir puertos indicando el nombre del servicio usamos el comando:

sudo ufw allow nombre_servicio

La lista de servicios se encuentra en/etc/services. Consultando este archivo tenemos el nombre del servicio, número de puerto con su protocolo TCP y/o UDP. Muestro un fragmento:

ftp 21/tcp
fsp 21/udp fspd
ssh 22/tcp # SSH Remote Login Protocol
telnet 23/tcp
smtp 25/tcp mail
time 37/tcp timserver
time 37/udp timserver
whois 43/tcp nicname
tacacs 49/tcp # Login Host Protocol (TACACS)
tacacs 49/udp
domain 53/tcp # Domain Name Server
domain 53/udp
bootps 67/udp
bootpc 68/udp
tftp 69/udp
gopher 70/tcp # Internet Gopher
finger 79/tcp
http 80/tcp www # WorldWideWeb HTTP
snmp 161/tcp # Simple Net Mgmt Protocol
snmp 161/udp

Por ejemplo, para abrir el firewall para ssh lo haríamos con:

sudo ufw allow ssh

Esto abrirá el puerto 22/tcp. Si el servicio requiere protocolos TCP y UDP, como por ejemplo snmp, abrirá el puerto para los dos protocolos.

sudo ufw allow snmp

Podemos abrir puertos directamente especificando el número. Si no especificamos protocolo lo abrirá en ambos. Si solo queremos un protocolo hay que especificarlo. Ejemplos:

#abrir el puerto 22 tcp (requerido para SSH)
sudo ufw allow 22/tcp

#abrir el puerto 161 para tcp y udp (requerido para SNMP)
sudo ufw allow 161

#abrir el puerto 5555 para udp
sudo ufw allow 5555/udp

Una posibilidad muy interesante sobre todo para el puerto de SSH es usar la opción limit que cerrará el puerto en el caso de que hayan varios errores de conexión en un intervalo pequeño de tiempo. De esta manera, estamos mas protegidos contra los ataques por fuerza bruta.

sudo ufw limit ssh
#si consultamos el estado mostrará que el puerto 22 está abierto en modo LIMIT
To Action From
-- ------ ----
22/tcp LIMIT IN Anywhere
22/tcp (v6) LIMIT IN Anywhere (v6)

También podemos denegar o permitir el acceso desde determinadas IP o rango de IP

sudo ufw allow from 11.22.33.44
sudo ufw allow from 11.22.33.0/24

El primer comando está muy claro. Le indicamos desde que IP podemos acceder. El segundo comando es un poco mas avanzado. Para indicar el rango estamos usando el estándar de bloques CIDR. En el capítulo sobre comandos de red podremos saber un poco sobre esto. Ahora, solo comentar que la instrucción permite acceso para todo el rango de esta red desde 1 a 254.

Además de la IP o rango de IP, también podemos especificar que puerto tendrá abierto.

sudo ufw allow from 11.22.33.44 to any port 22
sudo ufw allow from 11.22.33.0/24 to any port 22

Abrir puertos para salida

Si con allow se abren las entradas para abrir salidas se usa allow out

#abrir puerto 1000 tcp y udp para salida
sudo ufw allow out 1000
#abrir los puertos de salida para traceroute
sudo ufw allow out 33434:33524/udp

Activar y desactivar cortafuegos. Comandos ufw enable y ufw disable

En el momento que tenemos como mínimo el puerto SSH abierto ya podemos activar UFW. Al hacerlo, un mensaje nos avisará de que podemos cortar la conexión SSH.

ubuntu@instance-20220131-1641:~$ sudo ufw enable
Command may disrupt existing ssh connections. Proceed with operation (y|n)? y

Si lo queremos desactivar:

ubuntu@instance-20220131-1641:~$ sudo ufw disable
Firewall stopped and disabled on system startup

Estado del firewall. Comando ufw status

Teniendo ya el firewall activo podemos comprobar que puertos tenemos abiertos

Podemos usar ufw status o la forma mas completa ufw status verbose

ubuntu@instance-20220131-1641:~$ sudo ufw status verbose
Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), disabled (routed)
New profiles: skip

To Action From
-- ------ ----
22/tcp ALLOW IN Anywhere
22/tcp (v6) ALLOW IN Anywhere (v6)

Otra forma de comprobar que está activo es por medio del comandoservice.

ubuntu@instance-20220131-1641:~$ service ufw status
● ufw.service - Uncomplicated firewall
Loaded: loaded (/lib/systemd/system/ufw.service; enabled; vendor preset: enabled)
Active: active (exited) since Mon 2022-01-10 04:56:40 UTC; 1 months 5 days ago
Docs: man:ufw(8)
Main PID: 438 (code=exited, status=0/SUCCESS)
Tasks: 0 (limit: 7002)
Memory: 0B
CGroup: /system.slice/ufw.service

Jan 10 04:56:40 instance-20220131-1641 systemd[1]: Finished Uncomplicated firewall.
Warning: journal has been rotated since unit was started, output may be incomplete.

Cerrar puertos. Comando ufw deny

De la misma forma que abrimos con allow podemos cerrar con deny.

#cerrar el puerto 22 tcp
sudo ufw deny 22/tcp

#cerrar el puerto 161 para tcp y udp
sudo ufw deny 161

También podemos borrar la regla:

sudo ufw delete allow snmp

Las reglas del firewall se pueden listar de manera numerada y eliminarlas por su número:

ubuntu@instance-20220131-1641:~$ sudo ufw status numbered
Status: active

To Action From
-- ------ ----
[ 1] 22/tcp LIMIT IN Anywhere
[ 2] 80/tcp ALLOW IN Anywhere
[ 3] 161 ALLOW IN Anywhere
[ 4] 22/tcp (v6) LIMIT IN Anywhere (v6)
[ 5] 80/tcp (v6) ALLOW IN Anywhere (v6)
[ 6] 161 (v6) ALLOW IN Anywhere (v6)

Para eliminar una regla por su número:

# Borra la regla 2. Para este ejemplo el puerto 80/tcp IPv4
sudo ufw delete 2

Reiniciar UFW a su estado inicial. Comando ufw reset

Con ufw reset borramos todas las reglas que hayamos introducido y deja UFW desactivado.

ubuntu@instance-20220131-1641:~$ sudo ufw reset
Resetting all rules to installed defaults. This may disrupt existing ssh
connections. Proceed with operation (y|n)? y
Backing up 'user.rules' to '/etc/ufw/user.rules.20220208_170833'
Backing up 'before.rules' to '/etc/ufw/before.rules.20220208_170833'
Backing up 'after.rules' to '/etc/ufw/after.rules.20220208_170833'
Backing up 'user6.rules' to '/etc/ufw/user6.rules.20220208_170833'
Backing up 'before6.rules' to '/etc/ufw/before6.rules.20220208_170833'
Backing up 'after6.rules' to '/etc/ufw/after6.rules.20220208_170833'

Tras esto al hacer una consulta con ufw status responderá Estado: inactivo. Nuevamente, antes de activarlo hay que tener la precaución de abrir SSH.

Reglas permanentes

Con ufw no hay que hacer nada especial para que las reglas sean permanentes como sí ocurre con otras interfaces de firewall. Las reglas creadas siguen activas aunque se reinicie el servidor.

Solución al error de Ping no funciona

Puede ocurrir y de hecho me ha pasado (VirtualBox con Ubuntu 20.04 con IP estática y red NAT) que al estar UFW activo no funcione el comandopingporque requiere el protocolo ICMP.

$ ping 8.8.8.8
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
ping: sendmsg: Operation not permitted
ping: sendmsg: Operation not permitted
ping: sendmsg: Operation not permitted

Para intercambiar datos de estado o mensajes de error, los nodos recurren al Internet Control Message Protocol (ICMP) en las redes TCP/IP. ICMP no tiene puertos y no sabía el motivo de por qué el firewall bloqueaba las respuestas de ping. Encontré una posible solución que funcionó a muchos usuarios de un conocido foro de IT con el mismo problema pero en mi máquina Ubuntu no me daba resultado. Consiste en aplicar el comando iptables --flushpara borrar reglas de iptables. Como digo no funcionó.

La solución que fue bien consistió en editar nano /etc/ufw/before.rules y añadir unas reglas para permiter el tráfico saliente ICMP.

# allow outbound icmp
-A ufw-before-output -p icmp -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT
-A ufw-before-output -p icmp -m state --state ESTABLISHED,RELATED -j ACCEPT

Por último y para que por fin funcione elping hice unrebootdel sistema. Probé, antes de ser tan drástico,ufw reload y desactivar y activar ufw conufw disable, ufw enablesin éxito. Seguramente, hay alguna manera de reiniciar todos los servicios de red, evitando reiniciar el sistema pero por el momento no he sabido hacerlo.

Llegados a este punto pingresponde a direcciones IP y en un principio debería también dar respuesta si ponemos dominios porque tenemos el puerto 53 abierto para dns y por si acaso también, el puerto 43, que también usaa el comando whois. En estos momentos, los puertos abiertos son:

Y si hacemos un pinga un famoso DNS de google podemos ver que funciona correctamente.

Lo siguiente que vamos a comprobar es que resuelve nombres y que podemos hacer pinga cualquier dominio:

¡Error! Algo no funciona. Desactivo ufw y ping www.google.comfunciona. Lo vuelvo a activar y deja de resolver. Tenemos algo mal en el firewall. Buscando y probando muchas posibles soluciones al final encuentro una que sí que va. Inicialmente, yo había abierto el puerto 53 con el comandosudo allow domainque abre el puerto 53 tanto en IPV4 como IPV6 pero parece que esto no es suficiente. La solución final fue (y esto me hizo perdor varias horas) abrir el puerto 53 especificando también para salidas. Tras el comandoufw allow out 53el comandopingresuelve dominios.

Parece que ya funciona todo. Sin embargo, al intentar descargar paquetes compruebo que se detiene la descarga. Lo vemos a continuación.

Solución del problema de descarga de paquetes apt

En el estado actual, mi máquina virtual, no es capaz de descargar archivos del gestor de paquetesapt. Primeras investigaciones revelan que los gestores de paquetes usan los protocolos http, https y en algún caso ftp, con los puertos 80, 443 y 21 respectivamente. En este momento están cerrados y por tanto es lógico que no funcione.

Al intentarapt-get upgradetras iniciar el proceso cuando llega el momento de descargar se produce una pausa. Algo no va bien.

Pasados varios segundos aparece una lista de errores de conexión a la direcciones http de los paquetes.

La solución es abrir los puertos 80 y 443 de http y https tanto de entrada como de salida.

Tras esto apt-get upgradey la descarga de cualquier paquete desde aptfuncionará perfectamente.

Resumiendo un poco, aquí puedes ver el estado de ufw para que funcione ping y apt. Recuerda también que es necesario editar /etc/ufw/before.rulesañadiendo las dos reglas que vimos para permitir tráfico ICMP.

Un apunte final sobre firewall

Como ves, abrir y cerrar puertos es bastante sencillo con UFW. Aunque no hemos visto todas las posibilidades, ya conocemos las mas comunes para tener un servidor bastante mas seguro. Usar ufw, firewalld o otra interfaz es tu decisión personal.