Mi objetivo es limitar el acceso a los contenedores docker a unas pocas direcciones IP públicas. ¿Existe un proceso simple y repetible para lograr mi objetivo? Comprender solo los conceptos básicos de iptables mientras uso las opciones predeterminadas de Docker, me resulta muy difícil.
Me gustaría ejecutar un contenedor, hacerlo visible para la Internet pública, pero solo permitir conexiones desde hosts seleccionados. Esperaría establecer una política de ENTRADA predeterminada de RECHAZO y luego solo permitir conexiones desde mis hosts. Pero las reglas y cadenas NAT de Docker se interponen en el camino y mis reglas de ENTRADA se ignoran.
¿Puede alguien proporcionar un ejemplo de cómo lograr mi objetivo dadas las siguientes suposiciones?
Host IP pública 80.80.80.80 en eth0
Host IP privada 192.168.1.10 en eth1
docker run -d -p 3306:3306 mysql
Bloquear todas las conexiones al host / contenedor 3306 excepto de los hosts 4.4.4.4 y 8.8.8.8
Me complace vincular el contenedor solo a la dirección IP local, pero necesitaría instrucciones sobre cómo configurar correctamente las reglas de reenvío de iptables que sobreviven al proceso de docker y los reinicios del host.
Dos cosas a tener en cuenta al trabajar con las reglas de firewall de docker:
Para evitar que sus reglas sean golpeadas por docker, use el DOCKER-USER cadena
Docker hace el mapeo de puertos en el PREROUTING la cadena de la nat tabla. Esto sucede antes de la filter reglas, entonces --dest y --dport verá la IP interna y el puerto del contenedor. Para acceder al destino original, puede usar -m conntrack --ctorigdstport.
Por ejemplo:
iptables -A DOCKER-USER -i eth0 -s 8.8.8.8 -p tcp -m conntrack --ctorigdstport 3306 --ctdir ORIGINAL -j ACCEPTiptables -A DOCKER-USER -i eth0 -s 4.4.4.4 -p tcp -m conntrack --ctorigdstport 3306 --ctdir ORIGINAL -j ACCEPTiptables -A DOCKER-USER -i eth0 -p tcp -m conntrack --ctorigdstport 3306 --ctdir ORIGINAL -j DROP
NOTA: Sin --ctdir ORIGINAL, esto también coincidiría con los paquetes de respuesta que regresan para una conexión desde el contenedor al puerto 3306 en algún otro servidor, que es casi seguro que no es lo que desea. No lo necesitas estrictamente si, como yo, tu primera regla es -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT, ya que eso se ocupará de todos los paquetes de respuesta, pero sería más seguro seguir usando --ctdir ORIGINAL Por cierto.
A diferencia de la ventana acoplable en cadena, no se restablece al crear / iniciar contenedores. Por lo tanto, puede agregar estas líneas a su configuración/script de iptables para aprovisionar el servidor incluso antes de instalar docker e iniciar los contenedores:
Ahora el puerto para MySQL está bloqueado para el acceso externo (eth0) incluso si docker abre el puerto para el mundo. (Estas reglas asumen que su interfaz externa es eth0.)
Eventualmente, tendrás que limpiar ip y reiniciar el servicio docker primero, si lo arruinaste demasiado tratando de bloquear el puerto como lo hice yo.
He creado una imagen de Docker que usa este método para administrar automáticamente las iptables por usted, usando variables de entorno o dinámicamente con etcd (o ambos):
Las reglas de reenvío de Docker permiten todas las direcciones IP de origen externas de forma predeterminada. Para permitir que solo una IP o red específica acceda a los contenedores, inserte una regla anulada en la parte superior de la cadena de filtros de DOCKER. Por ejemplo, para restringir el acceso externo de modo que solo la IP de origen 8.8.8.8 pueda acceder a los contenedores, se podría agregar la siguiente regla: iptables -I DOCKER -i ext_if ! -s 8.8.8.8 -j DROP