Configure ssh with multiple deploy keys for multiple git repositories

Oct. 2, 2019


Recently I had to set up a server in which developers had access to multiple git repositories in their home directories. Here is how I went about it.

First and foremost, to access GitHub you must be authorized for private repositories. This could mean SSH keys, or authenticating with a username and password. I wanted to avoid the developers being prompted continuously, so I used keys. Also, since I can not take everyone's private key and just drop it in their home directories, I had to think of a different way to go about this. I could not use the developer's personal private key for a couple main reasons.

  1. Access to developer accounts is too open. I don’t want access to their personal GitHub accounts, and they don’t want me to have it either. Telling the developers to generate another key pair and to give me the private key and upload their public to github as an alternate account key pair was out of the question.
  2. Assuming it wasn’t an issue to use a key pair for a developer and their account, it would be an effort to get the private key from every developer and keep track of the file.

After a little research the best option emerged - using deploy keys! Deploy keys are SSH key pairs that apply to a single repository. Actually setting this up took a bit of time (it didn’t help getting conflicting sources of information online), but it is pretty simple. This gist here was by far the most helpful source.

There are three main steps.

Create the Deploy Key and Put it on GitHub

Everyone and their mother’s have likely created SSH keys before using this guide. Go ahead and generate an SSH key pair that can be used for the repository.

Navigate to GitHub repository > settings > Deploy Keys and click "Add Deploy Key".

screen capture

Paste in the public key in the text area labeled “key” and give the public key a descriptive title so you can recognize it in the future.

Now test your private key files ability to access the repository

ssh -i /path/to/.ssh/keyfile git@github.com

in my example:

(base) nick {~/.ssh}$ ssh -i haskell_ping-dk haskell_ping.github.com
PTY allocation request failed on channel 0
Hi nick-brady! You've successfully authenticated, but GitHub does not provide shell access.
Connection to github.com closed.

Note, only grant write access if needed (pushing code back up to origin). Also, put the private key (does not have the .pub extension) into the SSH directory of the user. I.e. ~/.ssh/.

Configure SSH config

The SSH config needs to be configured so that each repo is listed as separate host. Using subdomains of github.com can accomplish this. This is done so that when the SSH connections are started by git, that the config can use the correct file. I keep all of my private keys of the deploy keys in the ~.ssh directory with a naming convention to keep it organized - I.e. ${reponame}-dk. Where “-dk” signifies “deploy key”.

(base) nick {~/.ssh}$ cat config 
Host haskell-ping.github.com
User git
Hostname github.com
IdentityFile ~/.ssh/haskell_ping-dk
UserKnownHostsFile ~/.ssh/known_hosts

Host repo2.github.com
User git
Hostname github.com
IdentityFile ~/.ssh/repo2-dk
UserKnownHostsFile ~/.ssh/known_hosts

This file is configured for haskell-ping and another repository repo2.

My tree structure inside my user directory now looks like this:

.ssh/
├── authorized_keys
├── config
├── haskell_ping-dk
├── known_hosts
└── repo2-dk

Update git config

In order for the config file to actually do anything, we need to update our git config for each repository so that the connection, when created, will use the subdomain we configured in our SSH config file.

The file being updated is ${REPO_DIR}/.git/config.

Here is an example file for mine after being updated to work with the SSH config above.

[core]
    repositoryformatversion = 0
    filemode = true
    bare = false
    logallrefupdates = true
[remote "origin"]
    url = git@haskell-ping.github.com:nick-brady/haskell-ping.git
    fetch = +refs/heads/*:refs/remotes/origin/*
[branch "master"]
    remote = origin
    merge = refs/heads/master

You can edit this file manually, or by using the git command. I prefer to use the git cli to modify the file. You can do this with

git remote set-url origin git@{{ repository name }}.github.com:{{ repo name_space }}/{{ repository name }}.git

… which in my example for haskell-ping becomes

git remote set-url origin git@haskell-ping.github.com:nick-brady/haskell-ping.git

You should now be able to use the command line from each repository you have configured!

Comment Enter a new comment: