3 min read

Managing multiple SSH keys

Syed Aslam

Though it is generally the case and is considered a good practice to have only one public-private key pair per device, sometimes you end up using more than one key. Like, for example, you might use one SSH key pair for your personal projects and you might use a different key for accessing your corporates' private repositories. On top of that, you might be using a different key for accessing a client's server.

Managing SSH keys can become cumbersome as soon as you need to use a second key. Traditionally, you would use ssh-add to add your keys to ssh-agent, typing in the password for each key if required. The problem is that you would need to do this every time you restart your computer since ssh-agent will restart and you will have to add and type in the password for each key all over again.

The solution is to automate adding keys, store keys, and to specify which key to use when accessing certain servers by creating a configuration file specifying our customizations for SSH to use automatically.

SSH Config

SSH Config is a per-user configuration file for SSH communication. Create a new file typically stored at ~/.ssh/config. Since this config file is new, you might need to do chmod 600 ~/.ssh/config.

On Linux and macOS, verify that the permissions on your IdentityFile are 400. SSH will reject, in a not explicit manner, SSH keys that are too readable. It will just look like a credential rejection. The solution, in this case, is:

  chmod 400 ~/.ssh/id_rsa

Anyways, the first thing to solve using this config is to avoid having to add custom-named SSH keys using ssh-add. Assuming your private key is named ~/.ssh/id_rsa, add the following to the config file:

Host github.com
  HostName github.com
  User git # GitHub username
  IdentityFile ~/.ssh/id_rsa
  IdentitiesOnly yes
  AddKeysToAgent yes

It is important that the base URI of Host github.com in config and the base URI of the repository that you want to clone and work with match. But, it is also possible to have a custom hostname:

Host github-personal
  HostName github.com
  User github-personal-user # GitHub username
  IdentityFile ~/.ssh/id_rsa
  IdentitiesOnly yes
  AddKeysToAgent yes

With this setting now you can say git clone git@github-personal:github-account/interesting-project.git. If you had already cloned the repository, you can change the remote url, if you want, by:

  git remote set-url origin git@github-personal:github-account/interesting-project.git git@github.com:some-github-user/interesting-project.git

Next, to add another account do:

Host github-corporate
  HostName github.com
  User github-corporate-user # GitHub username
  IdentityFile ~/.ssh/id_ed25519
  AddKeysToAgent yes
  IdentitiesOnly yes

The Ed25519 was introduced on OpenSSH version 6.5 and is now the recommended way to generate ssh key pair. This is EdDSA implementation using the Twisted Edwards curve. It uses elliptic curve cryptography that offers better security with faster performance compared to DSA or ECDSA. Today, the RSA is the most widely used public-key algorithm for SSH keys. But compared to Ed25519, it's slower and even considered not safe if it's generated with a key smaller than 2048-bit length.

The Ed25519 public-key is compact, contains 68 characters compared to RSA 3072 that has 544 characters. Generating the key is also almost as fast as the signing process. It's also fast to perform batch signature verification with Ed25519. It is built to be collision resilience. Hash-function collision won't break the system.

  $ ssh-keygen -t ed25519 -C "your_email@example.com"

This creates a new ssh key, using the provided email as a label. If your system doesn't support the Ed25519 algorithm, use:

  ssh-keygen -t rsa -b 4096 -C "your_email@example.com"

Getting back to the task in hand, now you can use git clone git@github-corporate:company/project.git.

Per repository settings

It turns out you can also define repository-specific keys overriding the configuration in ~/.ssh/config file. There are, at least, two ways to do this.

One, using the GIT_SSH_COMMAND. From Git version 2.3.0, you can use the environment variable GIT_SSH_COMMAND like this:

  GIT_SSH_COMMAND="ssh -i ~/.ssh/id_rsa" git clone git@github-corporate:company/project.git

Note that -i can sometimes be overridden by your config file, in which case, you should give SSH an empty config file, like this:

  GIT_SSH_COMMAND="ssh -i ~/.ssh/id_rsa -F /dev/null" git clone git@github-corporate:company/project.git

Second, via core.sshCommand. From Git version 2.10.0, you can configure this per repo or globally, so you don't have to set the environment variable any more!

  git config core.sshCommand "ssh -i ~/.ssh/id_rsa -F /dev/null"
  git pull
  git push