Docker
Iptables con Docker
Buscar..
Introducción
Este tema trata sobre cómo limitar el acceso a sus contenedores de la ventana acoplable desde el mundo exterior utilizando iptables.
Para las personas impacientes, puedes consultar los ejemplos. Para los demás, lea la sección de comentarios para comprender cómo crear nuevas reglas.
Sintaxis
- iptables -I DOCKER [REGLA ...] [ACCEPT | DROP] // Para agregar una regla a la parte superior de la tabla DOCKER
- iptables -D DOCKER [REGLA ...] [ACCEPT | DROP] // Para eliminar una regla de la tabla DOCKER
- ipset restore </etc/ipfriends.conf // Para reconfigurar los ipset ipfriends
Parámetros
Parámetros | Detalles |
---|---|
ext_if | Su interfaz externa en el host Docker. |
XXX.XXX.XXX.XXX | Se debe dar una IP particular a la cual los contenedores de Docker acceden. |
YYY.YYY.YYY.YYY | Se debe proporcionar otra IP a la que accedan los contenedores Docker. |
ipfriends | El nombre del conjunto de ipsets que define las direcciones IP permitidas para acceder a sus contenedores de Docker. |
Observaciones
El problema
Configurar las reglas de iptables para los contenedores Docker es un poco complicado. Al principio, usted pensaría que las reglas de firewall "clásicas" deberían hacer el truco.
Por ejemplo, supongamos que ha configurado un contenedor nginx-proxy + varios contenedores de servicio para exponer a través de HTTPS algunos servicios web personales. Entonces, una regla como esta debería dar acceso a sus servicios web solo para IP XXX.XXX.XXX.XXX.
$ iptables -A INPUT -i eth0 -p tcp -s XXX.XXX.XXX.XXX -j ACCEPT
$ iptables -P INPUT DROP
No funcionará, sus contenedores siguen siendo accesibles para todos.
De hecho, los contenedores Docker no son servicios de host. Se basan en una red virtual en su host, y el host actúa como una puerta de enlace para esta red. Y con respecto a las puertas de enlace, el tráfico enrutado no se maneja con la tabla INPUT, sino con la tabla FORWARD, que hace que la regla publicada antes sea inefectiva.
Pero no es todo. De hecho, el demonio Docker crea muchas reglas de iptables cuando comienza a hacer su magia con respecto a la conectividad de la red de contenedores. En particular, se crea una tabla DOCKER para manejar las reglas relativas a los contenedores al reenviar el tráfico de la tabla FORWARD a esta nueva tabla.
$ iptables -L
Chain INPUT (policy ACCEPT)
target prot opt source destination
Chain FORWARD (policy DROP)
target prot opt source destination
DOCKER-ISOLATION all -- anywhere anywhere
DOCKER all -- anywhere anywhere
ACCEPT all -- anywhere anywhere ctstate RELATED,ESTABLISHED
ACCEPT all -- anywhere anywhere
ACCEPT all -- anywhere anywhere
DOCKER all -- anywhere anywhere
ACCEPT all -- anywhere anywhere ctstate RELATED,ESTABLISHED
ACCEPT all -- anywhere anywhere
ACCEPT all -- anywhere anywhere
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
Chain DOCKER (2 references)
target prot opt source destination
ACCEPT tcp -- anywhere 172.18.0.4 tcp dpt:https
ACCEPT tcp -- anywhere 172.18.0.4 tcp dpt:http
Chain DOCKER-ISOLATION (1 references)
target prot opt source destination
DROP all -- anywhere anywhere
DROP all -- anywhere anywhere
RETURN all -- anywhere anywhere
La solución
Si verifica la documentación oficial ( https://docs.docker.com/v1.5/articles/networking/) , se ofrece una primera solución para limitar el acceso del contenedor Docker a una IP particular.
$ iptables -I DOCKER -i ext_if ! -s 8.8.8.8 -j DROP
De hecho, agregar una regla en la parte superior de la tabla DOCKER es una buena idea. No interfiere con las reglas configuradas automáticamente por Docker, y es simple. Pero faltan dos grandes:
- Primero, ¿qué sucede si necesita acceder desde dos IP en lugar de una? Aquí solo se puede aceptar un src IP, el otro se eliminará sin ninguna forma de evitarlo.
- En segundo lugar, ¿qué pasa si su docker necesita acceso a Internet? Prácticamente ninguna solicitud tendrá éxito, ya que solo el servidor 8.8.8.8 podría responder a ellos.
- Por último, ¿y si quieres añadir otras lógicas? Por ejemplo, dé acceso a cualquier usuario a su servidor web que sirve en el protocolo HTTP, pero limite todo lo demás a una IP particular.
Para la primera observación, podemos usar ipset . En lugar de permitir una IP en la regla anterior, permitimos todas las IP desde el conjunto de datos predefinido. Como beneficio adicional, el ipset se puede actualizar sin la necesidad de redefinir la regla de iptable.
$ iptables -I DOCKER -i ext_if -m set ! --match-set my-ipset src -j DROP
Para la segunda observación, este es un problema canónico para los firewalls: si se le permite comunicarse con un servidor a través de un firewall, entonces el firewall debe autorizar al servidor a responder a su solicitud. Esto se puede hacer mediante la autorización de paquetes que están relacionados con una conexión establecida. Para la lógica docker, da:
$ iptables -I DOCKER -i ext_if -m state --state ESTABLISHED,RELATED -j ACCEPT
La última observación se centra en un punto: las reglas de iptables son esenciales. De hecho, la lógica adicional para ACEPTAR algunas conexiones (incluida la que concierne a las conexiones ESTABLECIDAS) debe colocarse en la parte superior de la tabla DOCKER, antes de la regla DROP que niega todas las conexiones restantes que no coincidan con el conjunto de cambios.
Como usamos la opción -I de iptable, que inserta reglas en la parte superior de la tabla, las reglas de iptables anteriores deben insertarse en orden inverso:
// Drop rule for non matching IPs
$ iptables -I DOCKER -i ext_if -m set ! --match-set my-ipset src -j DROP
// Then Accept rules for established connections
$ iptables -I DOCKER -i ext_if -m state --state ESTABLISHED,RELATED -j ACCEPT
$ iptables -I DOCKER -i ext_if ... ACCEPT // Then 3rd custom accept rule
$ iptables -I DOCKER -i ext_if ... ACCEPT // Then 2nd custom accept rule
$ iptables -I DOCKER -i ext_if ... ACCEPT // Then 1st custom accept rule
Con todo esto en mente, ahora puede consultar los ejemplos que ilustran esta configuración.
Limite el acceso en los contenedores Docker a un conjunto de IPs
Primero, instale el ipset si es necesario. Por favor refiérase a su distribución para saber cómo hacerlo. Como ejemplo, aquí está el comando para distribuciones similares a Debian.
$ apt-get update
$ apt-get install ipset
Luego cree un archivo de configuración para definir un ipset que contenga las IP para las que desea abrir el acceso a sus contenedores de Docker.
$ vi /etc/ipfriends.conf
# Recreate the ipset if needed, and flush all entries
create -exist ipfriends hash:ip family inet hashsize 1024 maxelem 65536
flush
# Give access to specific ips
add ipfriends XXX.XXX.XXX.XXX
add ipfriends YYY.YYY.YYY.YYY
Cargue este ipset.
$ ipset restore < /etc/ipfriends.conf
Asegúrese de que su demonio Docker se esté ejecutando: no se debe mostrar ningún error después de ingresar el siguiente comando.
$ docker ps
Estás listo para insertar tus reglas de iptables. Debe respetar el orden.
// All requests of src ips not matching the ones from ipset ipfriends will be dropped.
$ iptables -I DOCKER -i ext_if -m set ! --match-set ipfriends src -j DROP
// Except for requests coming from a connection already established.
$ iptables -I DOCKER -i ext_if -m state --state ESTABLISHED,RELATED -j ACCEPT
Si desea crear nuevas reglas, deberá eliminar todas las reglas personalizadas que haya agregado antes de insertar las nuevas.
$ iptables -D DOCKER -i ext_if -m set ! --match-set ipfriends src -j DROP
$ iptables -D DOCKER -i ext_if -m state --state ESTABLISHED,RELATED -j ACCEPT
Configurar acceso de restricción cuando se inicia el demonio Docker
Trabajo en progreso
Algunas reglas personalizadas de iptables
Trabajo en progreso