# Docker con nftables


> [!WARNING]
>
> El soporte para nftables introducido en Docker 29.0.0 es experimental; las opciones de configuración, el comportamiento y la implementación podrían cambiar en futuras versiones. Las reglas para las redes overlay aún no se han migrado desde iptables. Por lo tanto, nftables no se puede habilitar cuando el daemon de Docker se ejecuta en modo Swarm.

Para utilizar nftables en lugar de iptables, utiliza la opción de Docker Engine `--firewall-backend=nftables` en su línea de comandos, o `"firewall-backend": "nftables"` en su archivo de configuración. Es posible que también necesites modificar la configuración del reenvío de IP en el host y migrar las reglas de la cadena `DOCKER-USER` de iptables; consulta la sección de [migración de iptables a nftables](#migracion-de-iptables-a-nftables).

Para redes bridge, Docker crea reglas de nftables en el espacio de nombres de red del host. Para redes bridge y de otros tipos, también se crean reglas de nftables para DNS en el espacio de nombres de red del contenedor.

La creación de reglas de nftables se puede deshabilitar mediante las opciones del daemon `iptables` e `ip6tables`. _Estas opciones se aplican tanto a iptables como a nftables._ Consulta [Evitar que Docker manipule las reglas del cortafuegos](/engine/network/firewall-nftables/packet-filtering-firewalls/#evitar-que-docker-manipule-las-reglas-del-cortafuegos). Sin embargo, esto no se recomienda para la mayoría de los usuarios, ya que probablemente afectará el funcionamiento de la red de los contenedores.

## Tablas nftables de Docker

Para redes bridge, Docker crea dos tablas: `ip docker-bridges` e `ip6 docker-bridges`.

Cada tabla contiene una serie de [cadenas base](https://wiki.nftables.org/wiki-nftables/index.php/Configuring_chains#Adding_base_chains), y se añaden cadenas adicionales para cada red bridge. El proyecto moby tiene una cierta [documentación interna](https://github.com/moby/moby/blob/master/integration/network/bridge/nftablesdoc.md) que describe sus nftables y cómo dependen de la configuración de la red y del contenedor. Sin embargo, es probable que las tablas y sus reglas cambien entre las diferentes versiones de Docker Engine.

> [!NOTE]
>
> No modifiques las tablas de Docker directamente, ya que es probable que se pierdan las modificaciones; Docker espera tener la propiedad completa de sus tablas.

> [!NOTE]
>
> Debido a que iptables tiene un conjunto fijo de cadenas, equivalente a las cadenas base de nftables, todas las reglas se incluyen en esas cadenas. La cadena `DOCKER-USER` se proporciona como una forma de insertar reglas en la cadena `FORWARD` de la tabla `filter`, para que se ejecuten antes de las reglas de Docker. En la implementación de nftables de Docker, no existe una cadena `DOCKER-USER`. En su lugar, se pueden adquirir o añadir reglas en tablas separadas, con cadenas base que tengan los mismos tipos y puntos de hook que las cadenas base de Docker. Si es necesario, se puede utilizar la [prioridad de la cadena base](https://wiki.nftables.org/wiki-nftables/index.php/Configuring_chains#Base_chain_priority) para indicar a nftables el orden en que debe llamar a las cadenas. Docker utiliza [valores de prioridad](https://wiki.nftables.org/wiki-nftables/index.php/Netfilter_hooks#Priority_within_hook) conocidos para cada una de sus cadenas base.

## Migración de iptables a nftables

Si el daemon de Docker se ha estado ejecutando con el backend de cortafuegos de iptables, reiniciarlo con el backend de nftables eliminará la mayoría de las cadenas y reglas de iptables de Docker, y creará reglas de nftables en su lugar.

Si el reenvío de IP no está habilitado, Docker informará de un error al crear una red bridge que lo necesite. Debido al bridge predeterminado, si el reenvío de IPv4 está deshabilitado, el error se notificará durante el inicio del daemon. Consulta [Reenvío de IP](#reenvio-de-ip).

Si tienes reglas en la cadena `DOCKER-USER`, consulta la sección de [migración de `DOCKER-USER`](#migracion-de-docker-user).

Es posible que debas actualizar manualmente la política `FORWARD` de iptables si Docker con iptables la estableció en `DROP`, o como parte de la configuración del cortafuegos de tu host. Consulta [Política FORWARD en iptables](#politica-forward-en-iptables).

### Reenvío de IP

El reenvío de IP en el host de Docker permite el funcionamiento de características de Docker como la publicación de puertos, la comunicación entre redes bridge y el enrutamiento directo desde fuera del host hacia contenedores en redes bridge.

Cuando se ejecuta con iptables, y según la configuración de la red y del daemon, Docker puede habilitar el reenvío de IPv4 e IPv6 en el host.

Con el backend de cortafuegos nftables habilitado, Docker no habilitará el reenvío de IP por sí mismo. Informará de un error si el reenvío es necesario pero aún no está habilitado. Para deshabilitar la comprobación de Docker sobre el reenvío de IP, permitiéndole iniciar y crear redes cuando determine que el reenvío está deshabilitado, utiliza la opción del daemon `--ip-forward=false`, o `"ip-forward": false` en su archivo de configuración.

> [!WARNING]
>
> Al habilitar el reenvío de IP, asegúrate de tener reglas de cortafuegos para bloquear el reenvío no deseado entre interfaces que no son de Docker.

> [!NOTE]
>
> Si detienes Docker para migrar a nftables, es posible que Docker ya haya habilitado el reenvío de IP en tu sistema. Después de reiniciar, si ningún otro servicio vuelve a habilitar el reenvío, Docker no se iniciará.

Si Docker se encuentra en una máquina virtual que tiene una sola interfaz de red y ningún otro software en ejecución, probablemente no haya reenvío no deseado que bloquear. Sin embargo, en un host físico con múltiples interfaces de red, el reenvío entre esas interfaces probablemente deba bloquearse con reglas de nftables, a menos que el host esté actuando como un enrutador.

Para habilitar el reenvío de IP en el host, configura los siguientes sysctls:

- `net.ipv4.ip_forward=1`
- `net.ipv6.conf.all.forwarding=1`

Si tu host utiliza `systemd`, puedes emplear `systemd-sysctl`. Por ejemplo, editando `/etc/sysctl.d/99-sysctl.conf`.

Si el host ejecuta `firewalld`, puedes usarlo para bloquear el reenvío no deseado. Los bridges de Docker se encuentran en una zona de firewalld llamada `docker`, y esta crea una política de reenvío llamada `docker-forwarding` que acepta el reenvío desde `CUALQUIER` (ANY) zona a la zona `docker`.

Por ejemplo, para utilizar nftables con el fin de bloquear el reenvío entre las interfaces `eth0` y `eth1`, podrías emplear:

```console
table inet no-ext-forwarding {
	chain no-ext-forwarding {
		type filter hook forward priority filter; policy accept;
		iifname "eth0" oifname "eth1" drop
		iifname "eth1" oifname "eth0" drop
	}
}
```

### Política FORWARD en iptables

Una cadena de iptables con política `FORWARD` configurada como `DROP` descartará los paquetes que hayan sido aceptados por las reglas de nftables de Docker, debido a que el paquete será procesado tanto por las cadenas de iptables como por las cadenas de nftables de Docker.

Algunas características, incluyendo la publicación de puertos, no funcionarán a menos que se elimine la política `DROP` o se añadan reglas de iptables adicionales a la cadena `FORWARD` de iptables para aceptar el tráfico relacionado con Docker.

Cuando Docker utiliza iptables y habilita el reenvío de IP en el host, establece la política predeterminada de la cadena `FORWARD` de iptables como `DROP`. Por lo tanto, si detienes Docker para migrar a nftables, es posible que haya establecido un valor `DROP` que debas eliminar. De todos modos, se eliminará al reiniciar.

Para seguir utilizando reglas en `DOCKER-USER` que dependan de que la cadena tenga la política `DROP`, debes añadir reglas `ACCEPT` explícitas para el tráfico relacionado con Docker.

Para comprobar la política `FORWARD` actual de iptables, utiliza:

```console
$ iptables -L FORWARD
Chain FORWARD (policy DROP)
target     prot opt source               destination
$ ip6tables -L FORWARD
Chain FORWARD (policy ACCEPT)
target     prot opt source               destination
```

Para establecer las políticas de iptables en `ACCEPT` para IPv4 e IPv6:

```console
$ iptables -P FORWARD ACCEPT
$ ip6tables -P FORWARD ACCEPT
```

### Migración de `DOCKER-USER`

Con el backend de cortafuegos "iptables", las reglas añadidas a `DOCKER-USER` se procesan antes que las reglas de Docker en la cadena `FORWARD` de la tabla filter.

Al iniciar el daemon con nftables después de haberse ejecutado con iptables, Docker no eliminará el salto de la cadena `FORWARD` a `DOCKER-USER`. Por lo tanto, las reglas creadas en `DOCKER-USER` seguirán ejecutándose hasta que se elimine el salto o se reinicie el host.

Al iniciar con nftables, el daemon no añadirá el salto. Por lo tanto, a menos que exista un salto previo, las reglas en `DOCKER-USER` se ignorarán.

#### Migración de reglas ACCEPT

Algunas reglas de la cadena `DOCKER-USER` seguirán funcionando. Por ejemplo, si se descarta un paquete, se descartará antes o después de las reglas de nftables en la cadena `filter-FORWARD` de Docker. Sin embargo, otras reglas, en particular las reglas `ACCEPT` destinadas a invalidar las reglas `DROP` de Docker, no funcionarán.

En nftables, una regla de "aceptar" no es definitiva. Finaliza el procesamiento de su cadena base, pero el paquete aceptado seguirá siendo procesado por otras cadenas base, que podrían descartarlo.

Para invalidar la regla `drop` de Docker, debes utilizar una marca de cortafuegos (firewall mark). Selecciona una marca que no esté en uso en tu host y utiliza la opción de Docker Engine `--bridge-accept-fwmark`.

Por ejemplo, `--bridge-accept-fwmark=1` indica al daemon que acepte cualquier paquete con un valor de `fwmark` igual a `1`. Opcionalmente, puedes proporcionar una máscara para coincidir con bits específicos en la marca, como `--bridge-accept-fwmark=0x1/0x3`.

Luego, en lugar de aceptar el paquete en `DOCKER-USER`, añade la marca de cortafuegos que hayas elegido y Docker no lo descartará.

La marca de cortafuegos debe añadirse antes de que se ejecuten las reglas de Docker. Por lo tanto, si la marca se añade en una cadena con tipo `filter` and hook `forward`, debe tener una prioridad `filter - 1` o inferior.

## Reemplazar `DOCKER-USER` con una tabla nftables

Debido a que nftables no tiene cadenas predefinidas, para reemplazar la cadena `DOCKER-USER` puedes crear tu propia tabla y añadir cadenas y reglas a ella.

La cadena `DOCKER-USER` tiene tipo `filter` y hook `forward`, por lo que solo puede tener reglas en la cadena filter forward. Las cadenas base de tu tabla pueden tener cualquier `type` o `hook`. Si tus reglas necesitan ejecutarse antes que las de Docker, asigna a las cadenas base un número de `priority` inferior al de la cadena de Docker. O una prioridad más alta para asegurarte de que se ejecuten después de las reglas de Docker.

Las cadenas base de Docker utilizan los valores de prioridad definidos en [valores de prioridad](https://wiki.nftables.org/wiki-nftables/index.php/Netfilter_hooks#Priority_within_hook).

## Ejemplo: restringir conexiones externas a los contenedores

De forma predeterminada, cualquier host remoto puede conectarse a los puertos publicados a las direcciones externas del host de Docker.

Para permitir que solo una IP o red específica acceda a los contenedores, crea una tabla con una cadena base que tenga una regla drop. Por ejemplo, la siguiente tabla descarta los paquetes de todas las direcciones IP excepto de `192.0.2.2`:

```console
table ip my-table {
	chain my-filter-forward {
		type filter hook forward priority filter; policy accept;
		iifname "interfaz_ext" ip saddr != 192.0.2.2 counter drop
	}
}
```

Deberás cambiar `interfaz_ext` por el nombre de la interfaz externa de tu host.

En su lugar, podrías aceptar conexiones desde una subred de origen. La siguiente tabla solo acepta el acceso desde la subred `192.0.2.0/24`:

```console
table ip my-table {
	chain my-filter-forward {
		type filter hook forward priority filter; policy accept;
		iifname "interfaz_ext" ip saddr != 192.0.2.0/24 counter drop
	}
}
```

Si estás ejecutando otros servicios en el host que utilizan el reenvío de IP y necesitan ser accedidos por diferentes hosts externos, necesitarás filtros más específicos. Por ejemplo, para coincidir con el prefijo predeterminado `br-` de los dispositivos bridge pertenecientes a las redes bridge definidas por el usuario de Docker:

```console
table ip my-table {
	chain my-filter-forward {
		type filter hook forward priority filter; policy accept;
		iifname "interfaz_ext" oifname "br-*" ip saddr != 192.0.2.0/24 counter drop
	}
}
```

Para obtener más información sobre la configuración de nftables y su uso avanzado, consulta la [wiki de nftables](https://wiki.nftables.org/wiki-nftables/index.php/Main_Page).

