API authentication with the private key on a smartcard (yubikey)

I’m trying to figure out how much work it would be for incus client to use a private key on a smartcard (specifically, a yubikey through its PIV applet) as opposed to the current on-disk client.key.

Is there anyone else interested in such a feature? I know of the existence of OIDC, but I’d rather keep things local/simple, and I am heavily relying on a yubikey already for SSH (yubikey-agent/sk-ssh-ed25519@openssh.com), age (though age-plugin-yubikey) and its OpenPGP applet, so might as well continue down that path.

My impression is that the server side is already sufficiently generic for this to work, because the trust list takes fingerprints. That is, you can do this:

$ ykman piv keys generate --algorithm ECCP256 83 pubkey.pem
$ ykman piv certificates generate --subject "CN=incus" 83 pubkey.pem
$ ykman piv certificates export 83 client.crt
$ incus config trust add client.crt

What is currently missing, is a codepath in the incus client to use a yubikey instead of client.key on-disk. I have to investigate whether the go tls library makes plumbing this in simple or hard. But at least on the PIV side, there is GitHub - go-piv/piv-go: Keys and certificates for YubiKeys, written in Go · GitHub to build on.

It looks like piv-go exposes a standard crypto.PrivateKey and this could be passed into the X509KeyPair that is constructed inside of Incus.

I’m not sure that we’d want to pull in a Yubikey-specific backend, we’d likely then be asked about supporting TPM backend keys, HSM backed keys, … and don’t really want to have with each of them individually.

PKCS11 may be the better option by using something like GitHub - miekg/pkcs11: pkcs11 wrapper for Go · GitHub.

The problem there is that it would require the client to use cgo, or rather, we’d need to make this entire logic dependent on the client being built with cgo and likely a specific pkcs11 build tag. Then distributions can decide whether to link against pkcs11 and provide that functionality.

OK, that sounds very understandable. The CGO stuff is unfortunate.

Going by the hint in miek’s repo, the combination of GitHub - eclipse-keypont/crypto11: Implement crypto.Signer and crypto.Decrypter for HSM-protected keys via PKCS#11 · GitHub and YKCS11 should get me where I’d want to be.