Git is currently the most popular version control system. It supports both HTTPS and SSH for accessing remote repositories. SSH is often preferred as it is more convenient and more secure.
As OpenSSH supports FIDO security keys and Git supports SSH, their combination can be used effectively to increase the security of your Git repositories.
This document describes
how to protect SSH access to your repositories using a security key
how to sign Git commits and tags with SSH keys that are protected with a security key
When using git with SSH as its transport protocol, using a FIDO security key to authenticate Git operations works exactly the same as when setting up SSH for any other SSH connections.
Follow the step-by-step configuration instructions to enable SSH authentication with the YubiKey and FIDO2 for your clients.
If you are hosting a remote Git repository yourself, you will need to install and configure an OpenSSH server that supports FIDO. A default install will work fine, just make sure you enable SSH public key authentication.
If you are using a cloud service like Github or Gitlab, see below.
Because anyone can spoof a Git committer or author name with a
git config command, many developers like to sign their
tags and commits.
Traditionally, this is done using PGP, and you can
use a YubiKey for that as well.
However, it may be simpler to use SSH for this, as since versions 2.34 Git also supports signing tags and commits using SSH keys. This means that SSH keys can be used that are backed by FIDO security keys.
To sign Git tags or Git commits, you will need to configure your Git client to use the SSH key format instead of the default PGP key format:
git config gpg.format ssh
In addition, you need to tell Git what SSH key to sign with. Let’s assume you generated an ECDSA key, using your security key with something like:
ssh-keygen -t ecdsa-sk -f ~/.ssh/id_ecdsa_sk ...
In that case, instruct Git to use the generated key for signing:
git config user.signingKey ~/.ssh/id_ecdsa_sk
To verify signatures, we also need to tell Git what SSH public
keys are trusted for verification.
In PGP this is done using your PGP key ring.
For SSH signatures, trusted public keys are typically collected
The file contents is similar to an
authorized_keys file, with
entries starting with a signer’s email address.
cat ~/.ssh/allowed_signers email@example.com firstname.lastname@example.org AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIJhUXYvdwz3Dx45bWNmxHs1R21mlUm0o63+s4iCzRoFeAAAACnNzaDpnaXRodWI= user@host
The file format is described here.
Add this file to your Git configuration:
git config gpg.ssh.allowedSignersFile ~/.ssh/allowed_signers
See the git-config manpage for more details.
When collaborating in a team, all team members should add their colleague’s SSH keys in a similar way to be able to verify each other’s signatures.
Signing a Git commit using SSH is no different than signing with PGP:
git commit -S -m'initial import' [main (root-commit) 519ccdd] initial import 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 README
Your security key will blink, prompting for you to touch it.
The Git log can show and verify signatures:
git log --oneline --show-signature 519ccdd (HEAD -> main) Good "git" signature for email@example.com with ED25519-SK key SHA256:FpybChVXHU/MnwIvOszDxV2yFSbDp9ZkYXxjQ2E+8x0 initial import
You can also instruct Git to reject commits without valid signatures when merging. See the Git documentation for more details.
Similarly, you can sign tags using your security key:
git tag -s v1.0 -m'signed v1.0 tag'
Again, your security key will blink, prompting for you to touch it.
To view the tag signature:
git show v1.0 tag v1.0 Tagger: User <firstname.lastname@example.org> Date: Fri Sep 23 16:10:41 2022 +0200 signed v1.0 tag -----BEGIN SSH SIGNATURE----- U1NIU0lHAAAAAQAAAFAAAAAac2stc3NoLWVkMjU1MTlAb3BlbnNzaC5jb20AAAAgmFRdi9 3DPcPHjltY2bEezVHbWaVSbSjrf6ziILNGgV4AAAAKc3NoOmdpdGh1YgAAAANnaXQAAAAA AAAABnNoYTUxMgAAAGcAAAAac2stc3NoLWVkMjU1MTlAb3BlbnNzaC5jb20AAABA2TkoFS os9OiTRdHLWc+TyefMQ+Bl6cDFMOBQQsEkemcmzVb8n6IaaDYPMrsZ6OJBwosyGHbOx88H P6M6meusDwEAAAAu -----END SSH SIGNATURE----- commit 519ccdda4ad0bdf6b4790a6a0d0972b12df0ef9c (HEAD -> main, tag: v1.0) ...
To verify the Git tag signature:
git tag -v v1.0 object 519ccdda4ad0bdf6b4790a6a0d0972b12df0ef9c type commit tag v1.0 tagger User <email@example.com> 1663942241 +0200 signed v1.0 tag Good "git" signature for firstname.lastname@example.org with ED25519-SK key SHA256:FpybChVXHU/MnwIvOszDxV2yFSbDp9ZkYXxjQ2E+8x0
See the Git documentation for more details on signing Git tags and commits.
You can use ECDSA as well as ED25519 keys stored on a security key such as the YubiKey. See their documentation for details.
In short, to access your GitHub repositories over SSH with your security key:
generate an SSH key pair backed by your security key:
ssh-keygen -t ecdsa-sk
upload the public key to GitHub in your personal profile.
test access with
ssh -T email@example.com
Your security key should start to blink, waiting for you to touch it to approve authentication:
ssh -T firstname.lastname@example.org Confirm user presence for key ECDSA-SK SHA256:47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU User presence confirmed Hi user! You've successfully authenticated, but GitHub does not provide shell access.
You should now be able to perform Git operations protected with the FIDO credential on your security key.
If it doesn’t, verify that the SSH public keys on your security key match your registered GitHub SSH keys, available at the URL
username is your GitHub username.
For commit and tag signing, upload your SSH key as a Signing Key, instead of an Authentication Key.
Like GitHub, GitLab supports FIDO security keys both for access using a browser (as a second factor) and when using a Git client.
As before, you can test access using your security key by initiating an SSH connection:
ssh -T email@example.com Confirm user presence for key ECDSA-SK SHA256:47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU User presence confirmed Welcome to GitLab, @user!
At the time of writing, GitLab doesn’t show verified tags or commits on their web interface.
When generating SSH keys backed by security keys, consider using additional options.
When you want to easily replicate the SSH key files for use on different systems, consider generating resident keys:
ssh-keygen -t ecdsa-sk -O resident
For extra security whenever your credential is used for signing operations, consider requiring to always require the FIDO PIN:
ssh-keygen -t ecdsa-sk -f ~/.ssh/id_ecdsa_sk -O verify-required
When storing multiple credentials on your security key, they can
be hard to distinguish from one another. Consider adding an application
name that starts with
ssh: to tell them apart:
ssh-keygen -t ecdsa-sk -f ~/.ssh/id_ecdsa_sk -O resident -O application=ssh:gitlab
This way, when listing the credentials stored on your security key, it becomes more easy to tell which is which:
ykman fido credentials list Enter your PIN: ssh: 0000000000000000000000000000000000000000000000000000000000000000 openssh ssh:github 0000000000000000000000000000000000000000000000000000000000000000 openssh ssh:gitlab 0000000000000000000000000000000000000000000000000000000000000000 openssh
This approach also protects you from accidentally overwriting your SSH credentials.
Using your security key with git depends on specific versions of your software.
SSH version 8.2 is required for FIDO support.
For resident keys, SSH version 8.4 is required.
For resident keys, you will need a security key with support for discoverable credentials (formerly known as resident keys) and the
credProtect extension. For YubiKeys these are available in firmware versions 5.4 and up.
For using SSH signatures, Git version 2.34 is required.
Also note that:
the version of OpenSSH available on Windows does not support FIDO keys at the time this page was last updated.
the version of OpenSSH shipped with MacOS does not support FIDO keys. Use Homebrew to install a version that does.