¿Cómo puede Discourse eludir UFW? Solo habilité el puerto 22, por lo que todos los demás puertos deberían estar cerrados. Pero un foro funcionó de todos modos. ¿Cómo es eso posible?
Gotita de DigitalOcean, pero eso no debería significar nada. Y ninguna instalación de un clic, sino la forma oficial.
Esta no es una pregunta de soporte pura, pero aquí no tenemos una categoría llamada Preguntas básicas estúpidas de principiantes
¿Intentaste abrir el foro en una ventana de incógnito o en un navegador diferente? Es fácil dejarse engañar por la versión en caché que aparece. A mí mismo me ha pasado y otro desarrollador me dijo que el sitio de staging se veía bien cuando en realidad no estaba funcionando en absoluto.
Solo 22/tcp (OpenSSH) ALLOW IN Anywhere como debería ser. Esas son las dos cosas que siempre hago: permitir OpenSSH y habilitar UFW.
Abro puertos solo si es necesario, como cuando instale Nginx. Pero como ese VPS era solo para Discourse, no hice nada más; olvidé UFW por completo.
Ese no puede ser el caso. Ese foro estuvo activo durante semanas.
Me desperté ante esta situación cuando conecté Nginx/Varnish a ese VPS y necesité abrir otro puerto, y me di cuenta de que el único que estaba abierto era el puerto 22.
Editar:
¿Cómo pude enviar correos electrónicos? El puerto 587 tampoco estaba abierto
No está claro si estás diciendo que el valor predeterminado está configurado en denegar o no. La razón por la que pregunto específicamente sobre la línea “Default” es porque es posible tener un valor predeterminado de permitir y configurar un puerto específico para permitir, aunque esto último no cambia nada en esa disposición.
Si alguien más configuró Discourse, ¿es posible que esa persona haya cambiado el valor predeterminado a permitir en lugar de permitir los puertos HTTP/HTTPS?
Supongo que esto es SMTP en otro lugar, tu servidor Discourse conectándose a ese servidor SMTP usando el puerto 587. Las conexiones salientes están permitidas en todos los puertos por defecto, por lo que UFW no interferirá con el envío de correos electrónicos a menos que cambies explícitamente la política de salida.
[quote=“Simon Manning, post:7, topic:231873, username:Simon_Manning”]¿es posible que esa persona haya cambiado el valor predeterminado a permitir en lugar de permitir los puertos HTTP/HTTPS?
[/quote]
No. Pero ¿allow (outgoing) permite algo saliente? Si es así, entonces volvemos a “no tenemos aquí una categoría llamada Preguntas estúpidamente básicas de principiantes” y he aprendido cosas nuevas.
Editar:
Todavía estoy perdido, pero ¿cómo es deny (incoming)?
La respuesta corta es que Discourse no puede eludir las reglas de su firewall y el lugar para hacer preguntas estúpidas sobre cosas del sistema operativo es en algún lugar como Stack Exchange. (Por favor, no piense que soy grosero. Ahí es donde residen esas respuestas. Después de ejecutar Linux desde los primeros lanzamientos, todavía voy a lugares como ese para todas mis preguntas estúpidas. ¡Todavía las tengo!)
Conozco el lugar Hay una relación señal/ruido demasiado alta. Bueno, esa fue una caracterización injusta, pero quise decir que es realmente difícil encontrar cosas relevantes allí. Es tan masivo.
Esta es en realidad una muy buena pregunta y una que me sorprende que nadie más haya hecho todavía. La respuesta es complicada, pero hasta ahora las respuestas sobre este tema han sido desafortunadamente despectivas en tono sin responder a la pregunta.
No es que Discourse esté eludiendo ufw, sino que docker elude ufw agregando reglas que hacen que los puertos expuestos de los contenedores de docker funcionen a pesar de la presencia de ufw.
¿Qué está pasando?
Los paquetes entrantes destinados a un contenedor llegan a la tabla FORWARD, no a la tabla INPUT como se podría esperar.
Instalación previa de docker
Chain FORWARD (policy DROP 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
0 0 ufw-before-logging-forward all -- any any anywhere anywhere
0 0 ufw-before-forward all -- any any anywhere anywhere
0 0 ufw-after-forward all -- any any anywhere anywhere
0 0 ufw-after-logging-forward all -- any any anywhere anywhere
0 0 ufw-reject-forward all -- any any anywhere anywhere
0 0 ufw-track-forward all -- any any anywhere anywhere
Instalación posterior de docker
Chain FORWARD (policy DROP 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
8 416 DOCKER-USER all -- any any anywhere anywhere
8 416 DOCKER-ISOLATION-STAGE-1 all -- any any anywhere anywhere
0 0 ACCEPT all -- any docker0 anywhere anywhere ctstate RELATED,ESTABLISHED
4 256 DOCKER all -- any docker0 anywhere anywhere
4 160 ACCEPT all -- docker0 !docker0 anywhere anywhere
0 0 ACCEPT all -- docker0 docker0 anywhere anywhere
0 0 ufw-before-logging-forward all -- any any anywhere anywhere
0 0 ufw-before-forward all -- any any anywhere anywhere
0 0 ufw-after-forward all -- any any anywhere anywhere
0 0 ufw-after-logging-forward all -- any any anywhere anywhere
0 0 ufw-reject-forward all -- any any anywhere anywhere
0 0 ufw-track-forward all -- any any anywhere anywhere
La razón por la que los paquetes llegan a la tabla forward se debe a las reglas que docker agrega a la tabla nat:
Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
210 12734 DOCKER all -- any any anywhere anywhere ADDRTYPE match dst-type LOCAL
Chain DOCKER (2 references)
pkts bytes target prot opt in out source destination
0 0 RETURN all -- docker0 any anywhere anywhere
0 0 DNAT tcp -- !docker0 any anywhere anywhere tcp dpt:https to:172.17.0.2:443
107 6848 DNAT tcp -- !docker0 any anywhere anywhere tcp dpt:http to:172.17.0.2:80
nat/PREROUTING se procesa antes de que se tome la decisión de enviar paquetes a través de INPUT o FORWARD.
En última instancia, el problema es que hay dos servicios en el sistema que modifican las reglas del firewall. ufw no sabe nada de esto, por lo que solo puede informar lo que él ha configurado.
Una solución
Para esto, se debe reconfigurar el firewall para que pase el tráfico destinado a docker a través de las cadenas de ufw también:
Utilizo la siguiente ligera adaptación de su trabajo, implementada antes de habilitar ufw:
# Robado de https://github.com/chaifeng/ufw-docker - parece sensato
# añadir el reenvío a ufw-user-input permite conexiones a
# puertos reenviados que hemos abierto explícitamente
cat <<EOUFW >> /etc/ufw/after.rules
# BEGIN UFW AND DOCKER
*filter
:ufw-user-forward - [0:0]
:ufw-user-input - [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 -p udp -m udp --sport 53 --dport 1024:65535 -j RETURN
-A DOCKER-USER -j ufw-user-forward
-A DOCKER-USER -j ufw-user-input
-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 tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -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 DROP -p udp -m udp --dport 0:32767 -d 192.168.0.0/16
-A DOCKER-USER -j RETURN
COMMIT
# END UFW AND DOCKER
EOUFW
Este tema está resuelto, pero reveló un problema menor en mi configuración. Lo explicaré si alguien busca algo similar algún día.
Tenía un VPS donde Nginx se encarga de SSL y otras cosas de todos mis sitios (muchos de ellos, el inglés es un idioma muy extraño ). Nginx envía solicitudes a Varnish. Es un proxy inverso inútil para Discourse, pero realiza cierto filtrado. Varnish envía solicitudes a otro VPS donde vive Discourse usando el puerto 83. Ambos VPS escuchan el mismo puerto y solo se permite a ambas IPs. Estaba totalmente feliz, hasta ahora.
Probé qué sucede cuando usé el puerto 443 curl -I https://forum.example.tld:443. Funcionó bien, porque todavía tengo un certificado SSL válido en el lado de Discourse (hice este cambio hace algunas semanas).
La respuesta de @supermathie explica por qué sucede esto y cómo solucionarlo. Claro, no hay problemas de seguridad debido a eso en absoluto, hasta donde sé, pero es realmente molesto
Supongo que no se pregunta porque no es frecuente que alguien instale discourse y quiera que no funcione, así que cuando docker lo hace funcionar cuando has configurado el firewall de tal manera que no debería, la mayoría de la gente no se queja.
Es un problema muy interesante, pero parece un poco esotérico, y no es un problema de Discourse, sino una peculiaridad de docker. La pregunta se reduce a “¿cómo puedo configurar mi firewall para evitar que discourse funcione?”. Intentaré recordar lo de la preruta.
¡Si supiera la respuesta, no habría sido despectivo! ¡Gracias por salvar el día en este asunto!
Ciertamente no intentaba ser despectivo, sino solucionar problemas… aunque evidentemente partía de una posición de ignorancia sobre lo que Docker estaba haciendo. ¡Toda esa información es muy útil, gracias por responder!
Si el OP o alguien más puede cambiarlo, podría valer la pena cambiar la solución marcada.
Si bien es más un problema de Docker, puedo ver algunas hipótesis de Discourse que se derivan de esto. Por ejemplo, podría tener un servidor de oficina accesible desde el exterior, pero quiero configurar UFW para restringir Discourse a que solo sea accesible desde el interior de la oficina. Las adiciones de Docker impedirían esa configuración.
Aunque en ese escenario en particular, lo configuraría en un firewall de hardware/hipervisor en lugar de UFW en el host de todos modos.
En realidad, lo resolví después de un tiempo y escribí este script de bash para hacerlo en instalaciones de Discourse.
Restablece tu firewall, instala ufw-docker-util (que edita el archivo after.rules), luego agrega los puertos 443 y 80 a tu lista de permitidos. Listo.
También permite el puerto 22 desde cualquier IP para asegurarte de no quedarte fuera. Después de que todo funcione, vuelve a asegurar el puerto 22.
EDITAR: el script funciona pero reconstruir Discourse después de usarlo fallará: fatal: unable to access 'https://github.com/discourse/discourse.git/': Could not resolve host: github.com - así que NO uses el script a menos que sepas cómo resolver esto.
La última vez que hice un script de bash, cambié el propietario de todos los directorios a www-data:www-data, ¡así que para mí un trabajo como este me facilita la vida!
Pero en general, me gustaría ver que Docker siga completamente UFW/iptables. Solo porque uso GeoIP-blocking a través de ipables (sí, lo sé, UFW es solo una interfaz minimalista para iptables).
Claro, ya no estamos en Discourse, pero aquí podemos ver por qué los programadores y los usuarios finales no siempre se entienden tan bien: los programadores ven el mundo como bloques lógicos y construcciones if/then/else, pero los usuarios finales lo ven con contexto completo. Significa que, como uso Discourse, aunque funcione dentro de Docker, desde mi punto de vista es Discourse el que no sigue mis reglas
Esto debería ir a Praise, pero cambié la URL del foro hace unas semanas. Y conseguí que todos los script kiddies del mundo y bots de SEO inútiles me visitaran. Conseguí en un VPS de 2 GB/1 vCPU de DigitalOcean 3000 agentes de usuario diferentes por hora y Discourse simplemente no se preocupó. Cualquier instalación de WordPress sería lenta/caída después de ese tipo de rush tipo ddos.
Entonces, no necesito forzar a Discourse (bueno, a Docker) a seguir las prohibiciones de Fail2ban y mis reglas, pero odio tanto a esos bots.