Using multiple yubikeys

18. September 2025

The setup

I have been using a yubikey as my primary storage device for gpg-keys for a few years now. I use these keys daily, for signing things, mainly commits, for encrypting things, but most importantly for ssh authentication. I even use them to become root on my current system using ssh root@localhost, I don't even remember my actual root password anymore.

This works great. A few years ago I even bought a second yubikey just in case the first one ever breaks, so I'd have a backup. Back then I commisioned the second yubikey, tossed it in a secure place and never looked at it again, just keeping it for the worst case.

This changed recently because on multiple occasions I forgot my primary yubikey in my PC at home when going out, leaving me without access to any of my servers, or even local root. To prevent this happening again, I came up with the plan of having one home yubikey that always resides in the desktop PC at home, and one mobile yubikey that remains on my keychain only to be used intermittenly with my laptop.

Since I already had the second yubikey this sounded like a great plan. As it turns out however the tools I use aren't really made for this usage pattern.

This is the story and solutions I have found so far to enable my usage.

GPG

The most tool I mostly use is (sadly) still gpg. The yubikey has 3 keyslots to save gpg private keys, on for each usage, authentication, signing and encrypting. I used this great guide to set these up and now use them for both siging my commits as well as ssh, by using the gpg-agent.

Multi GPG vs Single GPG

When using multiple yubikeys the main decision on has to make is whether to use one gpg masterkey per yubikey or cloning the same gpg keys to each yubikey.

Using a singular gpg-key makes usage a lot easier as you don't have to remember to add both keys everywhere you'd like to use them. However in case one of the keys gets lost or stolen you'd have to revoke the singular keys, leaving you without any chain of trust.

For this reason I choose to implement one gpg key per yubikey. If one gets stolen I can revoke it and resign everysing I published using the other key.

gpg-agent

This one suprisingly just worked. It seems to realize that only one key can be used and prompts me for the corresponding pin, never even mentioning the other possible key. Yay at least one.

Signing

Both my gpg identities contain my primary email, which I've so far used as the uid when signing things. GPG however dosn't really seem to support this case in which two keys have the same uid, and will always only try the first one when using gpg -u <email>. First here meaning first to have been added to the keyring. If that doesn't work it will just fail instead of trying a different one.

One solution would be instead of setting your git/jujutsu signing key uid to <email> to directly set it to the fingerprint of the key you'd like to use. This has the drawback of having to be done on a per-repository basis and changed each time you'd like to use the other yubikey.

I have implemented another solution as seen here. This works by telling git/jujutsu to call this wrapper as their gpg program.

The wrapper then does three things:

  1. See if the identity is even set to <email>. Just in case I ever actually don't want to use my yubikeys.
  2. If it is it will remove the identy flag from the call and replace it by the identity of whichever yubikey is plugged in.
  3. Call gpg with the updated identity and any other flags we have been called with.

So far it's worked great. One downside is that I think the ykman call in there resets the yubikey and in turn also any cached PINs.

Another thing to watch out for is I think you have to use the public fingerprint of the specific signing subkey, not the fingerprint of the masterkey. gpg --list-keys only prints the masterkey fingerprint, you can use gpg --card-status to get the subkey fingerprints.

Private Key handles on impermanence

Kinda hyperspecific but maybe you have this problem.

You can just copy the private keygrips into the gpg config folder instead of having to call gpg --card-status each time to get gpg to pick up on the secrets keys. See this script.

Age

The second program I use a lot is age using age-plugin-yubikey to have my secret keys on the yubikey.

The problem here is basically the same. Basically age will always query the identities, private keys in age-land, and associated plugings in the given order. There is no way for the plugin to know whether there is a second idenity and it can just silently exit, or if it is the only one and should output an error when it cannot function.

At least age tries the second yubikey if the first one fails, so for now I just have to click skip this yubikey each time I'm using my secondary one.

The main tool I'm using with age is agenix-rekey so I might implement a way to on-demand reorder the identities in there, but for now there's a bunch of other stuff to do so this will have to wait.

FIDO and other stuff

Of course most people will probably use the yubikey as a FIDO or webauthn key. I barely do that. If I use webauthn or passkeys I save them in my bitwarden, to have them easily accessible anywhere.

But I think it should just work with two keys here. The major downside of course being you would have to separately add each yubikey to each site you want to use them.

https://blog.lel.lol/blog/atom.xml