Configures a YubiKey as a SSH CA in order to sign user and host keys for SSH certificate authentication. Some would call this the right way to configure SSH authentication as opposed to simply using public keys. Then configures SSH servers and daemons to verify certificates against this CA.
IT admins, maybe overseeing an infrastructure with multiple servers and clients and/or users.
Ensure the PC/SC daemon is running. It is not started by default on distributions such as Arch.
systemctl start pcscd.service
Insert the YubiKey into your next USB slot and pull the list of detected YubiKeys.
ykman list
Ensure PIV is enabled on that YubiKey and confirm with y
. Then change PIN, PUK and the management key.
ykman config usb -e PIV
ykman piv change-pin
ykman piv change-puk
ykman piv change-management-key
Create a new key pair and certificate in PIV slot 9d (which according to the PIV documentation is designated for Key Management use). Use --pin-policy
and --touch-policy
to decide when PIN and/or touch is required to access this slot. The default is --pin-policy ALWAYS
and --touch-policy NEVER
. sshca.pub
is a path/filename where ykman
will write a public key for the slot certificate. It can be deleted after generation since it's possible to extract the pubkey afterwards if necessary.
ykman piv keys generate 9d sshca.pem
ykman piv certificates generade -s "SSH CA" -d 3650 9d sshca.pem
Extract the public key of the generated keypair for use with SSH. The important part is -D libykcs11.so
telling ssh-keygen
to use the p11-kit
YubiKey module for access.
ssh-keygen -D libykcs11.so | grep Management > /tmp/sshca.pub
Generate a SSH keypair like you usually would, using your favorite options. This one uses EdDSA/Curve25519 key type with a -Comment and writes this to a -file.
ssh-keygen -t ed25519 -C "Host key for a server" -f /tmp/host-server
Transfer the generated private key to the YubiKey machine and sign it. -h
designates a host key. Use -D
to tell ssh-keygen
which library to use, -s
as the key indicator, -I
as the key name, -n
as the host/domain names with which the host will be reachable and -V
as the validity period of this certificate. You will be asked for the PIV pin, a touch of the button or both, depending on your settings.
ssh-keygen -h -D libykcs11.so -s /tmp/sshca.pub -I "Host key for a server" -n example.com -V +52w host-server.pub
Transfer the newly generated certificate along with the public key of the SSH CA (sshca.pub
) to the host and save it in /etc/ssh/
. Make sure they belong to root and that the private key is sufficiently secured (otherwise SSH will not start, anyway).
chmod 0600 /etc/ssh/host-server
/etc/ssh/sshd_config
must be edited so that the new host certificate is presented to connecting clients, and so that SSH authenticates them against the YubiKey CA. Disable, comment out or delete default password and pubkey-related directives. Restart sshd afterwards.
HostCertificate /etc/ssh/host-myserver-cert.pub
HostKey /etc/ssh/host-myserver
TrustedUserCAKeys /etc/ssh/sshca.pub
# AuthorizedKeysFile .ssh/authorized_keys
# HostKey /etc/ssh/ssh_host_rsa_key
# HostKey /etc/ssh/ssh_host_ecdsa_key
# HostKey /etc/ssh/ssh_host_ed25519_key
# PubKeyAuthentication yes
# PasswordAuthentication yes
KbdInteractiveAuthentication no
As with the host keys, generate a keypair with your favorite options.
ssh-keygen -t ed25519 -C "User key for user123" -f /tmp/user-123
Transfer the private key to the YubiKey machine and sign it. The command is very similar, but this time -h
must be omitted. -n
now designates the user names instead of host names.
ssh-keygen -D libykcs11.so -s /tmp/sshca.pub -I "User key for user123" -n user123 -V +52w user-user123.pub
Transfer the generated user-user123-cert.pub
file back to the user. Now to decide whether certificate authentication should be done for that user only or globally on a client machine.
Place the private key and user cert into /etc/ssh/
. In /etc/ssh/ssh_known_hosts
enter the contents of the sshca.pub
using the @cert-authority
directive. The middle part is a comma-separated list of hostnames with which the certificate is to be used. It accepts globs, so a *
would mean all hosts.
@cert-authority example.com ssh-rsa AB3zā¦
Place the private key and usercert into ~/.ssh/
of relevant users instead and edit ~.ssh/known_hosts
. The entry is the same as in the global case.