problem open link container ubuntu docker containers firewall iptables

open - ¿Cuál es la mejor práctica de docker+ufw en Ubuntu?



iptables docker problem (4)

Acabo de probar Docker. Es impresionante, pero parece que no funciona bien con ufw. Por defecto, la ventana acoplable manipulará un poco las iptables. El resultado no es un error pero no es lo que esperaba. Para más detalles puedes leer Los peligros de UFW + Docker

Mi objetivo es configurar un sistema como

Host (running ufw) -> docker container 1 - nginx (as a reverse proxy) -> docker container 2 - node web 1 -> docker container 3 - node web 2 -> .......

Quiero administrar el tráfico entrante (por ejemplo, restringir el acceso) a través de ufw, por lo tanto, no quiero que la ventana acoplable toque mis iptables. Aqui esta mi prueba

Ambiente:

  • un Ubuntu 14.04 recién instalado (kernel: 3.13.0-53)
  • Docker 1.6.2
  • El reenvío ufw está habilitado. ( Habilitar el reenvío UFW )
  • --iptables=false fue agregado al demonio Docker.

Primer intento

docker run --name ghost -v /home/xxxx/ghost_content:/var/lib/ghost -d ghost docker run --name nginx -p 80:80 -v /home/xxxx/nginx_site_enable:/etc/nginx/conf.d:ro --link ghost:ghost -d nginx

Sin suerte. El primer comando está bien, pero el segundo comando arrojará un error

Error response from daemon: Cannot start container

Segundo intento

Entonces encontré esto: no se pueden vincular contenedores con --iptables = false # 12701

Después de ejecutar el siguiente comando, todo se ve bien.

sudo iptables -N DOCKER

Sin embargo, noté que no puedo establecer ninguna conexión de salida dentro de los contenedores. Por ejemplo:

xxxxg@ubuntu:~$ sudo docker exec -t -i nginx /bin/bash root@b0d33f22d3f4:/# ping 74.125.21.147 PING 74.125.21.147 (74.125.21.147): 56 data bytes ^C--- 74.125.21.147 ping statistics --- 35 packets transmitted, 0 packets received, 100% packet loss root@b0d33f22d3f4:/#

Si --iptables=false del demonio Docker, entonces la conexión a Internet de los contenedores volverá a la normalidad, pero el ufw no funcionará "correctamente" (bueno ... por mi definición).

Entonces, ¿cuál es la mejor práctica de docker + ufw? ¿Alguien puede proporcionar alguna ayuda?

Gracias.

Bart.


Problema

Este problema ha existido durante mucho tiempo.

Deshabilitar iptables en Docker tendrá otros problemas.

La reversión cambia primero

Si ha modificado su servidor de acuerdo con la solución actual que encontramos en Internet, restaure estos cambios primero, incluyendo:

  • Habilitar la función iptables de Docker. Elimine todos los cambios como --iptables=false , incluido el archivo de configuración /etc/docker/daemon.json .
  • La regla ADELANTE predeterminada de UFW vuelve a cambiar al valor predeterminado DROP lugar de ACCEPT .
  • Elimine las reglas relacionadas con la red Docker en el archivo de configuración de UFW /etc/ufw/after.rules .
  • Si ha modificado los archivos de configuración de Docker, reinicie Docker primero. Modificaremos la configuración de UFW más tarde y podremos reiniciarla luego.

Resolviendo problemas de UFW y Docker

Esta solución necesita modificar solo un archivo de configuración UFW, todas las configuraciones y opciones de Docker siguen siendo las predeterminadas. No necesita deshabilitar la función iptables docker.

Modifique el archivo de configuración de UFW /etc/ufw/after.rules y agregue las siguientes reglas al final del archivo:

# BEGIN UFW AND DOCKER *filter :ufw-user-forward - [0:0] :DOCKER-USER - [0:0] -A DOCKER-USER -j RETURN -s 10.0.0.0/8 -A DOCKER-USER -j RETURN -s 172.16.0.0/12 -A DOCKER-USER -j RETURN -s 192.168.0.0/16 -A DOCKER-USER -j ufw-user-forward -A DOCKER-USER -j DROP -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 192.168.0.0/16 -A DOCKER-USER -j DROP -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 10.0.0.0/8 -A DOCKER-USER -j DROP -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 172.16.0.0/12 -A DOCKER-USER -j DROP -p udp -m udp --dport 0:32767 -d 192.168.0.0/16 -A DOCKER-USER -j DROP -p udp -m udp --dport 0:32767 -d 10.0.0.0/8 -A DOCKER-USER -j DROP -p udp -m udp --dport 0:32767 -d 172.16.0.0/12 -A DOCKER-USER -j RETURN COMMIT # END UFW AND DOCKER

Usando el comando sudo systemctl restart ufw para reiniciar UFW después de cambiar el archivo. Ahora la red pública no puede acceder a los puertos de la ventana acoplable publicados, el contenedor y la red privada pueden visitarse regularmente y los contenedores también pueden acceder a la red externa desde el interior.

Si desea permitir que las redes públicas accedan a los servicios proporcionados por el contenedor Docker, por ejemplo, el puerto de servicio de un contenedor es 80 . Ejecute el siguiente comando para permitir que las redes públicas accedan a este servicio:

ufw route allow proto tcp from any to any port 80

Este comando le permite a la red pública acceder a todos los puertos publicados cuyo puerto de contenedor es 80.

Nota: Si publicamos un puerto mediante la opción -p 8080:80 , deberíamos usar el puerto de contenedor 80 , no el puerto de host 8080 .

Si hay varios contenedores con un puerto de servicio de 80, pero solo queremos que la red externa acceda a un contenedor en particular. Por ejemplo, si la dirección privada del contenedor es 172.17.0.2, use el siguiente comando:

ufw route allow proto tcp from any to 172.17.0.2 port 80

Si el protocolo de red del servicio es UDP, por ejemplo, un servicio DNS, puede usar el siguiente comando para permitir que la red externa acceda a todos los servicios DNS publicados:

ufw route allow proto udp from any to any port 53

De manera similar, aunque solo sea para un contenedor específico, como la dirección IP 172.17.0.2:

ufw route allow proto udp from any to 172.17.0.2 port 53

¿Cómo funciona?

Las siguientes reglas permiten que las redes privadas puedan visitarse entre sí. Normalmente, las redes privadas son más confiables que las redes públicas.

-A DOCKER-USER -j RETURN -s 10.0.0.0/8 -A DOCKER-USER -j RETURN -s 172.16.0.0/12 -A DOCKER-USER -j RETURN -s 192.168.0.0/16

Las siguientes reglas permiten a UFW administrar si las redes públicas pueden visitar los servicios proporcionados por el contenedor Docker. Para que podamos gestionar todas las reglas de firewall en un solo lugar.

-A DOCKER-USER -j ufw-user-forward

Las siguientes reglas bloquean las solicitudes de conexión iniciadas por todas las redes públicas, pero permiten que las redes internas accedan a redes externas. Para el protocolo TCP, impide el establecimiento activo de una conexión TCP desde redes públicas. Para el protocolo UDP, se bloquean todos los accesos a puertos que son menos de 32767. ¿Por qué es este puerto? Debido a que el protocolo UDP no tiene estado, no es posible bloquear la señal de intercambio que inicia la solicitud de conexión como lo hace TCP. Para GNU / Linux podemos encontrar el rango de puertos locales en el archivo /proc/sys/net/ipv4/ip_local_port_range . El rango predeterminado es 32768 60999 . Al acceder a un servicio de protocolo UDP desde un contenedor en ejecución, el puerto local se seleccionará al azar del puerto y el servidor devolverá los datos a este puerto aleatorio. Por lo tanto, podemos suponer que el puerto de escucha del protocolo UDP dentro de todos los contenedores es menos de 32768. Esta es la razón por la que no queremos que las redes públicas accedan a los puertos UDP que menos de 32768.

-A DOCKER-USER -j DROP -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 192.168.0.0/16 -A DOCKER-USER -j DROP -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 10.0.0.0/8 -A DOCKER-USER -j DROP -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 172.16.0.0/12 -A DOCKER-USER -j DROP -p udp -m udp --dport 0:32767 -d 192.168.0.0/16 -A DOCKER-USER -j DROP -p udp -m udp --dport 0:32767 -d 10.0.0.0/8 -A DOCKER-USER -j DROP -p udp -m udp --dport 0:32767 -d 172.16.0.0/12 -A DOCKER-USER -j RETURN

Más

https://github.com/chaifeng/ufw-docker

sudo wget -O /usr/local/bin/ufw-docker https://github.com/chaifeng/ufw-docker/raw/master/ufw-docker chmod +x /usr/local/bin/ufw-docker

Uso

ufw-docker help ufw-docker install ufw-docker status ufw-docker allow webapp ufw-docker allow webapp 80 ufw-docker allow webapp 53/udp ufw-docker list webapp ufw-docker delete allow webapp 80/tcp ufw-docker delete allow webapp

Actualización: 2018-09-10

La razón para elegir ufw-user-forward , no ufw-user-input

usando ufw-user-input

Pro:

Fácil de usar y entender, soporta versiones anteriores de Ubuntu.

Por ejemplo, para permitir que el público visite un puerto publicado cuyo puerto de contenedor es 8080 , use el comando:

ufw allow 8080

Estafa:

No solo expone los puertos de contenedores sino que también expone los puertos del host.

Por ejemplo, si un servicio se está ejecutando en el host y el puerto es 8080 . El comando ufw allow 8080 permite a la red pública visitar el servicio y todos los puertos publicados cuyo puerto de contenedores es 8080 . Pero solo queremos exponer el servicio que se ejecuta en el host, o simplemente el servicio que se ejecuta dentro de contenedores, no ambos.

Para evitar este problema, es posible que necesitemos usar un comando similar al siguiente para todos los contenedores:

ufw allow proto tcp from any to 172.16.0.3 port 8080

usando ufw-user-forward

Pro:

No se pueden exponer servicios que se ejecutan en hosts y contenedores al mismo tiempo con el mismo comando.

Por ejemplo, si queremos publicar el puerto 8080 de contenedores, use el siguiente comando:

ufw route allow 8080

La red pública puede acceder a todos los puertos publicados cuyos puertos de contenedor son 8080 .

Pero a la red pública todavía no se puede acceder al puerto 8080 del host. Si queremos hacerlo, ejecute el siguiente comando para permitir que el público acceda al puerto en el host por separado:

ufw allow 8080

Estafa:

No es compatible con versiones anteriores de Ubuntu, y el comando es un poco más complicado. Pero puede usar mi script https://github.com/chaifeng/ufw-docker .

Conclusión

Si estamos usando una versión anterior de Ubuntu, podemos usar la cadena de ufw-user-input . Pero tenga cuidado de evitar exponer servicios que no deben ser expuestos.

Si estamos usando una versión más nueva de Ubuntu que es compatible con el subcomando ufw route , es mejor que utilicemos la cadena ufw-user-forward , y que utilicemos el comando ufw route para administrar las reglas del firewall para los contenedores.

Actualización: 6 de octubre de 2018

El script https://github.com/chaifeng/ufw-docker compatible con Docker Swarm ahora. Consulte el último código para obtener más información, https://github.com/chaifeng/ufw-docker

Instalar para el modo Docker Swarm

Solo podemos usar este script en los nodos del administrador para administrar las reglas del firewall cuando se usa en modo de enjambre.

  • Modificación de todos los archivos after.rules en todos los nodos, incluidos los administradores y los trabajadores
  • Despliegue de este script en los nodos del administrador

Al ejecutarse en el modo Docker Swarm, este script agregará un servicio global ufw-docker-agent . La imagen chaifeng/ufw-docker-agent también se chaifeng/ufw-docker-agent automáticamente a partir de este proyecto.


He tenido un problema como hace meses y últimamente he decidido describir el problema junto con la solución en mi blog. Aquí está el atajo.

Usar --iptables=false no te ayudará mucho con el caso que describiste. Simplemente no es suficiente aquí. Por defecto, ninguno de sus contenedores puede hacer ninguna conexión saliente.

Hay un pequeño paso que está omitiendo en su camino para tener contenedores detrás de UFW aquí. Puede usar el --iptables=false o crear el archivo /etc/docker/daemon.json con el siguiente contenido

{ "iptables": false }

el resultado será el mismo, pero la última opción requiere que reinicie el servicio completo de la ventana acoplable con el service docker restart o incluso que reinicie si la ventana acoplable tuvo la oportunidad de agregar reglas de iptables antes de desactivar esta función.

Cuando esté hecho, haz dos cosas más:

$ sed -i -e ''s/DEFAULT_FORWARD_POLICY="DROP"/DEFAULT_FORWARD_POLICY="ACCEPT"/g'' /etc/default/ufw $ ufw reload

así que configura la política de reenvío predeterminada en UFW para aceptar, y usa:

$ iptables -t nat -A POSTROUTING ! -o docker0 -s 172.17.0.0/16 -j MASQUERADE

De esa manera, lo que está logrando es deshabilitar el comportamiento desordenado de la ventana acoplable en sus reglas de iptables y al mismo tiempo se le proporciona el enrutamiento necesario para que los contenedores hagan las conexiones salientes muy bien. Sin embargo, las reglas de UFW todavía estarán restringidas a partir de este punto.

Espero que esto resuelva el problema para usted y cualquiera que llegue aquí en busca de una respuesta.

Describí el problema y la solución de manera más completa en https://www.mkubaczyk.com/2017/09/05/force-docker-not-bypass-ufw-rules-ubuntu-16-04/


No estoy seguro de lo que está preguntando, pero de lo que puedo reunir, ¿le gustaría tener un mejor control sobre quién puede acceder a sus aplicaciones que se ejecutan dentro de Docker? He respondido una pregunta similar aquí para controlar el tráfico a través de un proxy de front-end en lugar de hacerlo con tablas de IP.

Espero que esto ayude

Dylan

Editar

Con el enfoque anterior, puede usar UFW para permitir solo las conexiones entrantes al puerto 80 (es decir, el proxy). Esto mantiene cualquier exposición de puerto al mínimo con la ventaja adicional de que puede controlar el tráfico a través de una configuración de proxy y DNS


Para lo que vale, aquí hay un addendum a la respuesta de @mkubaczyk para el caso donde hay más redes de puentes involucradas en toda la configuración. Estos pueden ser proporcionados por proyectos Docker-Compose y aquí es cómo se pueden generar las reglas adecuadas, dado que estos proyectos son controlados por systemd .

/etc/systemd/system/[email protected]

[Unit] Description=Docker-Compose project: %I After=docker.service BindsTo=docker.service AssertPathIsDirectory=/<projects_path>/%I AssertFileNotEmpty=/<projects_path>/%I/docker-compose.yml [Service] Type=simple Restart=always WorkingDirectory=/<projects_path>/%I ExecStartPre=/usr/bin/docker-compose up --no-start --remove-orphans ExecStartPre=+/usr/local/bin/update-iptables-for-docker-bridges ExecStart=/usr/bin/docker-compose up ExecStop=/usr/bin/docker-compose stop --timeout 30 TimeoutStopSec=30 User=<…> StandardOutput=null [Install] WantedBy=multi-user.target

/usr/local/bin/update-iptables-for-docker-bridges

#!/bin/sh for network in $(docker network ls --filter ''driver=bridge'' --quiet); do iface=$(docker network inspect --format ''{{index .Options "com.docker.network.bridge.name"}}'' ${network}) [ -z $iface ] && iface="br-${network}" subnet=$(docker network inspect --format ''{{range .IPAM.Config}}{{.Subnet}}{{end}}'' ${network}) rule="! --out-interface ${iface} --source ${subnet} --jump MASQUERADE" iptables --table nat --check POSTROUTING ${rule} || iptables --table nat --append POSTROUTING ${rule} done

Obviamente, esto no escalará tan bien.

También es digno de mencionar que todo el concepto básico disfrazará la fuente de cualquier conexión para las aplicaciones que se ejecutan en un contenedor.