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:

1

sudo ip route del default
sudo ip route add default via 192.168.100.2

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

3

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 \; }

4

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 \; }

5

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

6

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 \; }

7

Si probamos hacer ping al localhost, veremos que no funciona:

8

Y que tampoco tenemos acceso a internet:

9

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

10

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

11

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

12

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

13

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

14

Y ahora, si hacemos ping al localhost, veremos que funciona:

15

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

16

Vamos a probar que funciona el ping desde nuestra propia máquina:

17

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

18

Para probar que funciona, vamos a realizar un ping desde la máquina router-fw a la máquina lan:

19

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

20

Para probar que funciona, vamos a realizar un ping desde la máquina lan hacia el exterior:

21

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

22

Probamos que funciona realizando una consulta DNS desde la máquina:

dig @1.1.1.1 www.example.org

23

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

24

Primero, vamos a comprobar que funciona http:

curl portquiz.net:80

25

Y ahora le toca el turno a https:

curl portquiz.net:443

26

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

27

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

28

Y ahora, desde nuestra máquina, vamos aprobar que funciona:

telnet 172.22.200.80 80

29

Y desde nuestro navegador, podemos ver que podemos acceder al servidor web de la máquina lan:

30

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

31

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
    

32

Y comrpobamos que funciona conectándonos a nuestro host:

33

  • 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
    

34

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
    

35

36

  • 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
    

37

Y comprobamos que funciona tanto http como https:

    curl portquiz.net:80
    curl portquiz.net:443
    

38

39

  • 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
    

40

  • 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
    

41

  • 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
    

42

Y comprobamos que funciona haciendo ping a la máquina router-fw:

    ping 192.168.100.2
    

43

  • 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
    

44

Probamos que funciona conectándonos a nuestra máquina host:

    ssh maria@172.29.0.62
    

45

  • 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
    

46

Probamos que funciona correctamente desde mi máquina host:

    telnet 172.22.200.224 25
    

47

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
    

48

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
    

50

Y comprobamos que funciona correctamente conectándonos a la máquina LAN:

    ssh debian@172.22.200.133
    

51

  • 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
    

52

Y comprobamos que funciona correctamente:

    ssh -p 2222 debian@172.22.200.133
    

53

  • 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
        

54

  • 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
        

55

  • 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
        

56

  • Probamos las consultas DNS desde la máquina LAN:
        dig @192.168.202.2 www.example.org
        

57

Si ahora probamos a realizar una consulta DNS a otro servidor, veremos que no funciona:

        dig @1.1.1.1 www.example.org
        

58

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
    

59

Comprobamos que funciona correctamente:

    curl -I www.example.org
    

60