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
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
TrustedUserCAKeysof thesshd_configof 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
- Copy client public key to the system with the user CA private key.
- Sign the client public key using the user CA private key
- This produces the client certificate (public)
- Copy client certificate back to client
- 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.
Key generation flags explained
- -t ed25519
- Specifies the key type to create.
ed25519is 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
Signing
Copy the user's public key (~/.ssh/id_ed25519.pub) over manually to /tmp, then sign it with this command:
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
- Named
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 withTrustedUserCAKeysin the hostsshd_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
ssh -v [email protected] 2>&1 | grep -E "public|key|cert"
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
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
sshdservice. - 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_configasHostKeyandHostCertificaterespectively. - The certificate content is added as a
@cert-authorityin theknown_hostsfile 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
Key generation flags explained
- -t ed25519
- Specifies the key type to create.
ed25519is 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
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-authorityentries inknown_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-authorityline in theknown_hostsfile on the client.
- Named
Config
Add this to the sshd_config of the host the user will be connecting to.
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.
# @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