YubiKey as SSH CA

    Description

    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.

    Who is it for?

    IT admins, maybe overseeing an infrastructure with multiple servers and clients and/or users.

    Tools

    • YubiKey
    • ykman – Yubikey Manager, configurator for everything YubiKey
    • pcsclite – Middleware for Smartcard access
    • p11-kit – Middleware for PKCS#11 devices
    • libykcs11 – p11-kit module providing YubiKey support

    Preparation

    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
    

    Creation of CA

    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
    

    Signing host keys

    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
    

    Signing user keys

    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.

    Globally

    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…
    

    Per-user

    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.

    See also