Cortafuegos II: Perimetral con nftables
Introducción
nftables reemplaza las populares tablas {ip, ip6, arp, eb}. Este software proporciona un nuevo marco de clasificación de paquetes en el núcleo que se basa en una máquina virtual (VM) específica de la red y una nueva herramienta de línea de comandos del espacio de usuario nft. nftables reutiliza los subsistemas de Netfilter existentes, como la infraestructura de enlace existente, el sistema de seguimiento de conexiones, NAT, el subsistema de registro y colas del espacio de usuario.
Este software también proporciona libnftables, la biblioteca de espacio de usuario de alto nivel que incluye compatibilidad con JSON. Esta biblioteca se puede utilizar para crear y administrar reglas de nftables desde aplicaciones de terceros.
Esquema de red
Vamos a utilizar dos máquinas en openstack, que vamos a crear con la receta heat: escenario2.yaml. La receta heat ha deshabilitado el cortafuego que nos ofrece openstack (todos los puertos de todos los protocolos están abiertos). Una máquina (que tiene asignada una IP flotante) hará de cortafuegos, y la otra será una máquina de la red interna 192.168.100.0/24.
Configuración de las rutas por defecto
LAN
Configuramos la ruta por defecto de la LAN. Su fin es que la ruta por defecto de la LAN sea la del cortafuegos. Para ello, nos conectamos a la máquina lan
:
sudo ip route del default
sudo ip route add default via 192.168.100.2
Creamos las tablas filter y nat
En NFTables las reglas se agrupan en tablas. Estas tablas contienen las cadenas, que a su vez, contienen las reglas. Las tablas se pueden crear con el comando nft add table
. Las cadenas se pueden crear con el comando nft add chain
. Las reglas se pueden crear con el comando nft add rule
.
En nuestro caso, vamos a crear las tablas filter
y nat
, y de esta manera, quedarían las reglas ordenadas según el esquema de red que hemos definido:
sudo nft add table inet filter
sudo nft add table inet nat
Creamos las cadenas de la tabla filter
Las primeras cadenas que vamos a crear son las de la tabla filter
. Estas cadenas son las que se encargan de filtrar el tráfico de entrada, salida y de redirección. En este caso, vamos a crear las cadenas input
, output
y forward
:
sudo nft add chain inet filter input { type filter hook input priority 0 \; counter \; policy accept \; }
sudo nft add chain inet filter output { type filter hook output priority 0 \; counter \; policy accept \; }
sudo nft add chain inet filter forward { type filter hook forward priority 0 \; counter \; policy accept \; }
Creamos las cadenas de la tabla nat
Las cadenas que vamos a crear son las de la tabla nat
. Estas cadenas son las que se encargan de hacer el SNAT y el DNAT. En este caso, vamos a crear las cadenas prerouting
y postrouting
:
sudo nft add chain inet nat prerouting { type nat hook prerouting priority 0 \; }
sudo nft add chain inet nat postrouting { type nat hook postrouting priority 100 \; }
Tráfico ssh de entrada al cortafuegos
Para permitir el tráfico ssh de entrada al cortafuegos, es necesario crear las reglas que nos permitan dicha conexión, a través de las cadenas input
y output
por el puerto 22 de las redes del instituto. Para ello, vamos a crear las siguientes reglas:
sudo nft add rule inet filter input ip saddr 172.22.0.0/16 tcp dport 22 ct state new,established counter accept
sudo nft add rule inet filter output ip daddr 172.22.0.0/16 tcp sport 22 ct state established counter accept
sudo nft add rule inet filter input ip saddr 172.29.0.0/16 tcp dport 22 ct state new,established counter accept
sudo nft add rule inet filter output ip daddr 172.29.0.0/16 tcp sport 22 ct state established counter accept
Política por defecto de la tabla filter
La política por defecto de la tabla filter
es accept
. Las vamos a cambiar a drop
debido a que no queremos que se permita ningún tráfico que no esté especificado en las reglas:
sudo nft chain inet filter input { policy drop \; }
sudo nft chain inet filter output { policy drop \; }
sudo nft chain inet filter forward { policy drop \; }
Si probamos hacer ping al localhost, veremos que no funciona:
Y que tampoco tenemos acceso a internet:
Activamos el bit de forward
Para que el cortafuegos pueda hacer el forward de paquetes, es necesario activar el bit de forward. Para ello, vamos a activar el bit de forward con el siguiente comando:
echo 1 | sudo tee /proc/sys/net/ipv4/ip_forward
SNAT
Crearemos la regla SNAT con la que el cortafuegos va a hacer el SNAT de los paquetes que salgan por la interfaz ens3
hacia la LAN. Para ello, vamos a crear la siguiente regla:
sudo nft add rule inet nat postrouting oifname "ens3" ip saddr 192.168.100.0/24 counter masquerade
Tráfico ssh de salida al cortafuegos hacia la LAN
El tráfico ssh de salida al cortafuegos hacia la LAN, es necesario crear las reglas que nos permitan dicha conexión, a través de las cadenas input
y output
por el puerto 22 de la LAN. Para ello, vamos a crear las siguientes reglas:
sudo nft add rule inet filter output oifname "ens4" ip daddr 192.168.100.0/24 tcp dport 22 ct state new,established counter accept
sudo nft add rule inet filter input iifname "ens4" ip saddr 192.168.100.0/24 tcp sport 22 ct state established counter accept
Una vez configurado, vamos a probar que podemos conectarnos desde la máquina router-fw
a la máquina lan
:
ssh debian@192.168.100.10
Tráfico loopback
El tráfico loopback es aquel que se genera dentro de la misma máquina. Para permitir el tráfico loopback, es necesario crear las reglas que nos permitan dicha conexión, a través de las cadenas input
y output
. Para ello, vamos a crear las siguientes reglas:
sudo nft add rule inet filter output oifname "lo" counter accept
sudo nft add rule inet filter input iifname "lo" counter accept
Y ahora, si hacemos ping al localhost, veremos que funciona:
Tráfico ICMP
Permitimos el tráfico ICMP de entrada
Vamos a configurar también el permiso de tráfico ICMP de entrada. Este tráfico ICMP es el que se genera cuando hacemos ping a una máquina o cuando hacemos traceroute. Para permitir el tráfico ICMP de entrada, es necesario crear las reglas que nos permitan dicha conexión, a través de las cadenas input
y output
. Para ello, vamos a crear las siguientes reglas:
sudo nft add rule inet filter input iifname "ens3" icmp type echo-request counter accept
sudo nft add rule inet filter output oifname "ens3" icmp type echo-reply counter accept
Vamos a probar que funciona el ping desde nuestra propia máquina:
Permitimos el tráfico ICMP de salida hacia la LAN
Ahora le toca el turno al tráfico ICMP de salida hacia la LAN. Para permitir el tráfico ICMP de salida hacia la LAN, es necesario crear las reglas que nos permitan dicha conexión, a través de las cadenas input
y output
. Para ello, vamos a crear las siguientes reglas:
sudo nft add rule inet filter output oifname "ens4" icmp type echo-request counter accept
sudo nft add rule inet filter input iifname "ens4" icmp type echo-reply counter accept
Para probar que funciona, vamos a realizar un ping desde la máquina router-fw
a la máquina lan
:
FORWARD: tráfico ICMP de salida desde LAN hacia internet
Ahora vamos a permitir el tráfico ICMP de salida desde la LAN hacia internet. Para permitir el tráfico ICMP de salida desde la LAN hacia internet, es necesario crear las reglas que nos permitan dicha conexión, a través de la cadena forward
. Para ello, vamos a crear las siguientes reglas:
sudo nft add rule inet filter forward iifname "ens4" oifname "ens3" ip saddr 192.168.100.0/24 icmp type echo-request counter accept
sudo nft add rule inet filter forward iifname "ens3" oifname "ens4" ip daddr 192.168.100.0/24 icmp type echo-reply counter accept
Para probar que funciona, vamos a realizar un ping desde la máquina lan
hacia el exterior:
FORWARD: tráfico DNS saliente desde LAN
Vamos a permitir el tráfico DNS saliente desde la LAN. Para permitir el tráfico DNS saliente desde la LAN, es necesario crear las reglas que nos permitan dicha conexión, a través de la cadena forward
. Para ello, vamos a crear las siguientes reglas:
sudo nft add rule inet filter forward iifname "ens4" oifname "ens3" ip saddr 192.168.100.0/24 udp dport 53 ct state new,established counter accept
sudo nft add rule inet filter forward iifname "ens3" oifname "ens4" ip daddr 192.168.100.0/24 udp sport 53 ct state established counter accept
Probamos que funciona realizando una consulta DNS desde la máquina:
dig @1.1.1.1 www.example.org
FORWARD: tráfico HTTP/HTTPS saliente desde LAN
Ahora vamos a permitir el tráfico HTTP/HTTPS saliente desde la LAN. Para permitir el tráfico HTTP/HTTPS saliente desde la LAN, es necesario crear las reglas que nos permitan dicha conexión, a través de la cadena forward
. Para ello, vamos a crear las siguientes reglas:
sudo nft add rule inet filter forward iifname "ens4" oifname "ens3" ip protocol tcp ip saddr 192.168.100.0/24 tcp dport { 80,443 } ct state new,established counter accept
sudo nft add rule inet filter forward iifname "ens3" oifname "ens4" ip protocol tcp ip daddr 192.168.100.0/24 tcp sport { 80,443 } ct state established counter accept
Primero, vamos a comprobar que funciona http:
curl portquiz.net:80
Y ahora le toca el turno a https:
curl portquiz.net:443
FORWARD: tráfico HTTP entrante hacia LAN
Le toca el turno al tráfico HTTP entrante hacia la LAN. Para permitir el tráfico HTTP entrante hacia la LAN, es necesario crear las reglas que nos permitan dicha conexión, a través de la cadena forward
. Para ello, vamos a crear las siguientes reglas:
sudo nft add rule inet filter forward iifname "ens3" oifname "ens4" ip daddr 192.168.100.0/24 tcp dport 80 ct state new,established counter accept
sudo nft add rule inet filter forward iifname "ens4" oifname "ens3" ip saddr 192.168.100.0/24 tcp sport 80 ct state established counter accept
Aplicamos una regla DNAT
Ahora vamos a aplicar una regla DNAT para que cuando se acceda al puerto 80 de la máquina router-fw
, se redirija al puerto 80 de la máquina lan
:
sudo nft add rule inet nat prerouting iifname "ens3" tcp dport 80 counter dnat ip to 192.168.100.10
Y ahora, desde nuestra máquina, vamos aprobar que funciona:
telnet 172.22.200.80 80
Y desde nuestro navegador, podemos ver que podemos acceder al servidor web de la máquina lan
:
Hacer persistente las reglas
Con todo lo anterior, ya tenemos las reglas necesarias para que la máquina router-fw
funcione como cortafuegos. Ahora vamos a hacer persistente las reglas, para que se mantengan tras reiniciar la máquina. Para ello, vamos a guardar las reglas en un fichero de configuración y vamos a configurar el servicio nftables
para que se inicie al arrancar el sistema:
nft list ruleset > /etc/nftables.conf
sudo systemctl enable nftables
sudo systemctl start nftables
Reglas necesarias para las siguientes operaciones
- Permitir poder hacer conexiones ssh al exterior desde la máquina cortafuegos.
sudo nft add rule inet filter output oifname "ens3" tcp dport 22 ct state new,established counter accept
sudo nft add rule inet filter input iifname "ens3" tcp sport 22 ct state established counter accept
Y comrpobamos que funciona conectándonos a nuestro host:
- Permitir hacer consultas DNS desde la máquina cortafuegos sólo al servidor 192.168.202.2. Comprueba que no puedes hacer un dig @1.1.1.1.
sudo nft add rule inet filter output ip daddr 192.168.202.2 udp dport 53 ct state new,established counter accept
sudo nft add rule inet filter input ip saddr 192.168.202.2 udp sport 53 ct state established counter accept
Y probamos que las consultas DNS al servidor 192.168.202.2 funcionan, pero no a otros servidores:
dig @192.168.202.2 www.example.org
dig @1.1.1.1 www.example.org
- Permitir que la máquina cortafuegos pueda navegar por internet.
sudo nft add rule inet filter output oifname "ens3" ip protocol tcp tcp dport { 80,443 } ct state new,established counter accept
sudo nft add rule inet filter input iifname "ens3" ip protocol tcp tcp sport { 80,443 } ct state established counter accept
Y comprobamos que funciona tanto http como https:
curl portquiz.net:80
curl portquiz.net:443
- Los equipos de la red local deben poder tener conexión al exterior.
Realizado con anterioridad durante la configuracion de SNAT y las reglas de forward para el tráfico ICMP saliente, que son las siguientes:
sudo nft add rule inet nat postrouting oifname "ens3" ip saddr 192.168.100.0/24 counter masquerade
sudo nft add rule inet filter forward iifname "ens4" oifname "ens3" ip saddr 192.168.100.0/24 icmp type echo-request counter accept
sudo nft add rule inet filter forward iifname "ens3" oifname "ens4" ip daddr 192.168.100.0/24 icmp type echo-reply counter accept
Probamos que funciona haciendo pong a google:
ping 8.8.8.8
- Permitimos el ssh desde el cortafuego a la LAN
Realizado durante la preparación del escenario. Las reglas son las siguientes:
sudo nft add rule inet filter output oifname "ens4" ip daddr 192.168.100.0/24 tcp dport 22 ct state new,established counter accept
sudo nft add rule inet filter input iifname "ens4" ip saddr 192.168.100.0/24 tcp sport 22 ct state established counter accept
Lo comprobamos conectándonos a nuestro host:
ssh maria@172.29.0.62
- Permitimos hacer ping desde la LAN a la máquina cortafuegos.
sudo nft add rule inet filter input iifname "ens4" icmp type echo-request counter accept
sudo nft add rule inet filter output oifname "ens4" icmp type echo-reply counter accept
Y comprobamos que funciona haciendo ping a la máquina router-fw
:
ping 192.168.100.2
- Permite realizar conexiones ssh desde los equipos de la LAN
sudo nft add rule inet filter forward iifname "ens4" oifname "ens3" ip saddr 192.168.100.0/24 tcp dport 22 ct state new,established counter accept
sudo nft add rule inet filter forward iifname "ens3" oifname "ens4" ip daddr 192.168.100.0/24 tcp sport 22 ct state established counter accept
Probamos que funciona conectándonos a nuestra máquina host:
ssh maria@172.29.0.62
- Instala un servidor de correos en la máquina de la LAN. Permite el acceso desde el exterior y desde el cortafuego al servidor de correos. Para probarlo puedes ejecutar un telnet al puerto 25 tcp.
sudo nft add rule inet filter forward iifname "ens3" oifname "ens4" ip daddr 192.168.100.0/24 tcp dport 25 counter accept
sudo nft add rule inet filter forward iifname "ens4" oifname "ens3" ip saddr 192.168.100.0/24 tcp sport 25 counter accept
sudo nft add rule inet nat prerouting iifname "ens3" tcp dport 25 counter dnat ip to 192.168.100.10
Probamos que funciona correctamente desde mi máquina host:
telnet 172.22.200.224 25
Permitiremos el acceso desde el cortafuegos al servidor de correos.
sudo nft add rule inet filter output ip daddr 192.168.100.10 tcp dport 25 counter accept
sudo nft add rule inet filter input ip saddr 192.168.100.10 tcp sport 25 counter accept
Y comprobamos que funciona correctamente:
telnet 192.168.100.10 25
- Permite poder hacer conexiones ssh desde exterior a la LAN
sudo nft add rule inet filter forward iifname "ens3" oifname "ens4" ip daddr 192.168.100.0/24 tcp dport 22 ct state new,established counter accept
sudo nft add rule inet filter forward iifname "ens4" oifname "ens3" ip saddr 192.168.100.0/24 tcp sport 22 ct state established counter accept
sudo nft add rule inet nat prerouting iifname "ens3" tcp dport 22 counter dnat ip to 192.168.100.10
Y comprobamos que funciona correctamente conectándonos a la máquina LAN:
ssh debian@172.22.200.133
- Modifica la regla anterior, para que al acceder desde el exterior por ssh tengamos que conectar al puerto 2222, aunque el servidor ssh este configurado para acceder por el puerto 22.
sudo nft add rule inet nat prerouting iifname "ens3" tcp dport 2222 counter dnat ip to 192.168.100.10:22
Y comprobamos que funciona correctamente:
ssh -p 2222 debian@172.22.200.133
-
Permite hacer consultas DNS desde la LAN sólo al servidor 192.168.202.2. Comprueba que no puedes hacer un dig @1.1.1.1.
-
Primero vamos a consultar que handle tiene la regla que nos permite realizar las cosultas DNS a cualquier servidor:
sudo nft list -a ruleset | grep 53
- Eliminamos las reglas que nos permiten realizar las consultas DNS a cualquier servidor:
sudo nft delete rule inet filter forward handle 42
sudo nft delete rule inet filter forward handle 43
- Añadimos las reglas que nos permiten realizar las consultas DNS sólo al servidor 192.168.202.2:
sudo nft add rule inet filter forward iifname "ens4" oifname "ens3" ip saddr 192.168.100.0/24 ip daddr 192.168.202.2 udp dport 53 ct state new,established counter accept
sudo nft add rule inet filter forward iifname "ens3" oifname "ens4" ip saddr 192.168.202.2 ip daddr 192.168.100.0/24 udp sport 53 ct state established counter accept
- Probamos las consultas DNS desde la máquina LAN:
dig @192.168.202.2 www.example.org
Si ahora probamos a realizar una consulta DNS a otro servidor, veremos que no funciona:
dig @1.1.1.1 www.example.org
Recordemos, que anteriormente teniamos las reglas que nos permitían realizar las consultas DNS a cualquier servidor.
- Permite que los equipos de la LAN puedan navegar por internet.
sudo nft add rule inet filter forward iifname "ens4" oifname "ens3" ip protocol tcp ip saddr 192.168.100.0/24 tcp dport { 80,443 } ct state new,established counter accept
sudo nft add rule inet filter forward iifname "ens3" oifname "ens4" ip protocol tcp
Comprobamos que funciona correctamente:
curl -I www.example.org