Docker en Debian / Ubuntu no respetando ufw firewall ajustes de los puertos de exposición
Docker pasa por alto ufw firewall y expone los puertos al mundo exterior, una fuga de seguridad muy grave.
Otra vez otro inesperado problema de Docker . En un post anterior describí por qué y cómo se debe forzar a Docker a usar un subnet, para prevenir cambios inesperados repentinos en la red con consecuencias como que el correo ya no funcione.
Este post trata sobre Docker no respetando los ajustes de firewall , al menos cuando se ejecuta Debian / Ubuntu y ufw (Uncomplicated Firewall). Docker no le dice esto, y expone los puertos, por lo que este comportamiento es totalmente inesperado.
Mi servidor ISPConfig está ejecutando Debian Stretch. Utilizo ufw como firewall, a continuación se muestran los ajustes principales.
ufw status verbose
Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), deny (routed)
New profiles: skip
To Action From
-- ------ ----
22/tcp ALLOW IN Anywhere
80/tcp ALLOW IN Anywhere
443/tcp ALLOW IN Anywhere
8080/tcp ALLOW IN Anywhere
25 ALLOW IN Anywhere
Como puede ver, todas las conexiones entrantes están bloqueadas excepto unas pocas permitidas.
Mi Docker Python utiliza el servidor HTTP Gunicorn WSGI para servir a la aplicación Python Flask . Nginx se ejecuta en el host y está configurado como inverso proxy para estas aplicaciones. Funciona a la perfección. En el archivo docker-compose.yml los puertos se cargan desde el archivo.env:
services:
web:
...
env_file:
- ./.env
ports:
- "${SERVER_PORT_HOST}:${SERVER_PORT_CONTAINER}"
Para una aplicación, el archivo.env contiene estas líneas:
SERVER_PORT_HOST=8001
SERVER_PORT_CONTAINER=8001
Así que en efecto la línea docker-compose que se utiliza es:
ports:
- "8001:8001"
El problema: Docker El puerto 8001 está expuesto a la red exterior aunque ufw esté configurado para bloquear las conexiones entrantes.
Esto significa que la aplicación/servicio Docker también es visible en <SERVER-IP>:8001. Esto no sólo es muy malo, sino que también es totalmente inesperado ya que se configuró ufw para bloquear todas las conexiones entrantes.
Soluciones
Hay varias soluciones para esto, aquí escojo enlazar el puerto a la máquina anfitriona. Las líneas docker-compose.yml se convierten entonces en:
ports:
- "127.0.0.1:8001:8001"
Esto funciona para mí.
Otras formas de resolver esto son evitar que Docker se confunda con el firewall, añadir reglas al archivo ufw /etc/ufw/after.rules, etc. Vea los enlaces a continuación.
Resumen
Algunas personas consideran este comportamiento de Docker como un error, y yo sólo puedo estar de acuerdo con esto. Ufw es un firewall, un programa muy importante para controlar la seguridad. Ufw es muy utilizado y si otro programa pasa por alto su comportamiento el usuario debe ser informado. Hasta que esto no se arregle, al menos Docker debería emitir un gran mensaje de advertencia al iniciar una aplicación.
Enlaces / créditos
Be careful with Docker ports!
https://dev.to/kovah/be-careful-with-docker-ports-3pih
Docker service exposed publicly though made to expose ports to localhost only
https://stackoverflow.com/questions/50621936/docker-service-exposed-publicly-though-made-to-expose-ports-to-localhost-only
Docker services only available to the local host
https://stackoverflow.com/questions/54261105/docker-services-only-available-to-the-local-host
How to fix the Docker and UFW security flaw
https://www.techrepublic.com/article/how-to-fix-the-docker-and-ufw-security-flaw/
The dangers of UFW + Docker
https://blog.viktorpetersson.com/2014/11/03/the-dangers-of-ufw-docker.html
What is the best practice of docker + ufw under Ubuntu
https://stackoverflow.com/questions/30383845/what-is-the-best-practice-of-docker-ufw-under-ubuntu
Leer más
Docker
Deje un comentario
Comente de forma anónima o inicie sesión para comentar.
Comentarios (1)
Deje una respuesta.
Responda de forma anónima o inicie sesión para responder.
Ein wirklich schweres und immer noch aktuelles Sicherheitsproblem. Danke für die schnelle Lösung für Docker Compose.
Recientes
- Cómo ocultar las claves primarias de la base de datos UUID de su aplicación web
- Don't Repeat Yourself (DRY) con Jinja2
- SQLAlchemy, PostgreSQL, número máximo de filas por user
- Mostrar los valores en filtros dinámicos SQLAlchemy
- Transferencia de datos segura con cifrado de Public Key y pyNaCl
- rqlite: una alternativa de alta disponibilidad y dist distribuida SQLite
Más vistos
- Usando Python's pyOpenSSL para verificar los certificados SSL descargados de un host
- Usando UUIDs en lugar de Integer Autoincrement Primary Keys con SQLAlchemy y MariaDb
- Conectarse a un servicio en un host Docker desde un contenedor Docker
- Usando PyInstaller y Cython para crear un ejecutable de Python
- SQLAlchemy: Uso de Cascade Deletes para eliminar objetos relacionados
- Flask RESTful API validación de parámetros de solicitud con esquemas Marshmallow