Anyone working on multiple repositories from multiple clients developer will adopt the pattern of using a single Private Key shared between project to facilitate the workflow.
The problem with that approach is: Once your private key gets leaked every single repository you had associed with is now compromised.
To avoid that I prefer to use different keys to different groups of repositories.
The easiest way to start working with multiple
keys is make use of .ssh/config file.
This file let us create a set of configurations based on domain used by git.
Let's assume you have two repos:
git@github.com:acmegroup/repo-1.git
git@github.com:johndoe/repo-2.git:
To avoid any chances of editing the wrong "repo-X" We will organize them in sub-folders:
/home/johndoe
├── Projects
│ ├── acme
│ └── personal
and here's our .ssh/ folder:
/home/johndoe/.ssh
id_ed25519
id_ed25519.pub
id_ed25519_acme
id_ed25519_acme.pub
Where id_ed25519 is our Secret Key for personal
projects.
Now we will clone our private repo on the personal folder:
cd ~/Projects/personal
git clone git@github.com:johndoe/repo-2.git
That will work just fine, resulting in:
/home/johndoe
├── Projects
│ ├── acme
│ └── personal
│ └── repo-2
but if you try the same for the repo-1 it will not work.
cd ~/Projects/acme;
git clone git@github.com:acmegroup/repo-1.git
It will fail because git will try to use the
same key for the personal repos.
We can represent the git clone as:
FROM git@github.com CLONE acmegroup/repo-1 WITH ~/.ssh/id_ed25519
So how can we tell
git(ssh) to use a different key?
We edit the .ssh/config file and tell ssh to
use a certain key when trying to reach certain
host domain:
# ~/.ssh/config
Host github.com
IdentityFile ~/.ssh/id_ed25519_acme
then we re-execute:
cd ~/Projects/acme;
git clone git@github.com:acmegroup/repo-1.git
resulting in:
/home/johndoe
├── Projects
│ ├── acme
│ └── repo-1
│ └── personal
│ └── repo-2
All done! Right? Not quite, but we are halfway there.
Even though our previous git clone for ACME's
repo-1 will worked now any other operations
(push, fetch, etc) for our personal's repo-2 will
fail.
How do we fix the personal repository operation?
Simple. Instead of using github.com we will use
a custom (alias) domain when cloning our
non-personal repositories. For example:
We will use github_acme.com (alias) domain when
cloning our ACME's repo-1.
cd ~/Projects/acme;
git clone git@github_acme.com:acmegroup/repo-1.git
Of course the new (alias) domain does not exist
in the real WWW and cloning will fail. That is
because we need one last step: Update the .ssh/config
file to handle the "alias" domain.
Host github_acme.com
IdentityFile ~/.ssh/id_ed25519_acme
HostName github.com
This will tell ssh to do two things
before when we try to clone from the custom
github_acme.com:
replace the original domain github_acme.com
with github.com
use the /home/johndoe/.ssh/id_ed25519_acme as
the private key for the request.
We can represent that as something like:
IF host == github_acme.com THEN
FROM git@github.com CLONE <some-repo> WITH ~/.ssh/id_ed25519_acme
ELSE
FROM git@github.com CLONE <some-repo> WITH ~/.ssh/id_ed25519
END
At this point you're all set to start working with even more Secrets Keys per repository.
As long as you remember to always adjust
your git repo's domain to match the configuration
from .ssh/config
At some point the motions required to adjust your git repo's domain will get old. Believe me.
The endgame here is to:
keep ssh being able to select the correct
secret key
stop having to rewrite our git domain
To do so we will create a .gitconfig_acme to
change the git domain (github.com) to the
"alias" domain we use on .ssh/config: github_acme.com
# ~/.gitconfig_acme
[url "git@github_acme.com"]
insteadOf = git@github.com
And we want to do that only for git operations
from our ~/Projects/acme folder. That is
achieved by editting the ~/.gitconfig (no suffix)
# ~/.gitconfig
[includeIf "gitdir:~/Projects/acme/"]
path = .gitconfig_acme
So now everytime we do:
cd ~/Projects/acme;
git clone git@github.com:acmegroup/repo-1.git
The following logic will be executed:
GIT {
IF current_path == ~/Projects/acme THEN
host = github_acme.com
END
}
SSH {
IF host == github_acme.com THEN
FROM git@github.com CLONE <some-repo> WITH ~/.ssh/id_ed25519_acme
ELSE
FROM git@github.com CLONE <some-repo> WITH ~/.ssh/id_ed25519
END
}
We added two extra steps of rewriting our initial request but in exchange we finally achieve and smooth git workflow working with multiple secret keys.