Skip to content

SSH Certificates

Advantages

  • Centralized access management - certificates can be revoked.
  • Additional security through the restrictions around how the certificates can be used. Both directions can be restricted in various ways:
    • Hostnames/IP address
    • Usernames
    • Validity period
  • User certificates can grant access to multiple usernames.
  • User certificates allow multiple users to be trusted through a single user CA.
  • Host certificates avoid clients having to verify host keys (or blindly trusting them on the first connection, as is common).
  • Host certificates allow multiple hosts to be trusted through a single host CA.

Quickstart

Configure sshd on server
cat <<EOF > /etc/ssh/sshd_config.d/certs.conf
TrustedUserCAKeys /etc/ssh/ssh_user_ca.pub
HostKey /etc/ssh/ssh_host_ed25519_key
HostCertificate /etc/ssh/ssh_host_ed25519_key-cert.pub
EOF

Client

Client core concepts

  • The user CA is just a set of public/private keys, separate from the user's normal set of keys.
  • The public key of the user CA is added to the TrustedUserCAKeys of the sshd_config of the host system.
  • The private key of the user CA is used to sign the user's public key, which produces the certificate file.
  • The certificate is a public key with embedded metadata/restrictions about the clients allowed to use it.
  • Clients can connect using the certificate and a matching private key.
  • Servers trust the certificate with restrictions instead of the user's public key.

General Process

  1. Copy client public key to the system with the user CA private key.
  2. Sign the client public key using the user CA private key
    • This produces the client certificate (public)
  3. Copy client certificate back to client
  4. Use on client in conjunction with the client private key.

Only public keys are copied around. Private keys should never move.

User CA

The keys for the User CA need to be generated on the same system that will be used to do the signing so that the private key is never transfered anywhere. It needs to be separate from the host certificate because it won't use the -h flag when signing.

Generate new user CA
ssh-keygen -t ed25519 -f /etc/ssh/ssh_user_ca -N "" -C "hermes-user-ca" 
Key generation flags explained
-t ed25519
Specifies the key type to create. ed25519 is a modern, secure elliptic curve algorithm that's faster and more secure than RSA.
-f /etc/ssh/ssh_user_ca
Specifies the filename for the key files. This creates both /etc/ssh/ssh_user_ca (private key) and /etc/ssh/ssh_user_ca.pub (public key).
-C "user-ca"
Provides a comment to identify the key. This is purely for human reference and appears in the public key file.
-N ""
Specifies the passphrase for the private key. An empty string ("") means no passphrase, which is typical for automated systems and CA keys.

Config

Add to server /etc/ssh/sshd_config
TrustedUserCAKeys /etc/ssh/ssh_user_ca.pub
Reload sshd
systemctl reload sshd

Signing

Copy the user's public key (~/.ssh/id_ed25519.pub) over manually to /tmp, then sign it with this command:

Sign user's public key with the CA
ssh-keygen \
    -s /etc/ssh/ssh_user_ca \
    -n root,john \
    -I john-laptop-2025-12-08 \
    -V +4w \
    -O source-address=192.168.1.0/24 \
    /tmp/id_ed25519.pub
Signing flags explained
-s /etc/ssh/ssh_user_ca
Path to the private key of the user CA that will sign the certificate.
-n root,john

Principals are the user account names this certificate is valid for. For user certificates, principals = usernames the certificate holder is allowed to log in as.

  • The user certificate is only valid when logging in as one of these usernames.
  • SSH servers will reject the cert if the username doesn't match a listed principal.
  • Multiple principals can be specified (comma separated).
  • User certs typically require principals to be specified.
-I john-laptop-2025-12-08

This is a human-readable certificate ID string.

  • Appears inside the certificate
  • Used for logs, auditing, debugging
  • Does not affect authorization
  • Can identify which device/purpose the cert is for
-V +4w

Specifies the validity period for the certificate. Format can be:

  • +52w = valid for 52 weeks from now
  • -5m:+52w = valid from 5 minutes ago to 52 weeks from now
  • Validity times are in UTC
  • Unlike keys, certificates can expire
-O source-address=192.168.1.0/24
Only trust connections coming from this IP address range (LAN). This is optional, but provides extra restrictions.
/tmp/id_ed25519.pub

Path to the user's public key that gets signed to produce the certificate file.

  • Named <key filename>-cert.pub.
  • The matching private key has to be used with the certificate

Copy the user cert (/tmp/id_ed25519-cert.pub) back to the client, where it will be automatically used because it will match the filenames of the existing keyset there.

The host can now authenticate users without having their public keys

The host trusts the user CA that signed the certificate, rather than the user's public key. Certificates from connecting clients will be considered valid if:

  • The path to the public key of the user CA (ssh_user_ca.pub) is configured with TrustedUserCAKeys in the host sshd_config
  • The client has a private key that matches its certificate
  • The username on the host matches one of the certificate's principals
  • The certificate is within its validity period
  • The certificate has not been revoked

More Tips

Inspect your certificate
ssh-keygen -L -f ~/.ssh/id_ed25519-cert.pub
Verify which key/certs are being used
ssh -v [email protected] 2>&1 | grep -E "public|key|cert"
Using with ssh-agent
ssh-add ~/.ssh/id_ed25519
# Outputs:
# Identity added: ~/.ssh/id_ed25519
# Certificate added: ~/.ssh/id_ed25519-cert.pub (john-laptop-2025-12-08)

Use IdentityFile and CertificateFile in SSH config

~/.ssh/config
Host hermes
    HostName hermes.john-stream.com
    User john
    IdentityFile ~/.ssh/custom-key-name
    CertificateFile ~/.ssh/custom-cert-name-cert.pub

The CertificateFile directive explicitly specifies which certificate to use, useful when the naming doesn't follow the standard <keyname>-cert.pub pattern.

Server

Server core concepts

  • The host CA is just a set of public/private keys, separate from the host keys for the sshd service.
  • The private key of the host CA is used to sign the public key of the host, which produces the certificate file.
  • The paths to the host's private key and certificate are each specified in the sshd_config as HostKey and HostCertificate respectively.
  • The certificate content is added as a @cert-authority in the known_hosts file on the client.
  • The certificate is a public key with metadata embedded about the hosts that can use it.
  • Clients trust the certificate instead of the host public key.

Host CA

Generate new host CA
ssh-keygen -t ed25519 -f /etc/ssh/ssh_host_ca -N "" -C "hermes-host-ca"
Key generation flags explained
-t ed25519
Specifies the key type to create. ed25519 is a modern, secure elliptic curve algorithm that's faster and more secure than RSA.
-f /etc/ssh/ssh_host_ca
Specifies the filename for the key file. This creates both /etc/ssh/ssh_host_ca (private key) and /etc/ssh/ssh_host_ca.pub (public key).
-C "hermes-ca"
Provides a comment to identify the key. This is purely for human reference and appears in the public key file.
-N ""
Specifies the passphrase for the private key. An empty string ("") means no passphrase, which is typical for automated systems and CA keys.

Signing

Use the private key of a CA to sign another (public) key to generate the certificate
ssh-keygen -h \
    -s /etc/ssh/ssh_host_ca \
    -n hermes.john-stream.com,192.168.1.10 \
    -I hermes-host-2025-12-08 \
    /etc/ssh/ssh_host_ed25519_key.pub
Sign command explanation
-h

Mark as a host certificate (not a user certificate). Host certs:

  • authenticate SSH servers
  • used for @cert-authority entries in known_hosts
  • bound to hostnames (principals)
-s /etc/ssh/ssh_host_ca
Path to the private key of the host CA that will be used to sign the host public key.
-n hermes.john-stream.com,192.168.1.10

Principals are the identifiers this certificate is valid for. For host certificates, principals = hostnames or IPs the certificate is allowed to represent.

  • Host certs are invalid without principals specified.
  • Multiple principals can be specified (comma separated).
  • SSH clients will reject the cert if the principal does not match what the client thinks the hostname is.
  • Hosts cannot be specified with CIDR notation - only specific IP addresses.
-I hermes-host-2025-12-08

This is a human-readable certificate ID string.

  • Embedded in the certificate metadata
  • Used for logs, auditing, debugging
  • Does not affect authorization
  • Does not need to match hostname
/etc/ssh/ssh_host_ed25519_key.pub

Path to the host public key that gets signed to produce the certificate file

  • Named <key filename>-cert.pub.
  • The matching private key has to be used with the certificate.
  • The content from this file is what goes in the @cert-authority line in the known_hosts file on the client.

Config

Add this to the sshd_config of the host the user will be connecting to.

Host /etc/ssh/sshd_config
HostKey /etc/ssh/ssh_host_ed25519_key
HostCertificate /etc/ssh/ssh_host_ed25519_key-cert.pub

This will cause the host to present the newly-signed certificate when clients connect. For the clients to trust the certificate, they have to trust the host CA that signed it. The clients trust the host CA by having an entry for it in their known_hosts file. Create an entry for the host CA as a @cert-authority using the the content from the public key of the host CA (ssh_host_ca.pub) in the client's known_hosts file.

Client ~/.ssh/known_hosts
# @cert-authority <pattern> <key-type> <base64> [comment]
@cert-authority *.john-stream.com,192.168.1.10 ssh-ed25519 AAAACCA.... hermes-host-ca

Put the @cert-authority in /etc/ssh/ssh_known_hosts instead of ~/.ssh/known_hosts to make it global on the client

Users can now connect without having the host's public key

Clients trust the host CA that signed the certificate, rather than the public key itself. Clients connecting will consider a certificate valid if:

  • The public key of the host CA that signed it (ssh_host_ca.pub) is in their known_hosts (via @cert-authority)
  • The hostname they connected to matches the certificate’s principal
  • The validity period (defaults) is acceptable