Hoy en día, la práctica recomendada es usar las llaves SSH para manejar la autenticación y autorización de tus repositorios privados en Github, Gitlab o Sourcehut.

Cuando creamos nuestra llave SSH en realidad creamos dos partes criptográficamente unidas, usando lo que se conoce como criptografía asimétrica, criptografía de dos partes o criptografía de clave pública.

La llave privada por convención id_rsa ubicada en ~/.ssh/ se usa en el proceso de autenticación con cualquier servidor o servicio (Github/Gitlab/Sourcehut) que tenga conocimiento de tu llave pública id_rsa.pub. Esta clave/llave privada se usa para desencriptar un mensaje encriptado con tu llave pública y solo con esa llave se puede desencriptar y por lo tanto validar que eres tú el dueño. Es decir si no tienes la llave privada, la llave pública no sirve de nada. Además, si alguien más tiene tu llave privada se puede hacer pasar por ti, así que nunca la compartas.

Nunca compartas tu llave privada, ya que cualquier persona con acceso a ella va a tener acceso a todos los productos donde te conectas por tu llave pública.

git clone local con SSH

Cuando hacemos un git clone <remote-url> en nuestra maquina local, ssh junto a git  se encarga de autenticarnos y de poder acceder a nuestro repo remoto.

Por ejemplo, voy a clonar el siguiente repositorio privado en mi máquina local

git clone git@gitlab.com:we-make/prueba.git

Y, dado que tengo configurado en Gitlab mi llave pública, Gitlab me permite acceder al repositorio.

Cloning into 'prueba'...
remote: Enumerating objects: 358, done.
remote: Counting objects: 100% (358/358), done.
...
Resolving deltas: 100% (2443/2443), done.

Temporalmente voy a mover la llave privada de ~/.ssh/id_rsa para simular que no tengo la credenciales necesarias.

mv ~/.ssh/id_rsa ~/backup

N.B.: en Mac OS Catalina tenemos que hacer un restart para que se aplique este cambio dado que el método de reiniciar no me funcionó:

sudo launchctl unload /System/Library/LaunchDaemons/ssh.plist
sudo launchctl load /System/Library/LaunchDaemons/ssh.plist

Ahora ejecuto el mismo comando de git clone

$ git clone git@gitlab.com:we-make/prueba.git
git@gitlab.com: Permission denied (publickey).
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.

Como vemos me arroja un error de permission denied (publickey) básicamente me dice que no tengo la llave necesaria para acceder.

Si ponemos de vuelta la llave privada, todo vuelve a la normalidad.

mv ~/backup ~/.ssh/id_rsa

git clone en un servidor remoto

Entonces, ¿qué pasa cuando queremos hacer un clone en un servidor remoto? Si no tenemos la llave privada en el servidor entonces nos va a tirar el mismo error permission denied (publickey).

Podemos hacer tres cosas para solucionarlo. La primera es copiar la llave privada al servidor, y la segunda es crear una nueva llave privada en el servidor con ssh-keygen e incluirla en nuestra cuenta de Gitlab/Github/Sourcehut (deployment keys).

La primera opción no es recomendada dado que estarías otorgándole todos los accesos al servidor. La segunda opción es algo más compleja ya que si tienes varios servidores tendrías que hacer la misma operación varias veces.

La tercera opción, y en este caso lo que yo recomiendo, es usar lo que se llama Agent Forwarding. Lo que hace el Agent Forwarding es "copiar" la clave privada al agente de SSH.  Veamos como usarlo.

Usando SSH Agent Forwarding

El primer método para usar Agent Forwarding es usar el flag -A cuando se ejecuta el comando de ssh. Por ejemplo, si me quiero conectar al servidor example.com con el usuario demo usando Agent forwarding  el comando sería:

ssh -A demo@example.com

Luego, una vez dentro del servidor remoto puedo ejecutar el mismo comando git clone como si estuviera en la computadora local.

$ git clone git@gitlab.com:we-make/prueba.git
Cloning into 'prueba'...
remote: Enumerating objects: 358, done.
remote: Counting objects: 100% (358/358), done.
...
Resolving deltas: 100% (2443/2443), done.

De esta manera, podemos hacer también los otros comandos de git git pull o git push, por ejemplo.

El segundo método para usar Agent Forwarding es agregarlo a la configuración de SSH en ~/.ssh/config (si no tienen el archivo creen uno nuevo con el nombre). Podemos editarlo con el siguiente comando, o también pueden usar su editor de textos favorito:

vim ~/.ssh/config

En el archivo deberíamos incluir las siguientes líneas:

~/.ssh/config
...
Host example.com
   	ForwardAgent yes
...

De esta manera todas las conexiones con example.com tendrán -A activados por defecto.

⚠️ Advertencia Importante: ⚠️

Si piensas modificar el file anterior para usar Agent Forwarding con todos los hosts  (Host *) ten en cuenta que eso probablemente sea una mala idea. El problema es que estarás compartiendo tu llave privada con todos y cada uno de los servidores con los cuales te conectas. Obviamente no van a tener la llave privada en sí, pero si tendrán acceso ilimitado mientras estés conectado. Solo agrega esta opción a servidores que confíes y en los cuales necesites usar agent forwarding.

Conclusión

Como vemos, usar este método de Agent forwarding nos simplifica mucho nuestro proceso de despliegue a un servidor nuevo. Incluso Capistrano lo utiliza para los despliegues de aplicaciones en Ruby en Rails. Solo tenemos que tener en cuenta que hay que tener cuidado sobre el acceso que le estas otorgando al servidor remoto cuando permites el agent forwarding.

Fuentes y lecturas recomendadas