SSH keys, multiple git deployment keys, one user

Introduction

I want the ability to do a git pull in any of my projects on a server, without attaching my git account or anyone else’s git account. Deployment keys makes this possible. You create a key pair, which is a public file and a private key.

Metaphor

Imagine that you have paranoid friends who don’t trust a face or voice, only a cryptographic “handshake” is sufficient. You create a key pair and share your public key with these friends. They will use this public key and generate a token each time they speak with you. You receive the token, decrypt it with your private key and send the decrypted token back. They’ll know it’s you since the matching private key is the only key that can decipher the token generated by the matching public file.

Practical

The private key sits on your server and is used each time we do a git pull. The public key is uploaded to the git server.

Optional step 0: Create a deployment user on the server

It’s recommended that you create a separate deployment-user on your server. Create this user before you proceed.

Step 1: Generate key pairs

ssh-keygen -t rsa -C "Deployment key for XYZ"

ssh-keygen generates the RSA key with descriptive Comment. Store it in ~/.ssh/XYZ_deployment_rsa. Repeat this for the next repo, ABC. ls ~/.ssh/ should have these four files, and a few other:

XYZ_deployment_rsa
XYZ_deployment_rsa.pub
ABC_deployment_rsa
ABC_deployment_rsa.pub

Submit these files to your git host. I’m using github.com, so I’ll visit my repo page > Settings > Deploy keys and past the content of the .pub file there.

Step 2: Edit ~/.ssh/config

~/.ssh/config is a handy file. If you use a custom SSH port (not 22) and an authentication key to your server, you’d use something like: ssh carl@hambro.me -p 39281 -i ~/.ssh/hambrome_rsa. These options are tedious and can be saved in the ~/.ssh/config file instead.

Host hambro
    HostName hambro.me
    Port 39281
    IdentityFile /Users/carl/.ssh/hambrome_rsa

Now, you’d use ssh hambro instead. Neat! Host hambro creates an alias of hambro which points to that block of options. We want to use such alias next time we do a git pull. It is tempting to put something like this into the file:

Host github.com
  HostName github.com
  IdentityFile /root/.ssh/XYZ_deployment_rsa
  IdentitiesOnly yes

But now we won’t be able to place our second repo, ABC, in another block, since the alias github.com is already taken! This is solved by not using github.com as the alias. You could use anything unique, but I’ll stick to XYZ-github.com and ABC-github.com. These “domains” won’t be resolved; they are only used as a lookup in our config-file. (They are resolved to github.com through the HostName option)

Host ZYZ-github.com
  HostName github.com
  IdentityFile /root/.ssh/XYZ_deployment_rsa
  IdentitiesOnly yes
  
Host ABC-github.com
  HostName github.com
  IdentityFile /root/.ssh/ABC_deployment_rsa
  IdentitiesOnly yes

Step 3: Set git upstream to use SSH

The final step is to clone your repo over SSH. However, we will replace github.com with XYZ-github.com and ABC-github.com. E.g.: git clone git@XYZ-github.com:hambro/my_xyz.git. You can change existing repo upstream if they’re cloned already: git remote set-url origin git@XYZ-github.com:hambro/my_xyz.git . You are now done!

If you did the optional step, all you have to do to pull is su deploymentuser -c "git pull".