Using SSH with multiple identities / certificates
A while back,I decided to start using SSH for all my GIT repos. However, being a consultant, I end up being involved in a lot of different repos, for a lot of different customers. And on top of that, I sometimes write code on my spare time as well. This causes a bit of a problem when it comes to SSH. So I decided to write a a post about how you solve it. It might be obvious to a lot of people, but it might also help someone with the same problem. If nothing else, it will help me when I forget in the future…
The problem
The problem is that, by default, the SSH agent will use a single certificate for all authentication. This is fine, if you only have one identity. For example, if you only have one GitHub account, you are good to go with just one certificate. Just give GitHub the public key, and it knows that whenever it sees someone using that key, it is you. And whenever you try to use SSH with GitHub, the SSH agent will use that certificate, and all is fine.
However, if you need to have multiple GitHub accounts, or multiple identities in general, it becomes a bit more problematic. You can only register a public key with a single account, which is kind of expected as the key is supposed to identify that you are you. However, if you have 2 accounts, you have 2 different identities, and you are actually 2 different “yous”. This requires us to use 2 different keys.
So how do we solve that?
The solution
Well, the first step is to create a new set of keys to use with our second identity. This is fairly easy to do by running
ssh-keygen -t rsa -b 4096 -f ~/.ssh/id_rsa_myOtherAccount
This will generate a new 4096 bit, RSA-based set of keys with the private key in the file id_rsa_myOtherAccount, and the public in id_rsa_myOtherAccount.pub.
Note: If you are using PowerShell on Windows, ~/
doesn’t actually work. Instead you have to use the full path, which is c:\Users\<USERNAME>\.ssh
. So, for the above example it would be c:\Users\<USERNAME>\.ssh\id_rsa_myOtherAccount
. However, if you write ~/.ssh
and press TAB
, PowerShell will add the path automatically for you.
Note: You can place your keys wherever you want, but ~/.ssh
is the standard location.
The ssh-keygen
command will ask for an “optional” passphrase. And I place optional in quotes here, because even if it is technically optional, I don’t think it should ever be left empty. You should definitely add a passphrase, and make it a good one! This is used for authentication, it needs to be secure!
Once you have input your passphrase twice, you will see something like this
The key fingerprint is:
SHA256:A5rYe8Sjz92GZ893FDwbpLUs9gAv9BYn8qqLSoYSV28 <USERNAME>@<COMPUTER_NAME>
The keys randomart image is:
+---[RSA 4096]----+
| |
| + o + |
| .. . * X .|
| o.+.. . X B |
| ...+ +ES = + =|
| o .+.. . . o.|
| . .oo. .. . |
| . o+ .oo+. . .|
| .+..=o.o. . |
+----[SHA256]-----+
Ok, so now we have 2 sets of keys that we can use. The default id_rsa
and the newly generated id_rsa_myOtherAccount
, as well as the corresponding public keys.
With the new key pair in place, we can go ahead and add the newly created public key to our second GitHub account (or wherever you need your second identity).
Once your service of choice knows your public key, we need to add the corresponding private key to the the SSH agent. And then we need to tell the agent, that it should use that new key in some scenarios. Let’s do it one step at a time
To add the new key to the SSH agent, we can run
ssh-add ~/.ssh/id_rsa_myOtherAccount
Note: Once again, PowerShell does not support ~/
and needs the full path…
This will register the new key with the SSH agent. However, it will still default to using the default one when asked to provide a key. So we need to configure it to use the new key in some cases. This is done by creating a file called config
at ~/.ssh/
. On Windows, this could be done by running
notepad c:\Users\<USERNAME>\.ssh\config
In this file, we can tell the SSH agent how to behave when it sees certain hosts. So for example, I could add
Host git-myOtherAccount
HostName git.com
User git
IdentityFile c:/Users/<USERNAME>/.ssh/id_rsa_myOtherAccount
IdentitiesOnly yes
This tells the SSH agent that whenever I try to talk to the host git-myOtherAccount
, it should open a connection to git.com
, using the username git
and the key from c:/Users/<USERNAME>/.ssh/id_rsa_myOtherAccount
.
Wait, what? The host git-myOtherAccount
? Yes, the host entry in this configuration is basically any string that you want. It will then be replaced by whatever is set in the HostName
field whenever you try to open an SSH connection to that host.
The next thing we need to do, is to make sure that we replace the host for SSH connection we want to make. In the case of GitHub, that means changing the address for any repo that we want to clone using this new key.
For example, say that you have a repo with an address of git@github.com:ChrisKlug/K8S4DEVS.git
. If we use this address, the SSH agent will look at the ~/.ssh/config
file to see if there is any Host
with the value github.com
. If doesn’t find one, it will just use the default key (id_rsa).
However, if it finds an entry with the same value, it will replace the host name with the value in the HostName
field, and use the key configured for this host instead.
Armed with this bit of knowledge, we can update the GitHub address we got to the repo, and turn it into git@git-myOtherAccount:ChrisKlug/K8S4DEVS.git
. As you can see, I just replaced github.com
with git-myOtherAccount
. The SSH agent will now find an entry in the config that corresponds to that. It will then automatically replace the host with github.com
(as configured), and use the configured key instead. E.g. git@git-myOtherAccount:ChrisKlug/K8S4DEVS.git
is turned back into git@github.com:ChrisKlug/K8S4DEVS.git
, but the id_rsa_myOtherAccount
key is used instead of the default one.
Note: You can use any host you want to. As mentioned before, it is just a string that is used to find the correct configuration.
Some extra comments
I had some extra thoughts and comments that might be useful, so I thought I would throw them in here as well…
SSH on Windows
WIndows 10 comes with an SSH agent built in. So there is no need to run third party tools like PuTTy anymore. Instead, you just need to turn on the built in agent. This is done by doing the following.
First, open the “Manage Optional Features” window and search for “OpenSSH Client”.
If you can’t find it, it needs to be installed by clicking on “Add a feature”. In the window that opens, search for “OpenSSH Client” and install it.
Next, open the “Services” window and look for the “OpenSSH Authentication Agent” service. Make sure that it is set to start up automatically, and that it is running.
Once we know that the agent is running, we need to make sure that it is the default agent being used by the system. Git for Windows includes a bunch of extras, including an SSH set up that used to make it easier to work with on previous versions of Windows. Today, this isn’t needed as Windows 10 has pretty much all of it built in.
So, to make sure that we are actually using the Windows 10 built-in agent, open up a terminal window (cmd.exe for example) and run
where ssh
This should tell you that the SSH executable is located at C:\Windows\System32\OpenSSH\ssh.exe.
Note: If it isn’t, have a look at your PATH variable to find out what path is causing it to end up at the wrong place. Once you have found it, either remove that path, or make sure you move it down so that the C:\Windows\System32 is placed before the one that causes the problem.
Once we know that the right SSH executable is being used, we should also also tell Git to use that same executable instead. This can be done by either creating a new environment variable called GIT_SSH with the value C:\Windows\System32\OpenSSH\ssh.exe. Or by setting up a Git configuration variable called core.sshCommand. Like this
git config --global core.sshCommand "'C:\Windows\System32\OpenSSH\ssh.exe'"
That should be it! Your computer should now have a running SSH agent for you to use. You just need to add your keys and make sure you use the SSH endpoint for your Git repos!
Updating the Git information
If you are using multiple identities for your repos, it is also very likely that you want to use different user information when interacting with them as well.
By default, Git uses the globally configured name and e-mail address. However, if you have for example a private account and a work account, you probably want your commits to reflect which one you are actually using. The SSH part will only do the authentication, the commits are still created and tagged by Git.
So to update your user information for a single repo, just run
git config user.name "<YOUR NAME>"
git config user.email "<YOUR EMAIL ADDRESS>"
This will make a local change for this particular repo only, which makes sure that any commits you add to this repo are added with the correct information.
Updating existing Git repos
If you already have existing Git repos and you want to change to SSH, you just need to update the URL for the origin. This is done by executing
git remote set-url origin git@<HOST>:<username>/<repo>
Note: Remember that the HOST can be either a real host, or a made up one from the SSH configuration
Managing SSH keys
Once in a while, you might want to see what keys are currently registered with the SSH agent. This is easily done by running
ssh-add -l
And if you want to remove a key, just run
ssh-add -d <PATH TO KEY>
And finally, a tiny little warning…
A little config warning
If you happen to create a config that looks something like this
Host GitHubPrivate
HostName github.com
User git
IdentityFile c:/Users/chris/.ssh/id_rsa_private
IdentitiesOnly yes
Host github.com
HostName github.com
User git
IdentityFile c:/Users/chris/.ssh/id_rsa_github
IdentitiesOnly yes
and then try to clone a repo using for example git@GitHubPrivate:ChrisKlug/K8S4DEVS.git
. The SSH agent will use id_rsa_github
instead of the (probably) intended id_rsa_private
.
Why? Well, here is why!
First the agent will find the GitHubPrivate
configuration, and replace the host name with github.com
and use the id_rsa_private
key. However, after changing the host to github.com
, it will keep going through the configuration and find another entry for the github.com
host. This new entry says that it should use id_rsa_github
. So the agent changes the key to be id_rsa_github
. So in the end, you end up with github.com
and id_rsa_github
, which is probably not the intended result.
To solve it, make sure you don’t override changed hosts further down the list of configurations.
That’s it for now I think. Being able to use multiple keys/identities is really useful in a lot of scenarios. But for me, it is always a pain to remember exactly how to configure it. Thus this post. I hope the information in it was useful for you as well!