Docker es una herramienta fantástica para desplegar aplicaciones en contenedores y mantener un sistema ordenado y limpio y UFW (Uncomplicated Firewall) es el cortafuegos “sin complicaciones” que se suele usar en los despliegues de Ubuntu o Debian.
El problema viene cuando los juntas ya que, por defecto, Docker ignora totalmente las reglas de UFW creando sus propias reglas de iptables antes que las de UFW, de modo que un puerto publicado por Docker queda abierto al exterior aunque UFW diga que está cerrado. Por ejemplo, si ejecutas:
docker run -d --name webtest -p 8080:80 nginx
E intentamos denegar ese acceso con:
ufw deny 8080
seguirás pudiendo acceder al contenedor desde fuera (el puerto 8080 se abre a todas las IP).
En la práctica esto puede generar que servicios (como bases de datos :D) que creías “solo internos” terminen expuesto a Internet mientras UFW se queda mirando.
¿Cómo podemos arreglar esto?
Una forma sencilla y clásica de evitar esto es no publicar el puerto en todas las interfaces, sino limitarlo a la interfaz de loopback (localhost). Así Docker solo abre el puerto 8080 en la dirección local y no queda expuesto públicamente. Por ejemplo:
docker run -d --name webtest -p 127.0.0.1:8080:80 nginx
De esta manera, incluso si “publicas” el contenedor, solo será accesible desde la máquina local. UFW puede entonces bloquear el acceso a ese puerto desde cualquier otra IP, porque técnicamente no está abierto al público. Para pasar el tráfico de internet a localhost, usamos un proxy y ya tenemos una arquitectura más segura. Quedaría algo así:
Desde Docker 17.06+, existe la cadena especial DOCKER-USER en iptables, que segun la documentación oficial se va a procesar antes que las reglas de Docker.Por ejemplo, podrías agregar reglas que bloqueen todo por defecto y luego permitan sólo lo que necesitas. Un caso típico es algo así:
# Aceptar conexiones establecidas
iptables -I DOCKER-USER -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
# Permitir sólo MySQL (3306) como ejemplo
iptables -I DOCKER-USER -p tcp --dport 3306 -j ACCEPT
# Bloquear todo lo demás
iptables -I DOCKER-USER -j DROP
Por otro lado, en vez de escribir directamente iptables, se pueden integrar estas reglas con UFW (por ejemplo, editando /etc/ufw/after.rules para que llame a ufw-user-forward o a tu propio DOCKER-USER para que UFW meta sus reglas a la cadena DOCKER-USER en cada reinicio, de forma que Docker ya no pueda saltearlas. Sin embargo es bastante más complicado que la solución 1 en mi opinión.
Como comprenderéis este asunto es de sobra conocido por la comunidad y un dev decidió ponerle remedio mediante su propio wrapper que añade reglas específicas a UFW para manejar correctamente el tráfico de Docker: ufw-docker
El script funciona parecido a ufw, pero orientado a contenedores, por ejemplo algunas de las operaciones más comunes que podemos hacer:
Ver contenedores en ejecución:
sudo ufw-docker list
Permitir acceso a un puerto de un contenedor
sudo ufw-docker allow httpd 80
Denegar acceso
sudo ufw-docker deny nginx 443
Limitar acceso solo a una IP
sudo ufw-docker allow from 203.0.113.5 to nginx 8080
Obviamente existen más maneras de limitar el acceso como poner un firewall físicco delante del servidor pero estas son las más sencillas a mi parecer.
Copyright © TheDarknest All Rights Reserved