Handling multiple git SSH keys
Codemagic is the first CI/CD to make Apple M2 machines available to everyone (including the free tier!). This is a free upgrade from M1 machines with no price change.
I have for a long time fought a silent battle with my SSH configuration when trying to handle two different accounts with different SSH keys: one for work and one for my open source and personal contributions.
I have finally decided to stop and learn more about ssh config in order to find a good way to work effectively with both accounts. In this post, if you choose to keep reading after this enticing introduction 😅, I’ll go through the configuration that I have ended up with 👇.
Creating SSH keys
First thing I did was to start from scratch and remove all SSH keys I had. I then created two new ones: one for my work GitHub account and one for my personal one.
Note that, while I use GitHub, this example will work for any code hosting service you choose to use as the SSH config is for git rather than the specific services themselves.
To create the new keys I used the ssh-keygen
command from the terminal:
# Personal
ssh-keygen -t ed25519 -C "<my_personal_email>"
# Personal
ssh-keygen -t ed25519 -C "<my_work_email>"
When creating new keys, you need to choose a location where to store them. I would recommend using the default path suggested by
ssh-keygen
and append github username for the account the key is associated with to the file’s name (i.e.~/.ssh/id_ed25519_<git_username>
).
With both keys created, I then added them to the ssh-agent
like so:
# Add the private key (the one without the `.pub` suffix)
ssh-add <path_to_personal_key>
ssh-add <path_to_work_key>
Adding the key to the code hosting provider
Next step was to add the key to my account in my code hosting service (GitHub):
The SSH key settings can be found in the account’s settings.
To create the key in GitHub I needed to paste in its raw contents. I obtained these in string format by using pbcopy
on each of the public keys:
# This needs to be the public key (suffixed with `.pub`)
pbcopy < id_ed25519_<git_username>.pub
Note that this has to be done for each of the two accounts, and the right SSH key must be associated with its respective account in the code hosting service.
Creating an SSH config
Now that the keys were ready to be used, I then went on to create a SSH config from scratch (I wanted to fully understand how this process works, so I removed everything I had). To do so, I created a file called config
under the ~/.ssh
directory, which its sole purpose was to pick the correct key based on a git repository’s remote URL.
I then populated it with two different configurations, one for work and one for personal use:
# Personal Configuration
Host personal
HostName github.com
User git
IdentityFile ~/.ssh/id_ed25519_<personal_git_username>
# Work Configuration
Host work
HostName github.com
User git
IdentityFile ~/.ssh/id_ed25519_<work_git_username>
Let’s break the configuration above down to understand what it’s doing:
- The first thing is to specify a host with a given name, in this case it can be either
work
orpersonal
. - Host name will always be
github.com
, this means that whenever we use thework
orpersonal
hosts, they will always resolve togithub.com
. - Finally, we define which SSH key to use for each configuration.
That’s it! Last thing I needed to do at this point was to actually use this config and verify it all worked.
Using the new configurations
In order to determine which key a given repository would use, I needed to make some changes to my local repositories’ remote URLs (and any new ones I clone in the future). Since two new hosts have been defined, to use the right key, a repository must be cloned with one of those names defined in cofig (personal or work) as the host in its remote URL. For example, my new package ReadingTime
would now be cloned to use a personal key as follows:
git clone git@personal:polpielladev/reading-time.git
Or to use a work key, it can be cloned like so:
git clone git@work:polpielladev/reading-time.git
As I mentioned above, both these hosts will resolve to github.com
but the cool thing is that they will now use differnet SSH keys. 🎉
Before you go
Bear in mind that this is the way I like to work and it might not be the best way. My approach forces me to be very explicit whenever I set a remote and I am used to it. I can quickly see which key is being used by just inspecting the remote with the following command: git remote get-url origin --all
, which doesn’t require me to go digging into the config file when errors occur.
There are other approaches, such as setting specific repos or organisations as the hostnames so that you don’t have to remember to change the git clone command, so make sure you do some research and find the way that suits your workflow the most 😃.