Redirección de puertos con iptables + contrack

Pues seguimos con éstos pequeños errores que hemos cometido siempre y que ahora en un momento de cambios y con mucho mas entendimiento llegan mejores soluciones para que las cosas funcionen mejor (tanto a nivel técnico como personal). Hoy estoy tiernecilla y quiero agradecer con éste post todas éstas personas que seguís los posts que publico y tenéis al igual que yo éste blog como una herramienta de consulta, un lugar claro, sin muchas complicaciones donde encontrar justo aquello que necesito en cada momento o me da la pista para poder seguir avanzando con algo mas grande que estoy construyendo con el paso de los días.

Ésta vez me encuentro solucionando un problema que inicialmente parecía de nginx pero ha resultado ser de iptables, y es que las cosas nunca son lo que parecen a primera vista y es necesario tener un gran conocimiento del sistema para entender como poder solucionar los problemas de base y encontrar una solución definitiva que evita fallos futuros, para casos como hoy que ya en producción me encuentro con un problema grave de base. Para que un sistema funcione bien, las capas inferiores (base) deben estar bien.

Me dejo ya de palabrerías y comentarios dobles y me pongo en materia. El post que rectifico es éste: Proxmox + nat + iptables.

Gracias a las configuraciones de las antenas en los supernodos entiendo que se deben marcar los paquetes tanto de entrada (prerouting) como de salida (postrouting). En TCP hay una llamada de un cliente al sistema y el sistema devuelve la llamada y ésta también tiene que ser trackeada. Ya si como gateway pones la ip del firewall, es una buena práctica para solucionar problemas futuros de configuraciones erróneas.

Como no se lo puedo explicar a nadie y que lo entienda, pues lo escribo aquí a ver si algún otro desalmado como yo me comprenda y nos podamos sentir mas felices los dos :)

Debido a las ocurrencias diarias que terminamos haciendo aquellas cosas que no debemos, se me ocurre la gran y genial idea de poner un entorno de producción de mi nuevo producto, colibrí (nginx + uwsgi-emperor + python/django), en un servidor en online en el que la ip pública del servidor está en el host de proxmox. Para poder redistribuir los puertos entre los distintos servicios contenarizados en containers LXC dentro del proxmox idée el anterior post, ésto me ha funcionado de maravilla con nextcloud/collabora/etc. y mail, pero con el proxy nginx y el uwsgi-emperor, nginx ha empezado a soltar errores 502 bad gateway. Tras revisar varias configuraciones para montar el frontal de nginx y exponer uwsgi-emperor como un socket tcp en lugar de uno unix (luego hago un post de ésto), poner como gateway de los contenedores de django el del frontal de nginx, etc., los errores 502 seguían apareciendo, así que he llegado a éste interesante artículo que habla de posibles causas para un 502: Qué es el error 502 y cómo se soluciona [6 métodos] y la de una configuración que comulga mucho mas con lo aprendido con las antenas: How To Forward Ports through a Linux Gateway with Iptables.

En resumen y siguiendo la dinámica de fácil sencillo y rápido de éste blog:

Instalamos conntrack en el host (en mi caso el proxmox)

# apt -y install conntrack

Hacemos un backup de la configuración actual y comentamos en este caso la configuración para los puertos 80 y 443 que es el que tengo que arreglar ahora:

# cd /etc
# cp firewall.conf{,.bkp}
# vi /etc/firewall.conf
# iptables-restore < /etc/firewall.conf

Ahora creamos las reglas que nos interesan. Mis contenedores comparten una subred que está alojada en vmbr1. vmbr0 es donde está la ip pública del servidor proxmox el cual estoy configurando iptables.

iptables -A FORWARD -i vmbr0 -o vmbr1 -p tcp --syn --dport 80 -m conntrack --ctstate NEW -j ACCEPT
iptables -A FORWARD -i vmbr0 -o vmbr1 -p tcp --syn --dport 443 -m conntrack --ctstate NEW -j ACCEPT
iptables -A FORWARD -i vmbr0 -o vmbr1 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -A FORWARD -i vmbr1 -o vmbr0 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -P FORWARD DROP
iptables -t nat -A PREROUTING -i vmbr0 -p tcp --dport 80 -j DNAT --to-destination 192.168.1.6
iptables -t nat -A POSTROUTING -o vmbr1 -p tcp --dport 80 -d 192.168.1.6 -j SNAT --to-source 192.168.1.1
iptables -t nat -A PREROUTING -i vmbr0 -p tcp --dport 443 -j DNAT --to-destination 192.168.1.6
iptables -t nat -A POSTROUTING -o vmbr1 -p tcp --dport 443 -d 192.168.1.6 -j SNAT --to-source 192.168.1.1

Guardamos la configuración al fichero de iptables

# iptables-save > /etc/firewall.conf

Y el contenido es el siguiente

# Generated by iptables-save v1.4.21 on Fri Oct  4 00:27:32 2019
*nat
:PREROUTING ACCEPT [1123:78492]
:INPUT ACCEPT [1045:73070]
:OUTPUT ACCEPT [498:30008]
:POSTROUTING ACCEPT [490:29400]
-A PREROUTING -i vmbr0 -p tcp -m tcp --dport 80 -j DNAT --to-destination 192.168.1.6
-A PREROUTING -i vmbr0 -p tcp -m tcp --dport 443 -j DNAT --to-destination 192.168.1.6
-A POSTROUTING -o vmbr0 -j MASQUERADE
-A POSTROUTING -d 192.168.1.6/32 -o vmbr1 -p tcp -m tcp --dport 80 -j SNAT --to-source 192.168.1.1
-A POSTROUTING -d 192.168.1.6/32 -o vmbr1 -p tcp -m tcp --dport 443 -j SNAT --to-source 192.168.1.1
COMMIT
# Completed on Fri Oct  4 00:27:32 2019
# Generated by iptables-save v1.4.21 on Fri Oct  4 00:27:32 2019
*filter
:INPUT ACCEPT [65:10204]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [46:10941]
-A FORWARD -i vmbr1 -j ACCEPT
-A FORWARD -i vmbr0 -o vmbr1 -p tcp -m tcp --dport 80 --tcp-flags FIN,SYN,RST,ACK SYN -m conntrack --ctstate NEW -j ACCEPT
-A FORWARD -i vmbr0 -o vmbr1 -p tcp -m tcp --dport 443 --tcp-flags FIN,SYN,RST,ACK SYN -m conntrack --ctstate NEW -j ACCEPT
-A FORWARD -i vmbr0 -o vmbr1 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -i vmbr1 -o vmbr0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
COMMIT
# Completed on Fri Oct  4 00:27:32 2019

Y si usamos iptables para ver como está la cosa la vemos así:

# iptables -L
Chain INPUT (policy ACCEPT)
target     prot opt source               destination         

Chain FORWARD (policy DROP)
target     prot opt source               destination         
ACCEPT     all  --  anywhere             anywhere            
ACCEPT     tcp  --  anywhere             anywhere             tcp dpt:http flags:FIN,SYN,RST,ACK/SYN ctstate NEW
ACCEPT     tcp  --  anywhere             anywhere             tcp dpt:https flags:FIN,SYN,RST,ACK/SYN ctstate NEW
ACCEPT     all  --  anywhere             anywhere             ctstate RELATED,ESTABLISHED
ACCEPT     all  --  anywhere             anywhere             ctstate RELATED,ESTABLISHED

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination     

    
# iptables -L -t nat
Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination         
DNAT       tcp  --  anywhere             anywhere             tcp dpt:http to:192.168.1.6
DNAT       tcp  --  anywhere             anywhere             tcp dpt:https to:192.168.1.6

Chain INPUT (policy ACCEPT)
target     prot opt source               destination         

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination         

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination         
MASQUERADE  all  --  anywhere             anywhere            
SNAT       tcp  --  anywhere             192.168.1.6          tcp dpt:http to:192.168.1.1
SNAT       tcp  --  anywhere             192.168.1.6          tcp dpt:https to:192.168.1.1

Nota: Tengo mas puertos configurados, pero para simplificar la cosa sólo me centro en los puertos 80 y 443.

Bueno, creo que voy a tener que rendirme de nuevo porque creo que sigue fallando, hehe, pero bueno, hasta aquí hemos llegado ofreciendo una forma mucho mas correcta de como configurar iptables en un host linux :) Espero que os haya sido de ayuda! :D

A seguir pensando en como solucionar el problema por ejemplo eliminando la variable de iptables, que el frontal nginx sea quien tenga la IP pública.

One Comment

Deixa un comentari

L'adreça electrònica no es publicarà. Els camps necessaris estan marcats amb *

Aquest lloc utilitza Akismet per reduir els comentaris brossa. Apreneu com es processen les dades dels comentaris.