If you don't care about why or how this works, you can skip right down to Setup Steps
These are the considerations I tried to satisfy while researching this solution:
- I prefer not to generate new SSH keys for every machine/VM/environment where I use git or SSH. I end up with tons of keys per GitHub account or remote server, and I don't remember which is which.
- I want to keep private keys secured somewhere that is not directly accessible on the filesystem. Also try to avoid copying private keys around at all costs.
- I like the idea of having finer grained control over which applications are using the SSH keys per instance.
- I need to be able to use multiple GitHub accounts on the same instance without too much fuss.
After researching for quite a bit, I found that 1Password satisfied the top three requrements without having to carry around a hardware security key.
The most common solution I saw for point four is to edit your SSH config to give different names to the hosts associated with each of the accounts. I'm not a fan of this for a couple reasons:
- I don't like having to remember to set the remote url for all the repos for different credentials. I'll forget and it's kind of a pain to remember when cloning.
- When using the 1Password SSH agent in WSL, the WSL SSH config file isn't used, so this really isn't an option. You could set this all up in the Windows SSH config, but see point 1.
My approach here is to use git config includes to make additional gitconfig files per 'account-directory' that specify exactly the keys (and account information) I want to use for the repos inside. I do this by overriding the SSH command to include the specific puclic key to use for that account - no ssh-agent retries or host configuration needed!
The only caveat is all repos associated with a GitHub account must live under a common parent directory, and not anywhere else on the filesystem.
In my case I have a folder structure like this:
~/src/
/work/
/work_repo1/
/work_repo2/
…
/personal/
/personal_repo1/
/personal_repo2/
…
The example above only shows two accounts, but technically there shouldn't be a limit to the amount of accounts you can use with this method. Since we're explicitly defining the key for each account (and assuming everything is configured correctly) you don't need to worry about the SSH server six key limit, since we'll be getting it right on the first try
When using the 1Password SSH agent you only need to export the public keys for each account to your filesystem, the private keys stay safe in the vault! The 1Password SSH agent will associate the public key to the correct private key in the vault at each time of use, so the private keys never need to leave your vault and aren't exposed.
The approach up until this point is system agnostic. With this, you can have multiple GitHub accounts with separate SSH keys on any system (MacOS, Linux, Windows, etc..) There is just a bit of extra setup needed when implementing this on WSL
We need this extra step because the 1Password SSH agent isn't actually running under WSL at all. We use the host machine's Windows SSH tools for all SSH functionality. The additional setup is simply to alias your SSH commands to use the Windows ssh.exe (and optionally alias the op.exe if you want to use the CLI in WSL)
- Make sure 1Password is installed, and you have your SSH keys created for any accounts you want to use.
- Note: If your SSH keys will exist in a vault other than the default vaults, see the Vaults note below.
- Enable the 1Password SSH agent, and make sure the OpenSSH Authentication Agent is disabled
- Optionally, install the 1Password CLI and enable it in the 1Password app.
- In WSL run
ssh.exe -V
and make sure you get the OpenSSH_for_windows version.- If not you'll need to make sure WSL is set up to run windows tools from linux
- If using the CLI check that
op.exe --version
works as well
- In WSL:
- If using the CLI run
op.exe read 'op://<VAULT>/<personal_key_name>/public key' > ~/.ssh/<personal_key_name>.pub
- If not, just export your key and copy it to you WSL filesystem in the
~/.ssh/
directory. - Repeat this step for all keys you want to use in WSL.
-
Inside each directory that will contain repos from a GitHub account, create a new .gitconfig which defines the SSH command and key to use. So for a
~/src/personal/
directory create a~/src/personal/.gitconfig
file that contains[user] email = <personal_GitHub_email> name = <personal_GitHub_name> [core] sshCommand = ssh.exe -i /home/<WSL_user>/.ssh/<personal_key_name>.pub
* Note: on systems other than WSL, simply replace
ssh.exe
with the SSH utility for that system, and keep the rest -
Tell your main gitconfig to include this new gitconfig. In your
~/.gitconfig
file add the following for the account-directory[includeIf "gitdir:~/src/personal/"] path = ~/src/personal/.gitconfig
-
I'd also recommend taking any account-specific information out of your main
~/.gitconfig
file so if a repo ends up in a different directory, you'll be prompted for account information and know you need to update your configuration. -
Any settings in the main gitconfig will carryover if they're not defined in the account-directory gitconfigs.
-
When you're done you should have a folder structure similar this:
~/ .gitconfig /src/ /work/ .gitconfig /work_repo1/ /work_repo2/ … /personal/ .gitconfig /personal_repo1/ /personal_repo2/ …
-
Everything in git should work as normal!
-
When you pull/push/clone or do anything else that requires authentication, the Windows 1Password SSH agent will prompt you for authentication for the associated keys, and you can just authenticate in 1Password the way you normally do!
If you want commit signing for an account-directory, just follow the regular 1Password commit signing instructions for WSL, and make sure you put the signing information into the gitconfig for the associated account-directory (not the main ~/.gitconfig
.)
- Make sure your GitHub account is configured with a signing key. If you use the same key for authentication and signing you should be fine. If you have separate keys for authentication and signing, you'll need to do step 3 for your signing key as well. Then follow the 1Password commit signing instructions for WSL with your signing key.
By default, the 1Password SSH agent will only include SSH keys that are stored in your default vaults (i.e. Personal, Private, or Employee Vault). If you move any SSH keys to a vault other than these three, you will need to explicity tell the SSH agent to include keys in that vault. This can be done by creating/editing the 1Password SSH agent config file.
I've only tested VSCode in WSL, but since we've configured the identities at the git and SSH level, any tools that are defined as compatible with the 1Password SSH agent should work properly.
Sure that's all fine and dandy for git, but if you want to use the 1Password SSH agent in WSL for authenticating connections to any SSH servers, you just need to add an SSH alias to the shell profile/rc file!