Dos entradas de gestión en un mismo host, un solo puerto de servicio y una regla de política que debía ayudar a ambas. La regla coincide con el puerto de origen 22, envía la búsqueda a una tabla que solo conoce el valor predeterminado de WAN, y la entrada VPN deja de responder a nuevos inicios de sesión mientras la entrada directa sigue funcionando. Nada de eso es misterioso una vez que el selector se lee correctamente. Un puerto de origen identifica un servicio, no la ruta por la que llegó una conexión.

Dos entradas, un solo puerto de servicio

El host tiene una dirección del lado de la LAN y una dirección VPN, y sshd escucha en ambas. Por lo tanto, una sesión directa y una sesión tunelizada comparten el puerto de servicio y solo difieren en qué dirección local recibe la conexión.

Esa diferencia basta para elegir una ruta de respuesta, y es exactamente la diferencia que una regla basada en el puerto descarta. Ambas sesiones producen respuestas cuyo puerto de origen es 22, así que una regla que coincida con ese puerto no puede separarlas. Envía ambas búsquedas a la misma tabla, y una de ellas recibe una respuesta que no encaja. La solución es hacer coincidir el atributo que realmente difiere.

Dar a cada entrada su propio puerto también funcionaría, y tratar eso como un requisito es una decisión de diseño, no una propiedad de SSH.

Lee la regla y luego la tabla

Una regla de política es un selector ordenado, y la primera que devuelve una respuesta utilizable termina la búsqueda. Lee la lista en orden y fíjate en qué regla puede ganar.

Después lee la tabla a la que apunta esa regla, porque una regla que se resuelve con éxito no es una regla que se resuelva de forma útil. Una tabla que solo contiene una ruta predeterminada envía la respuesta con origen VPN por la interfaz WAN. Una ruta más específica en una tabla posterior nunca se consulta, y por eso añadir una segunda tabla tantas veces no cambia nada. La tabla seleccionada es lo que hay que inspeccionar.

ip -4 rule show
ip route show table 100
ip route show table main

Esas dos salidas juntas explican el resultado; cualquiera de ellas por sí sola invita a una conclusión errónea.

Limita la regla al flujo que quieres decir

El atributo que separa las dos entradas es la dirección de origen local. Una regla que coincide con esa dirección envía solo las sesiones tunelizadas a la tabla privada y deja las sesiones directas en la tabla principal.

Esa regla debe emparejarse con una tabla que contenga la ruta privada y el camino de retorno para esa subred. Limita ambas al tráfico de gestión en lugar de a cada servicio del host. Una regla que captura todo el tráfico de esa dirección también redirigirá cualquier otra cosa que el host envíe desde ella. Lo estrecho vence a lo ingenioso aquí, porque la siguiente persona tiene que leerlo.

sudo ip rule add from 10.90.0.1 lookup 100 priority 100
sudo ip route add 10.90.0.0/24 dev wg0 table 100
ip route get 10.90.5.20 from 10.90.0.1

Si ambas entradas se traducen a una sola dirección local, esa distinción desaparece y el diseño necesita estado consciente de la conexión en su lugar.

Mantén separados el receptor, el permiso y la selección de respuesta

Tres cosas separadas deben ser ciertas antes de que una sesión funcione: la dirección existe, el servicio escucha en ella y la respuesta encuentra el camino de vuelta. Un cambio de ruta solo arregla la tercera.

La configuración del receptor es su propio archivo y su propia recarga, y varias direcciones de escucha son normales. La autenticación es otra tercera decisión, y una excepción de enrutamiento no da acceso a nadie. Mantén la verificación de la clave del host, la autenticación de la cuenta y las restricciones de origen en ambas entradas, y resiste el impulso de debilitar los demás controles del túnel para que funcione un solo camino de gestión.

Mantén un canal de recuperación que no dependa de la ruta que estás cambiando, porque un error aquí bloquea la propia solución.

Demuéstralo con una sesión nueva, no con una antigua

Un terminal establecido no demuestra nada, ya que fue admitido antes del cambio. Abre una sesión nueva a través de cada entrada prevista.

ss -ltnp | grep ':22'
sudo sshd -T | grep -i listenaddress
ssh -v [email protected] true
sudo journalctl -u ssh -n 30

Después repite la reconexión de VPN y vuelve a intentarlo, porque una ruta que sobrevive a una reconexión no es lo mismo que una añadida a una tabla que la reconexión vacía. Observa las fuentes denegadas por separado de las permitidas, para que un intento bloqueado no se esconda detrás de una sesión que funciona. Guarda la dirección local, la regla y la tabla junto al resultado. Si en cambio divides los puertos, regístralo como una decisión operativa y no como un límite de SSH.

Artículos relacionados