Tunel reverso SSH
La cuestión es que por una causa molesta tengo que lograr acceder por ssh
a
una pc que es inaccesible, por ejemplo, porque está detrás de un NAT, así
empezó la cosa, pero por suerte no es al primero al que le pasa, así que hay
bastante ayuda en Internet.
El problema es que esa mucha ayuda toca muchos detalles, es un problema viejo y hay soluciones variadas, dispersas, así que para futuras referencias voy intentar dejar una guía más cerradita.
Sobre el problema y la solución
La idea es poder acceder a una pc que está detrás de un NAT, que puede conectarse con otra, pero las otras computadoras no pueden conectarse con ella. Entonces, la solución es establecer un canal de esa computadora a otra que si sea accesible y utilizar ese canal para conectarse a la computadora. (ese canal de comunicación es el “tunel”).
Para que esto se entienda mejor, vamos a ponerle nombre a los personajes: la computadora a la que quiero acceder pero está encerrada es “V”, la computadora a la que si se puede acceder y que funcionará como proxy es “C” y la computadora desde dónde me quiero conectar es “R”. Con esos nombres lo que hago es establecer una conexión SSH desde V hacia C, estableciendo un tunel reverso, dejo esa conexión establecida, luego me conecto desde R a un puerto particular en C que me permite a través del tunel hablar con V.
Los detalles
Para que esto funcione primero necesitamos habilitar algunas funciones
especiales en sshd
en Carlos, estas opciones nos van a permitir abrir el
tunel para que sea accesible desde Carlos y nos va a asegurar que la conexión
no se caiga.
# /etc/ssh/sshd_config (en el "proxy": C)
GatewayPorts clientspecified
ClientAliveInterval 20
ClientAliveCountMax 10
Y luego vamos a necesitar reiniciar el servicio sshd (sudo service sshd
restart
)
El segundo paso es habilitar una llave ssh para abrir este puerto, en V creamos
una clave usando ssh-keygen
sin contraseña y la dejamos por ejemplo en
~/.ssh/tunnel_rsa
.
Como la llave ssh que creamos no tiene contraseña, vamos a darle permisos muy limitados en C para lo cual vamos a utilizar una linea de autorización muy específica:
# ~/.ssh/authorized_keys (C)
restrict,port-forwarding,permitlisten="0.0.0.0:2232" ssh-rsa AAAAB3NzaC....A2KE= tunnel@V
En este caso, lo que hacemos es primero quitarle todos los permisos con
restrict
, luego habilitamos el port-forwarding
y lo restringimos al puerto
que queremos. En esta linea va a ser necesario copiar la llave pública que
creamos en el paso anterior.
Ahora viene la parte de establecer la conexión, y la mayoría de las opciones las vamos a escribir en el archivo config, dónde va a ser más legible.
# .ssh/config (V)
Host tunnel-c
HostName c.example.org
Port 2222
RemoteForward 0.0.0.0:2232 localhost:22
ExitOnForwardFailure yes
IdentitiesOnly yes
IdentityFile ~/.ssh/tunnel_rsa
ServerAliveCountMax 10
ServerAliveInterval 20
En los casos de HostName y Port va a ser necesario ajustarse a los detalles de
la conexión de V con C (que cómo premisa estaba funcionando). El RemoteForward
es el más difícil de leer, pero lo que establece es un tunel entre C:2232 y
V:22. Las opciones relativas a Identity
permiten que usen la llave que
generamos (sin contraseña) y por último otras opciones para asegurarse que la
conexión no se pierde.
El paso final es establecer la conexión y evitar que esta se caiga o que si se
cae vuelva a funcionar, para lo cual vamos a usar autossh
que está hecho para
eso:
autossh -f -M 0 -S none -N tunnel-c
Las opciones ahí son -f
para correr como proceso de fondo, -M 0
para dejar
que ServerAlive
y ClientAlive
sean los encargados de verificar que la
conexión está funcionando (si no autossh crea otras redirecciones, pero ya no
debería ser necesario), -S none
va a evitar que esta sesión SSH utilice una
conexión Maestra y finalmente -N
indica que no queremos una sesión
interactiva (que no va a funcionar porque es una credencial restringida).
Finalmente, desde R, podemos establecer la conexión con V utilizando la siguiente configuración:
# .ssh/config (R)
Host V-with-tunel
HostName c.example.org # el hostname de C
Port 2232 # el puerto dónde instalamos el tunel
Obviamente, vamos a necesitar credenciales autorizadas en V para acceder desde R, eso no cambia.
Espero que sirva, cualquier comentario no duden en contactarme.