"Después del juego es antes del juego"
Sepp Herberger

lunes, 13 de octubre de 2014

Como entrar por ssh a un equipo que está detrás de un router.

Muchas veces queremos entrar por ssh a un equipo de casa o del trabajo y resulta que está detrás de un router, con el que nos damos de narices. Adicionalmente, el equipo tendrá una IP correspondiente a una IP privada de la red propia de nuestra instalación y no habrá posibilidad de conectar con él directamente.

Veremos ahora como solucionar esto con dos posibles escenarios:

1) Cuando tenemos la capacidad de configurar el router para que redirija las peticiones ssh hacia nuestro PC. Por ejemplo, el router ADSL de casa.

2) Cuando no podemos tocar el router, ya que está fuera de nuestro alcance y/o permisos. Por ejemplo, el router nuestro centro de trabajo o estudios.

Si nuestro caso es la unión de ambos, es decir, queremos acceder desde casa  (tras nuestro router ADSL) al trabajo (tras nuestro router corporativo), tendremos que llevar a cabo tanto los pasos del caso 1 como del caso 2.

1) Hacer ssh cuando podemos configurar el router.

Lo primero es tener servicio ssh instalado y funcionando correctamente según estas instrucciones:

El truco para saltar el router y llegar hasta nuestro PC está en configurar las reglas NAT del mismo para que redirija el tráfico ssh hacia el PC, que tendrá una IP fija dentro de nuestra red doméstica. Es lo que popularmente se conoce como "abrir puertos". Los detalles de esta configuración dependen mucho de la marca del router que tengamos en casa, pero Internet está llena de manuales sobre como abrir los puertos (normalmente los de bittorrent y amule) para cada router del mercado. Para adaptarlos a ssh simplemente hay que sustituir el puerto seleccionado al configurarlo por el puerto usado por nuestro servidor ssh (normalmente, el 22 o el 443, que es el que uso yo ya que muchos router corporativos tienen capado el puerto 22). Por ejemplo, para el famoso Livebox de Orange.

Otro problema que se nos presenta es ¿cuál es la IP del router de mi casa?. Normalmente será una IP dinámica que cambiará cada cierto tiempo o reinicio del mismo. Para soslayar ese problema existe NoIP, que te asocia un dominio gratuito del tipo nombre.noip.me a la dirección pública de tu router.

Una vez te has dado de alta (el servicio de NoIP se mantendrá gratuitamente para tí, siempre que una vez al mes lo reactives pulsando al enlace de activación en el recordatorio que te mandan por correo) y has elegido tu dominio (el sufijo siempre será noip.me si elegimos la opción gratuita) tienes que instalarte en tu PC el programa cliente disponible en la propia web de NoIP, que actualizará tu IP en el registro DNS de noip cada vez que te conectes. Si tienes un router ADSL lo suficientemente moderno (por ejemplo, el Livebox de Orange) el propio router tiene una opción en su interface de administración web para configurar esto sin necesidad de instalar nada en tu PC. Una vez dado de alta y configurado el ciente noip, instalado el servicio ssh y abierto el puerto pertinente del router, si haces:

ping dominio-de-mi-casa.noip.com

veras que tu router responde, y con:

ssh -p 443 usuario@dominio-de-mi-casa.noip.com

conectamos por ssh a nuestra máquina de casa (nótese que de ahora en adelante usaré siempre el puerto 443 para ssh).

NOTA: Esto anterior no funciona con router Livebox de Orange cuando lo hacemos dentro de la propia red doméstica. Por algún arcano motivo al enrutar el tráfico hace algún tipo de embrollo que no te permite conectar por ssh a tu IP pública. Yo lo que hago para probar es usar la conexión de datos del móvil y utilizar la apk de android Connectbot para ver si conecto por ssh desde fuera con el PC de casa.

2) Hacer ssh cuando no podemos configurar el router.

Ahora imaginemos que además queremos conectar al PC del trabajo por ssh de igual forma a como lo hemos hecho, en el paso anterior. Configuramos el servidor ssh, obtenemos la IP pública del router del trabajo, y.... ¿cómo abrimos los puertos del router?. Normalmente dicho router no lo controlamos nosotros ya que estamos dentro de una red corporativa y tenemos sus firewall en medio. Desde luego, si les pedimos a los encargados de la seguridad de la red que nos abran los puertos seguramente nos van a mandar a hacer puñetas.

¿Hay solución?. Si, hacer un "túnel inverso", en el que la conexión ssh va al revés: desde el destino al origen. Estrictamente hablando es el PC del trabajo el que te hace ssh a ti, y luego tú te "enganchas" a la conexión creada. Digamos que el PC del trabajo te "llama" por ssh a un sitio fijo (por ejemplo, el PC de casa), tu PC descuelga y ya tienes conexión ssh con él. Aquí viene bien explicado el proceso:

En resumen:

pc-trabajo # ssh -R -p 443  10101:localhost:22 usuario@dominio-de-mi-casa.noip.me -N   

esto conecta el PC del trabajo con el de casa, abriendo el túnel. Básicamente dice: "conéctate a dominio-de-mi-casa.noip.me por el puerto 443 y abre allí un túnel en el puerto 10101 y conéctalo con el puerto 22 de éste ordenador", ahí es nada. Al introducir esta orden nos pide la contraseña del usuario "usuario"  en el PC de casa y una vez metida se queda esperando a que se abra el otro extremo del túnel. En el PC de casa haremos:

pc-casa # ssh -p 10101 root@localhost  -C -X

y con eso conectamos con el PC del trabajo, ya que el puerto 10101 en el PC de casa es el extremo local del túnel abierto, estando en el otro extremo el puerto 22 del PC del trabajo con su demonio ssh esperando pacientemente tras él. Nos pide la contraseña de root allí (si ese es el usuario con el que queremos entrar) y una vez metida se inicia la sesión ssh.

Nótese como en el PC del trabajo asumo que el puerto donde está escuchando ssh es el 22, no 443 como en el PC de casa. Esto dependerá de nuestro caso particular.

Como hemos visto, cuando el PC del trabajo intenta conectar con el de casa para abrir el túnel inverso, nos pide la contraseña. Para evitar esto y hacer la llamada automática sin tener que teclear la contraseña cada vez, debemos establecer una relación de confianza entre el PC del trabajo y el PC de casa, de tal forma que se pueda hacer ssh de uno a otro sin que nos pida contraseña. Para ello, desde el PC del trabajo hacemos:

pc-trabajo # ssh-keygen
pc-trabajo # ssh-copy-id -p 443 usuario@dominio-de-mi-casa.noip.com

Esto genera Nos pedirá la contraseña una vez y ya está. Las próximas veces que hagamos:

pc-trabajo # ssh -p 443 usuario@dominio-de-mi-casa.noip.com

o

pc-trabajo # ssh -R -p 443 10101:localhost:22 usuario@dominio-de-mi-casa.noip.me -N   

desde el PC del trabajo se iniciará sesión en el de casa sin pedir contraseña.

El problema de este interesante método es que alguien debe estar en el otro extremo para iniciar la "llamada", o bien debemos ir primero al trabajo, abrir el túnel inverso y luego a casa, contestando la llamada y estableciendo la conexión ssh. Si no disponemos de un becario a tiempo completo en el PC del trabajo para avisarle por whatsapp de que inicie el túnel inverso, ¿cómo se puede automatizar esto para que la llamada se haga sola?. Pues si: con autossh.

Autossh permite crear un túnel ssh persistente: inicia una conexión inversa ssh y la mantiene contra viento y marea, reconectando de nuevo ante cualquier desconexión de la misma. Al caer la conexión, hay un pequeño intervalo de tiempo en la que no está activa hasta que autossh la reconecta, pero en general siempre que haya red entre los dos extremos estará funcional el túnel.

Primero instalamos el paquete autossh, luego y creamos un directorio llamado /etc/tunnel (esta ubicación es arbitraria, cada cual puede ponerlo donde quiera) para poner allí dos ficheros:

  • id_rsa: la clave privada ssh del usuario que abre el túnel en nuestro pc del trabajo (en mi caso, root). Esta clave privada está en /root/.ssh/id_rsa y debemos copiarla en /etc/tunnel y dejarla con permisos 600, para que sólo sea accesible por el root. Ojo con las claves privadas ssh.
  • tunnel.sh: el script que abre el túnel, que vemos a continuación:
#!/bin/bash
set +e
SSH_OPTIONS=" -i /etc/tunnel/id_rsa"
CREDENCIALES="usuario@dominio-de-mi-casa.noip.me"
PUERTO="443"
# Always assume initial connection will be successful
export AUTOSSH_GATETIME=0
# Disable echo service, relying on SSH exiting itself
export AUTOSSH_PORT=0
autossh -p $PUERTO -vv -- $SSH_OPTIONS -o 'ControlPath none' -R 10101:localhost:22 $CREDENCIALES -N > /var/user_sshlog.out 2> /var/user_ssh_error.out &   

Para conseguir que autossh se inicie al encender el PC lo invocamos añadiendo ésto rc.local, antes de la línea "exit 0":

/etc/tunnel/tunnel.sh > /var/user_tunnel.log 2>&1

Para que se ejecute el script y se establezca el túnel habría que reiniciar el PC del trabajo, aunque podemos lanzarlo manualmente mientras que hacemos pruebas.

Luego, desde el pc de casa entramos como ya hemos explicado:

pc-casa# ssh -p 10101 root@localhost  -C -X

MUY IMPORTANTE: con este método, el PC del trabajo debe estar siempre encendido y con el túnel inverso abierto, ofreciendo disponibilidad 24x7. Para que la conexión del túnel sea estable y no se produzcan timeout cuando lleva un tiempo sin usarse y para permitir conexiones X (para abrir aplicaciones gráficas remotas) hay que tocar un poco las configuraciones en el pc de casa:

En /etc/ssh/sshd_config añadir:

#Metido para las conexiones X
X11Forwarding yes
X11UseLocalhost yes
#Metido para el tunel inverso
ClientAliveInterval 30
ClientAliveCountMax 99999
GatewayPorts yes

Crear ~/.ssh/config (en el home del usuario al que conectamos, no en el usuario root) y añadir:

#Para el tunel inverso
Host *
Protocol 2
TCPKeepAlive yes
ServerAliveInterval 60
ForwardX11 Yes
ForwardX11Trusted yes

Por ultimo, reiniciamos el servicio ssh en el PC local.

pc-casa# service ssh restart

Pasado un tiempo (unos minutos a lo sumo) se iniciará el túnel desde el pc del trabajo y ya podremos entrar en él desde casa. Al final veremos la luz al final del túnel... y allí estará el demonio ssh.

10 comentarios:

  1. como puedo cerrar el puerto 10101 por favor ayuda

    ResponderEliminar
  2. En linux, usando iptables.
    http://elbauldelprogramador.com/20-ejemplos-de-iptables-para-sysadmins/
    http://www.cyberciti.biz/faq/iptables-block-port/

    ResponderEliminar
  3. Hola. Muy buena la explicación. La conexión la logro bien pero no logro hacer funcionar el script desde rc.local para un usuario distinto de root. Podrías indicarme a que se debe?

    ResponderEliminar
    Respuestas
    1. Hola, no entiendo que quieres hacer. ¿Conectar el túnel en uno de los dos extremos con un usuario no root....? Explica mejor tu caso...

      Eliminar
  4. Si Alfonso. Ya lo logré. Quería mantener la conexión con autossh pero con un usuario distinto de root. Así que tenía que indicarlo en el rc.local agregando esta linea:

    su pablo -c '/home/pablo/tunnel/tunnel.sh > /home/pablo/tunnel/logs/user_tunnel.log 2>&1'

    Despues lo demás es lo mismo que explicaste tan bien en este post. Abro desde la pc de mi casa un tunel (-R) hacia un servidor que tiene una ip fija y luego me conecto a mi casa a través de este último. Felicitaciones por el post.

    ResponderEliminar
    Respuestas
    1. Gracias, me alegro de que te haya servido. Un saludo.

      Eliminar
  5. Una duda y que pasa cuando los dos extremos estan detras de un NAT

    ResponderEliminar
    Respuestas
    1. Repasemos: hay dos extremos: uno en el que inicias la conexión (extremo A) o otro en el que la recibes (extremo B). Entiendo que el extremo A es tu casa o una red en la que tu tienes el control del router o firewall y puedes abrir los puertos y redirigirlos (como se haria con torrent o emule) hacia tu pc. En el extremo B está la red que tú no controlas (por ejemplo, tu trabajo o centro de estudios).

      Si no controlas el router/firewall del extremo A no puedes hacer nada de esto. En ese caso tendrías que usar una red intermedia que si controles para conectar ambos extremos, montando 2 saltos: del extremo A al pc intermedio y de dicho pc al extremo B. Demasiado complicado. Para esos casos mejor usar TeamViewer o similar.

      Eliminar