Un cortafuegos que solo admite el puerto VPN no es una regla. Son tres decisiones separadas que casualmente afectan al mismo número de puerto: la cadena de entrada decide qué puede llegar a un proceso local, la cadena de reenvío decide qué puede atravesar el host en nombre de los clientes del túnel, y la tabla NAT reescribe la dirección de origen a la salida. Equivoque una de ellas y el resultado rara vez es una caída limpia. Obtiene un host que acepta clientes pero no carga nada, o un host que parece cerrado hasta que alguien lee el orden de las cadenas.

El único puerto que no se puede cerrar

El oyente de la VPN debe aceptar conexiones desde direcciones que no puede predecir, así que es un servicio público por definición. Esa es la única excepción sobre la que se construye el diseño: un puerto UDP para OpenVPN, un puerto UDP para WireGuard, un puerto TCP para una VPN SSL. Todo lo demás pertenece detrás del túnel, lo que significa que los servicios de aplicación deben enlazarse a la dirección del túnel o a loopback, no a todas las interfaces.

Enlazar, sin embargo, no es aplicar. Un proceso enlazado a 0.0.0.0 solo es alcanzable si una regla lo admite, y la política por defecto es el recurso para el tráfico que no coincidió con ninguna regla, no la regla que gobierna el puerto. Una admisión colocada por encima de su denegación sigue siendo una admisión, y mover un servicio fuera de la dirección pública es una mejora independiente, no un sustituto de la cadena.

Entrada, reenvío y NAT responden preguntas distintas

El tráfico de entrada va destinado al propio host, así que ahí viven el oyente de la VPN y la ruta administrativa. El tráfico de reenvío atraviesa el host, y los clientes del túnel lo necesitan además de net.ipv4.ip_forward=1. La configuración clásica medio rota permite el flujo saliente y olvida la dirección de vuelta, así que el cliente completa su negociación y después no se carga nada; una regla de conntrack para tráfico establecido y relacionado cubre esa dirección.

NAT es la tercera pregunta. Sin una reescritura en postrouting, los paquetes reenviados salen con el origen privado del túnel y se descartan más arriba, porque ninguna red más allá del host sabe enrutar el grupo de vuelta. El prefijo de origen de esa regla debe coincidir con el grupo de la VPN, no con la dirección propia del host, y lo mismo vale para la regla de reenvío que nombra la subred de clientes.

IPv6 es una segunda política, no una idea posterior. Un host con una cadena IPv4 estricta y una política abierta en ip6tables no ha cerrado nada; los servicios siguen siendo alcanzables por la otra familia. O refleje el conjunto de reglas con ip6tables o desactive IPv6 a propósito en la interfaz pública, y anote cuál eligió.

Una base que se lee de una pasada

Empiece por la denegación y luego añada solo lo que el host necesita. Primero loopback y las respuestas, después la ruta administrativa, después el oyente del túnel, después la política de reenvío para los clientes:

iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW -j ACCEPT
iptables -A INPUT -p udp --dport 1194 -m conntrack --ctstate NEW -j ACCEPT
sysctl -w net.ipv4.ip_forward=1
iptables -A FORWARD -i tun0 -o eth0 -s 10.8.0.0/24 -j ACCEPT
iptables -A FORWARD -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADE

Los nombres de interfaz, el puerto y el grupo son marcadores de posición; léalos del servidor en lugar de copiarlos. Guardar el resultado importa tanto como escribirlo, porque un conjunto de reglas que vive solo en memoria desaparece en el siguiente reinicio y reabre el host sin hacer ruido. Hágalo persistente con el mecanismo de la distribución y guarde una copia fuera de la máquina para el día en que la máquina no arranque.

Cerrar el último puerto sin perder el host

Hay una trampa en el diseño. Si SSH solo existe a través del túnel, un servicio VPN fallido se lleva SSH consigo, y la única forma de volver puede ser una consola que nunca abrió. Antes de cerrar el último puerto público, confirme que esa consola existe y que realmente puede usarla, o mantenga una ruta administrativa estrecha que no dependa del túnel: SSH desde una dirección fija, solo claves, autenticación por contraseña desactivada.

Aplique el cambio desde una sesión ya establecida, no a través de la conexión que está a punto de filtrar. Programe una reversión para que un error caduque en lugar de volverse permanente, por ejemplo una tarea systemd-run --on-active=10min que restaura el conjunto de reglas anterior, y mantenga abierta una segunda sesión SSH mientras prueba la primera. Luego verifique que la tarea de reversión se ejecuta de verdad, porque una recuperación no probada es lo mismo que ninguna recuperación.

Verifique la ruta, no el script

Lea las reglas cargadas, no el archivo que se suponía que las cargaba. Desde un host externo autorizado, confirme que solo responden los puertos previstos; desde dentro del túnel, confirme que los servicios que quería publicar son alcanzables. Una política de denegación por defecto que también bloquea el tráfico del túnel parece idéntica a un cierre que funciona hasta que alguien intenta usarlo.

iptables -S
iptables -t nat -S
ss -lntup
ip -4 addr show

Anote el puerto permitido, el grupo de clientes, la interfaz del túnel, el origen administrativo y el procedimiento de consola junto a la configuración. El siguiente cambio en el grupo o en el nombre de la interfaz debe reflejarse tanto en el filtro como en la regla NAT, o el host vuelve a un estado medio abierto sin que nadie lo note.

Un hábito vale más que el conjunto de reglas: después de cada cambio, demuestre la ruta de reenvío con una petición de cliente y la ruta de recuperación con una segunda sesión. Un cierre que no ha usado es una hipótesis.

Artículos relacionados