This guide is for Linux/WSL. I don’t have a Mac to test with, but I suspect most of the principles apply. You will need to be running OpenSSH 8.2 or later (released 2020-02-14).
Modern Yubikeys (5.2.3+) can perform ed25519 operations onboard. This includes keeping the private key onboard, which is really what we’re after. There are other guides describing how to do this, but they’re all missing some key ingredient, or they add extra steps that I don’t need.
If you follow these steps:
- Your git commits will be cryptographically signed, and GitHub will show this.
- All authenticated GitHub operations (push/pull) will require a touch to your Yubikey.
- Your private key never leaves your Yubikey.
- You won’t need to learn GPG or have to maintain GPG keys.
- If your Yubikey is lost or stolen, your key is protected by a PIN.
1. Install ykman
ykman is a Yubikey CLI tool we’ll use for some initial setup. Download ykman
2. Create a PIN for FIDO operations
This PIN will protect you if your key is stolen or lost. You’ll need to memorize this PIN, because every time you reboot your computer, you’ll need to enter it before performing any crypto operations. The PIN is mandatory.
ykman fido access change-pin --new-pin
You should probably write your PIN down somewhere on paper.
3. Create a new ed25519 key
ssh-keygen -t ed25519-sk -C firstname.lastname@example.org -O email@example.com -O resident
The email addresses that you specify to ssh-keygen don’t have any effect on signing or identify verification, which is why I use them merely to help identify my keys. I use the “sk1” suffix to tell me that this is my security key #1. My second Yubikey will use “sk2”, etc. “Mars” is the hostname where I generated the key.
-O user option will cause that string to be written into the key data on the Yubikey, which helps identify it, if you have multiple keys on one device (I only have one).
-O resident option tells
ssh-keygen that the private key is going to live on the hardware device.
ed25519-sk stands for Security Key, and if you want more details about all this, see the OpenSSH 8.2 Release Notes
4. Make sure the new key is on your Yubikey
ykman fido credentials list
My output looks like this:
ssh: 62656e406d6172732e736b310000000000000000000000000000000000000000 openssh
The long string ending in 00000 is the hex encoding of the identifier that you specified in “-O user”, padded with zeroes.
5. Delete the private key off your hard drive
Note however, that we leave the public key file
id_ed25519_sk.pub, because we’ll need it for signing git commits.
6. Tell ssh-agent about your hardware key
Add keys from hardware devices into your local store:
My output is:
Resident identity added: ED25519-SK SHA256:7vuh0DJyNjehHIEZnDEQ7ZafWp/o2Eed+tNKtps6l9g
This does not copy the private key into memory. You’ll still need to touch your Yubikey whenever the private key is needed. But
ssh-add -K is necessary for informing ssh-agent that this key exists.
Note that every time you reboot, you’ll need to run
ssh-add -K before using your key, and this operation requires your PIN.
7. Add your key to Github
You can use this command to list your public keys:
My output looks like this:
Go to your Github profile, and under
SSH and GPG keys, add this new key.
You’ll have to add it twice. Once as an
Authentication key, and once as a
8. Configure git to sign with your new key
git config --global commit.gpgsign true git config --global gpg.format ssh git config --global user.signingkey "~/.ssh/id_ed25519_sk.pub"
9. Make a test commit
In order to complete the creation of your commit, you’ll need to touch your Yubikey. It should flash, indicating that it wants to be touched.
git push will also require a touch.
10. Verify on GitHub
Any commit that you make from now on, should show up on Github with the green
Verified badge, and if you click on it,
GitHub will show you the person associated with that commit.
If you click on the
Verified button on GitHub, it will show you the SHA256 hash of the key that signed this commit, which should match the hash
that you’ll see when doing
11. Verify locally
Unfortunately, I don’t know how to verify signatures locally. I think this is because GPG doesn’t understand the
firstname.lastname@example.org key format.
The following procedure might work in future, but it doesn’t work for me now.
git config --global gpg.ssh.allowedSignersFile ~/.ssh/allowed_signers cat ~/.ssh/id_ed25519_sk.pub >> ~/.ssh/allowed_signers git show --show-signature
This guide was based on the following sources: