SSH-Agent forwarding: reenvío de autenticación

Publicado por Diego Córdoba en

Hoy aprenderemos a reenviar la autenticación desde ssh-agentlas solicitudes de gestión de claves provistos por ssh-agent, por medio de una conexión SSH utilizando ssh-agent forwarding.

Si no leyeron el artículo anterior, les recomiendo que le den una mirada ya que les va a facilitar el entendimiento de lo que sigue.

Anteriormente aprendimos a trabajar con ssh-agent y ssh-add para mejorar la gestión de claves. Vimos que podíamos utilizar un servicio independiente al de SSH para gestionar los privilegios del acceso a las claves privadas utilizadas para autenticarnos en una conexión remota.

Motivación de ssh-agent forwarding

Cuando utilizamos ssh-agent invocamos a un daemon de gestión de claves que nos permite acceder a las claves privadas necesarias para generar firmas digitales de autenticación, o Key challenges, que el cliente debe responder al servidor al que se intenta conectar.

Ahora bien, imaginemos que tenemos ssh-agent corriendo en nuestra computadora, establecemos una conexión SSH contra un servidor remoto, y en dentro de ese servidor, necesitamos conectarnos, mediante claves asimétricas SSH, a otro servidor.

Esto es muy común verlo cuando trabajamos con repositorios remotos Git autenticados mediante claves asimétricas. En este caso, si la clave de autenticación que vamos a usar en el repositorio está en nuestra computadora local, y la conexión al repositorio la hacemos desde el servidor remoto, podríamos, como respuesta simple copiar la clave privada local dentro del directorio ~/.ssh/ del servidor.

Esto tiene, a simple vista, dos problemas: la seguridad, y la facilidad de mantenimiento.

  • Seguridad: Las claves privadas son nuestra identidad de usuario en los servicios SSH. Con el tiempo las usamos para conectarnos a infinidad de servicios y consolas. Al copiarlas entre equipos estamos corriendo el riesgo de que se filtren, que por error queden en un directorio temporal y accesibles a alguien más… y eso puede perjudicarnos mucho.
    (Al final dejé algunos comentarios adicionales sobre seguridad).
  • Mantenimiento: Además de inseguro, también es difícil de mantener. Imaginemos que usamos las claves privadas en vario servicios, y que éstas se encuentran copiadas a su vez en varios equipos. Si por alguna razón se compromete la clave, debemos generar una nueva clave y copiarla reemplazando a la anterior en todos los sitios.

Funcionamiento de ssh-agent forwarding

Aquí es donde se ve la ventaja del reenvío de ssh-agent en nuestras conexiones.

Como hemos visto en el artículo de ssh-agent, al establecer una conexión, el servidor le envía al cliente una solicitud de Key Challenge, y el cliente ssh local pide la respuesta al proceso ssh-agent. Éste genera la respuesta utilizando nuestra clave privada. Esto se ve en la siguiente imagen (rescatada de artículo anterior).

ssh-agent forwarding ssh local

Cuando ingresamos a un servidor SSH remoto, y desde el mismo necesitamos acceder a las claves de nuestra computadora local, el reenvío o forward permite que el cliente ssh remoto solicite la firma digital, o Key Challenge, al ssh-agent local de nuestra computadora, por medio del túnel previamente establecido.

Se esta manera, no será necesario copiar las claves privadas desde el cliente en el primer servidor, sino que podemos reenviar la solicitud de Key Challenge hacia nuestro equipo local, que tiene las claves privadas en el directorio ~/.ssh/.

La siguiente imagen muestra los pasos necesarios para realizar el establecimiento del segundo túnel reenviando las consultas de Key Challenge al ssh-agent local. Se considera que el primer túnel SSH ya se encuentra establecido, y se detallan los mensajes necesarios para realizar la segunda conexión SSH.

(Espero que se entienda, que está complicado de dibujar XD)

  1. El SSH Client remoto (verde en la imagen) envía, desde el servidor hacia el segundo servidor, la solicitud de conexión.
  2. El segundo servidor le solicita al SSH Client remoto el Key Challenge.
  3. El SSH Client remoto solicita al servidor SSH, que ha establecido previamente el primer túnel, la respuesta del Key Challenge.
  4. El dicho servidor reenvía dicha solicitud hacia el SSH Client original, por medio del túnel previamente establecido.
  5. El SSH client original solicita al ssh-agent la respuesta del Key Challenge.
  6. El ssh-agent recupera la clave privada para generar la respuesta.
  7. El ssh-agent genera la respuesta al Key Challenge y la envía al SSH Cliente que la solicitó.
  8. El SSH Cliente la recibe y se la envía al servidor remoto.
  9. El servidor SSH recibe la respuesta y se la comparte al SSH Client remoto que la solicitó inicialmente.
  10. El SSH Client remoto envía dicha respuesta al segundo servidor SSH, cumpliendo su requisito.
  11. El segundo servidor SSH valida la respuesta y establece el segundo túnel SSH.
ssh-agent forwarding ssh

Caso práctico del reenvío de ssh-agent

Veamos un ejemplo práctico del uso de ssh-agent forwarding. En mi computadora tengo mi clave privada para conectarme a un servidor SSH remoto, y es la misma clave que utilizo para autenticarme en mi cuenta de GitLab (a modo de «segundo servidor SSH«).

Como no quiero copiar mi clave privada desde mi cliente a mi servidor SSH, voy a reenviar las solicitudes de Key Challenge hacia mi ssh-agent local.

Antes que nada, un pequeño GIF que da cuenta de que, sin estas configuraciones, la verificación de SSH falla. Aquí me conecto a mi servidor SSH y, desde ahí, intento a verificar sin éxito la autenticación en GitLab vía SSH.

Ahora lo que sí funciona 🙂

Primer paso debemos configurar cliente de ssh para el reenvío de la autenticación en la primera conexión SSH. Esto podemos hacerlo configurando nuestro cliente ssh local. En mi caso, edité el archivo ~/.ssh/config añadiendo estas líneas:

Host enerious
	HostName 192.168.0.150
	ForwardAgent yes

Esto habilita la conexión contra mi servidor enerious y el reenvío de solicitudes de Key Challenge.

En mi caso ya tengo las claves privadas cargadas en ssh-add (lo hice como vimos acá). Básicamente, tengo dos claves, la primera, necesaria para mi autenticación en GitLab, y la segunda, para mi autenticación contra el servidor. Esto es un caso particular, podrían tener la misma clave para todo.

diego@cryptos ~ $ ssh-add -l
2048 SHA256:K1qQ4JjkG17W6lfo8zbFAGbcf9HE/cNIaJ2O+uWi4wE /home/diego/.ssh/id_rsa (RSA)
3072 SHA256:rYFGrBg2fWYb2LuiTWx1Vrxf+fTEFTkdXYQNifvJpDc diego@cryptos (RSA)

Paso siguiente, establecer la conexión contra mi servidor SSH. Aquí usaremos el modificador -A de ssh para reenviar la autenticación:

diego@cryptos ~ $ ssh -A user@192.168.0.150
user@enerious:~$ 

Finalmente, podemos verificar si la autenticación contra el servidor SSH de GitLab exitosamente:

user@enerious:~$ ssh -T git@gitlab.com
Welcome to GitLab, @d1cor!

La respuesta habla por si sola. El servidor SSH de GitLab pudo autenticarme utilizando la clave privada que tengo en mi computadora local.

Ahora, un GIF que muestra estos cambios funcionando:

ssh-agent forwarding successfully ssh

Esto, por supuesto, se da porque ya tengo previamente configurado mi acceso por SSH en mi cuenta de GitLab.

Una nota sobre seguridad

Anteriormente dijimos que usar ssh-agent forwarding era más seguro que copiar indiscriminadamente las claves privadas de un host a otro.

No obstante, debo aclarar que si, si bien esto es cierto, si el único objetivo de conectarse a un servidor es establecer una conexión contra un segundo servidor, probablemente sea más conveniente usar al servidor intermedio como host de salto (jump host).

En pocas palabras, un jump host nos permite conectarnos a un servidor en Internet utilizando a otro servidor como salto intermedio. Esto se logra usando la opción -J del cliente ssh.

Igualmente, lo dejo como inquietud, ya que excede los alcances de este artículo, así que seguramente publique algo en un futuro cercano 🙂

Conclusiones: ssh-agent forwarding

Hemos visto cómo reenviar la configuración de ssh-agent desde un cliente a un servidor para que, cuando se establecen conexiones remotas desde dicho servidor, se consulte por autenticación al ssh-agent de nuestro equipo local.

Esto evitó la copia de claves privadas entre equipos, mejorando la seguridad de los enlaces, y facilitando la administración de claves.

Así como en mi ejemplo, dentro del servidor verifiqué mi autenticación contra GitLab, bien podría haber conectado a otro servidor, siempre y cuando la clave necesaria se encuentre cargada en el ssh-agent de mi computadora local.

Finalmente, les comento que me quedan todavía varias ideas en el tintero para próximos artículos (sí, SSH es mi protocolo favorito, y es interminable :-)). Entre ellas, además del uso de jump hosts, les quiero comentar sobre el intercambio SSH completo, capturas de tráfico incluidas, y, por supuesto, grabaré este contenido para añadirlo al curso de Experto en SSH que tengo publicado en Udemy.

Les dejo también una lectura interesante sobre el funcionamiento de ssh-agent, con grafiquitos más bonitos que los míos seguramente.

Como siempre, espero que el contenido les guste y les resulte interesante! Quedo a disposición ante cualquier comentario.

¡Será hasta la próxima!


¿Preguntas? ¿Comentarios?

Si tenés dudas, o querés dejarnos tus comentarios y consultas, sumate al grupo de Telegram de la comunidad JuncoTIC!
¡Te esperamos!


Diego Córdoba

- Ingeniero en Informática - Mg. Teleinformática - Tesis pendiente - Docente universitario - Investigador