Use OpenSSH Certificates and Key Revocation
OpenSSH certificates let an administrator trust a signing authority (CA) while keeping individual user keys short-lived and attributable. A certificate is not a replacement for a private key: the client still proves possession of its private key, and sshd still checks the certificate’s principals, validity interval, source restrictions, and revocation status. This article uses a small, owned Linux estate as its example; apply it only to hosts and accounts you are authorized to administer.
Choose the certificate model
| Object | What it proves | Operational decision |
|---|---|---|
| User CA | A user key was signed by the organization’s CA and carries one or more principals. | Use for human SSH access; issue short validity and one named person or role. |
| Host CA | A host key was signed by the host CA. | Distribute @cert-authority trust instead of copying every host key. |
| Principal | The account or role name the certificate is allowed to log in as. | Keep it narrow, such as alice or pi-admin; do not use an accidental wildcard. |
| KRL | A compact revocation list consumed by OpenSSH. | Publish atomically, back it up, and test that revocation denies a connection. |
Use separate user and host CAs. Keep their key files, permissions, custodians, and rotation schedules separate so compromise of one authority does not automatically compromise the other. A certificate’s key ID (-I) should identify the ticket, owner, and purpose in an issuance record; it is useful in logs but is not a secret.
Create and protect a user CA
Run these commands on a protected signing host after checking the installed OpenSSH version with ssh -V and ssh-keygen -h. The option names below are long-standing OpenSSH options, but distributions can backport behavior. Stop and read the installed manual if an option is unavailable.
umask 077
install -d -m 700 "$HOME/ssh-ca"
ssh-keygen -t ed25519 -f "$HOME/ssh-ca/user_ca" -C "SSH user CA $(hostname -s)"
chmod 600 "$HOME/ssh-ca/user_ca"
chmod 644 "$HOME/ssh-ca/user_ca.pub"
Use a strong passphrase and keep the private key offline when not signing. A passphrase protects a stolen file but does not make an online CA safe. Limit signing access to a small, recorded group; use two-person review for production issuance; encrypt backups; store one backup offline; and periodically prove that the backup can be read without exposing the private key. If the CA key is suspected exposed, stop issuing, revoke its trust from every server, and follow the CA rotation procedure rather than merely changing a user key.
Issue a short-lived user certificate
Generate a user key on the user’s device. The private key never needs to visit the CA; send the public key through an approved channel and return only the signed certificate.
ssh-keygen -t ed25519 -f "$HOME/.ssh/id_ed25519_admin" -C "alice admin key"
chmod 600 "$HOME/.ssh/id_ed25519_admin"
chmod 644 "$HOME/.ssh/id_ed25519_admin.pub"
# On the protected CA host, after reviewing the request:
ssh-keygen -s "$HOME/ssh-ca/user_ca" \
-I "alice-change-20260914-001" \
-n "alice" \
-V "-5m:+8h" \
-z 20260914001 \
/path/to/id_ed25519_admin.pub
-V "-5m:+8h" allows a small clock-skew margin and expires the certificate eight hours after signing; choose a duration that matches the role and incident response window. For automation, use a separate service principal, a narrowly scoped account, and a lifetime measured in minutes or hours. Never issue a broad principal such as root merely to avoid correcting an account mapping.
Inspect before delivery:
ssh-keygen -L -f /path/to/id_ed25519_admin-cert.pub
ssh-keygen -lf /path/to/id_ed25519_admin-cert.pub
ssh-keygen -lf /path/to/id_ed25519_admin.pub
Confirm the key ID, principal, validity interval, critical options, and extensions. Deliver the certificate beside the private key as id_ed25519_admin-cert.pub; the SSH client discovers that conventional filename automatically. Prefer an explicit client stanza when several identities are present:
Host pi-admin.example.invalid
User alice
IdentityFile ~/.ssh/id_ed25519_admin
CertificateFile ~/.ssh/id_ed25519_admin-cert.pub
Trust principals on the server
Install only the user CA public key on the intended server, owned by root and not writable by the login user. TrustedUserCAKeys says which CA may sign users; it does not grant every Unix account. AuthorizedPrincipalsFile maps certificate principals to a local account:
install -o root -g root -m 0644 user_ca.pub /etc/ssh/user_ca.pub
install -o root -g root -m 0644 authorized_principals_alice /etc/ssh/authorized_principals/alice
# /etc/ssh/sshd_config.d/20-user-certificates.conf
TrustedUserCAKeys /etc/ssh/user_ca.pub
AuthorizedPrincipalsFile /etc/ssh/authorized_principals/%u
PubkeyAuthentication yes
PasswordAuthentication no
Put alice on the one line in /etc/ssh/authorized_principals/alice, validate the complete effective configuration, and reload only after a second session or console path is ready:
sshd -t
sshd -T | grep -E 'trustedusercakeys|authorizedprincipalsfile|passwordauthentication|pubkeyauthentication'
sudo systemctl reload ssh || sudo systemctl reload sshd
Some systems name the service ssh, others sshd; use the service name shown by the distribution. A reload preserves existing sessions. Test a new session with the certificate while keeping the old session open.
Revoke a certificate or key with a KRL
A KRL is safer to distribute than an ad-hoc text list, and it can revoke a certificate serial, an entire CA, or a raw public key. Create it in a temporary file, inspect it, then install it atomically with root ownership:
umask 077
work="$(mktemp -d)"
tmp="$work/revoked_keys"
trap 'rm -rf "$work"' EXIT
# Copy the existing KRL, or create a new one for the first entry.
if [ -f /etc/ssh/revoked_keys ]; then
cp -- /etc/ssh/revoked_keys "$tmp"
ssh-keygen -k -u -f "$tmp" \
-s "$HOME/ssh-ca/user_ca.pub" \
/path/to/id_ed25519_admin-cert.pub
else
ssh-keygen -k -f "$tmp" \
-s "$HOME/ssh-ca/user_ca.pub" \
/path/to/id_ed25519_admin-cert.pub
fi
ssh-keygen -Q -f "$tmp" /path/to/id_ed25519_admin-cert.pub
install -o root -g root -m 0644 "$tmp" /etc/ssh/revoked_keys
Feeding the signed certificate to ssh-keygen -k records its certificate serial in the KRL; -s identifies the CA that signed it. Use the issuance record and ssh-keygen -L to map a key ID to its certificate file and serial. For a raw public key, feed the public-key file without -s. Use -u when updating an existing KRL rather than accidentally replacing it. Configure the server:
# /etc/ssh/sshd_config.d/21-revocation.conf
RevokedKeys /etc/ssh/revoked_keys
Run sshd -t, reload, and test a revoked certificate from a separate terminal. A KRL is not retroactive for an already authenticated session; terminate the affected session after revocation. If the CA itself is compromised, revoke or remove CA trust on all servers and issue a replacement CA, not merely a KRL entry for one certificate.
Rotation, recovery, and verification
- Keep an inventory of CA fingerprints, custodians, trusted servers, principal-to-account mappings, certificate serials, expiry, and KRL deployment status. Do not store private keys in that inventory.
- Rotate user keys before expiry and after a device is lost, repaired by an untrusted party, or copied into an unapproved backup. Remove the old certificate and key only after the new path is verified.
- For CA rotation, distribute the new CA public key alongside the old one, verify new certificates, then remove old trust after its last planned certificate expires. Keep a console recovery copy of the configuration.
- Back up the CA public material, issuance records, KRL, server drop-ins, and test instructions. Encrypt CA private-key backups separately and perform a documented restore test.
- Test: valid principal succeeds; wrong principal fails; expired and not-yet-valid certificates fail; a revoked certificate serial and raw public key fail; password authentication remains disabled; an old CA fails after rotation; and a disconnected CA does not block already issued certificates.
Rollback means restoring the last known-good server drop-ins and KRL from a verified backup through the console or a trusted existing session, then running sshd -t before reload. Do not delete all keys as a “rollback,” and do not re-enable password login as an emergency shortcut.
Continue the SSH sequence
Continue the SSH sequence with Log Audit Troubleshoot and Recover SSH.
dispelled