Un túnel SSH

Mi primera intención con esta entrada era simplemente anotar a modo de nota/receta/chuleta cómo crear un túnel SSH para poder iniciar sesión en una máquina (o copiar ficheros por SCP) a la que no se tiene acceso directo, es decir, utilizando otra máquina como paso intermedio. Pero al final me he liado.

En primer lugar hay que explicar en qué consiste el túnel o redirección de puertos SSH. Básicamente se trata de abrir un socket TCP en modo escucha, establecer otra conexión con otro socket TCP en modo escucha cuando se establezca una conexión con el primero, y enviar por cada una de estas dos conexiones todo lo que se reciba por la otra. Es decir, la primera conexión TCP es un extremo de un túnel y la segunda conexión TCP es el otro.

Dicho esto, hay que tener en cuenta que el establecimiento y mantenimiento de un túnel SSH está asociado a una sesión SSH. Así, uno de los dos extremos del túnel estará forzosamente en el cliente o en el servidor de dicha sesión SSH. Por lo tanto, hay que decidir si dicho puente se quiere abrir en el cliente o en el servidor de esa necesaria sesión SSH.

Si se desea establecer un puente desde la máquina local (cliente de la sesión SSH) se utilizará el parámetro -L (de Local tunnel, por ejemplo), mientras que si el puente se quiere establecer en la máquina remota (servidor de la sesión SSH) se utilizará -R (de Remote tunnel, para seguir con la misma lógica)

Puesto que una imagen suele valer más que mil palabras, aquí van dos para reflejar ejemplos de ambas situaciones.

Estas imágenes están atribuidas a Serypol [CC BY-SA 4.0 (https://creativecommons.org/licenses/by-sa/4.0)], from Wikimedia Commons.

SSH Tunnel (remote)
Túneles desde servidor de la sesión SSH.
Ssh-L-Tunnel
Túneles desde cliente de la sesión SSH.

Seguiría extendiéndome porque el tema es interesante, pero ya me estoy cansando, así que voy a ir al grano de una vez, que es lo que originalmente pretendía.

En definitiva, para establecer el túnel hay que proporcionar cierta información que clasifico en cuatro grupos. El primero define la necesaria sesión SSH, donde se deberá al menos indicar la máquina con la que establecerla. El segundo determina si el túnel va a situar su entrada en el cliente de dicha sesión SSH (local) o en el servidor (remoto). En el tercero se define el socket TCP de entrada al túnel. Y en el cuarto y último el socket con el que se conecta la salida.

Para mostrar como se pone esto en práctica pondré dos ejemplos de túnel SSH que solucionan el problema que dio pie a esta entrada, uno en modo local y otro en modo remoto.

El problema

El problema a resolver consiste en obtener acceso a un servidor SSH con el que no tenía se tiene conectividad sino a través de otra servidor. La máquina desde la que se desea establecer la conexión se llamará local, la máquina desde la que se dará el salto (jump server se dice por ahí) se llamará proxima y la máquina destino final de la conexión se llamará ultima.

La solución con túnel local

Veamos como establecer el túnel en modo local definiendo los cuatro grupos de información que indiqué antes. El lugar donde colocar la entrada del túnel, como acabo de indicar, será en el lado local de la sesión SSH. La sesión SSH que soportará el túnel se establecerá entre las máquinas local y proxima, como no podía ser de otra forma. El socket TCP de entrada al túnel admitirá conexiones en todos los interfaces de local por el puerto 2222. Y el otro extremo del túnel establecerá conexión con el puerto 22 de ultima.

Para crear este túnel se ejecutaría el siguiente comando:

ssh -L *:2222:ultima:22 proxima -l usuario

En este comando se especifican los cuatro grupos de información tal como se explica a continuación por orden de aparición:

  1. -L indica que se desea crear un túnel desde el extremo local de la sesión SSH a establecer.
  2. *:2222 define la entrada al túnel.
    1. * indica que el puerto de escucha se asociará a todos los interfaces de red (*) en local. Aquí se podría haber indicado una IP concreta (o IPv6) para admitir únicamente conexiones en el interfaz correspondiente a dicha IP.
    2. 2222 es el puerto de escucha en local.
  3. ultima:22 define el destino del túnel.
    1. ultima es la IP o nombre de equipo o de dominio de ultima, la máquina destino de la conexión desde la salida del túnel.
    2. 22 es el puerto en ultima hacia el que se canalizarán las conexiones que se establezcan con el puerto 2222 en proxima.
  4. proxima -l usuario define la sesión SSH que abre y mantiene el túnel.
    • proxima es la IP o nombre de equipo o de dominio de proxima, la máquina intermedia o jump server.
    • -l usuario indica el nombre del usuario con el que se establecerá la sesión SSH a proxima.

Tras la ejecución de este comando se inicia una sesión SSH con proxima y, mientras dure dicha sesión, se mantendrá el túnel con entrada en el puerto 2222 de local y salida hacia el puerto 22 de ultima.

Sin embargo, con esta forma de establecer el túnel debemos mantener activa una sesión SSH que tal vez no necesitamos utilizar. Afortunadamente, se pueden añadir un par de opciones al comando anterior para crear una sesión SSH desligada de nuestra sesión local, de forma que mantengamos abierto el túnel sin requerir una sesión SSH interactiva.

Con el parámetro -f indicamos que la sesión SSH pase a segundo plano, desligándose de la sesión desde la que se lanza. Puesto que para pasar a segundo plano se debe indicar un comando a ejecutar en la sesión SSH, se añade también el parámetro -N que indica explícitamente que no se debe ejecutar ningún comando.

Por tanto el comando completo sería algo así:

ssh -L *:2222:ultima:22 proxima -l usuario -f -N

Ahora se puede iniciar una conexión con el puerto 22 de última para iniciar una sesión SSH desde cualquier máquina con acceso al puerto 2222 de local:

ssh -p 2222 local -l usuario

El túnel canalizará la conexión establecida con el puerto 2222 de local con una nueva conexión desde proxima al puerto 22 de ultima, donde deberá estar escuchando su servidor SSH.

La solución con túnel remoto

Por último, se puede crear la entrada del túnel en la máquina remota de la sesión SSH, es decir, en proxima. Para ello basta con utilizar la opción -R (remota) en lugar de -L (local).

ssh -R *:2222:ultima:22 proxima -l usuario -f -N

En este caso, puesto que la entrada del túnel la crea el servidor SSH (sshd) del lado remoto de la sesión SSH, este deberá tener la opción GatewayPorts habilitada en el fichero /etc/ssh/sshd_config, de lo contrario, solo aceptará conexiones al túnel en el interfaz de loopback, es decir solo se podrán conectar clientes que se ejecuten en la misma máquina que el servidor SSH.

Para permitir la conexión desde otras máquinas hay que comprobar que está la siguiente línea en el fichero /etc/ssh/sshd_config del servidor SSH (proxima) y reiniciar el servidor SSH si no lo estaba previamente:

GatewayPorts yes

Referencias:

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.