| Tested on | RHEL 10.2 as SSH server (192.168.56.116); Ubuntu 26.04 as CA/admin workstation and SSH client (192.168.56.121) |
|---|---|
| Package | openssh-server-9.9p1-25.el10_2.x86_64 / OpenSSH_10.2p1 Ubuntu |
| Applies to | Modern OpenSSH on RHEL, Rocky, AlmaLinux, Fedora, Ubuntu, and Debian (ssh-keygen -k / -u / -Q, RevokedKeys) |
| Privilege | sudo or root on the SSH server for the KRL file, sshd_config, and reload; normal user for CA signing and client login tests |
| Scope | OpenSSH-native Key Revocation Lists for plain public keys and user certificates (create, update, query, serial/range/Key ID/fingerprint revocation, RevokedKeys). Does not cover Vault, Smallstep, Teleport, or X.509 CRL/OCSP. |
| Related guides | SSH key authentication Generate SSH keys OpenSSH authentication methods Restrict SSH users and groups |
In this article we will revoke SSH access with an OpenSSH Key Revocation List (KRL) so sshd refuses a stolen key or a bad certificate everywhere you deploy that file. You do not need to wait for certificate expiry, and you do not need to hunt every authorized_keys copy in environments that use SSH certificates across many servers.
I ran the full path on RHEL 10.2 as the SSH server and Ubuntu 26.04 as the CA and client: issue a user certificate with a non-zero serial, create a KRL, confirm revocation with ssh-keygen -Q, point RevokedKeys at the file, watch login fail, then update the same KRL with -u and revoke by serial, serial range, Key ID, fingerprint, and plain public key.
What is an OpenSSH Key Revocation List (KRL)?
You may need to cut SSH access when:
- a private key is stolen
- an employee or administrator leaves
- a certificate was issued with the wrong principals
- a certificate must stop before its expiration time
- an SSH CA key is compromised
- a batch of certificates must be invalidated at once
With plain authorized_keys, you usually remove the user's public key from every server that trusts it. That works for one host. It gets painful when the same key is copied across a fleet.
With OpenSSH certificate authentication, short-lived certificates often expire soon enough that you can wait. When access must stop immediately, waiting is not enough.
OpenSSH's answer is a Key Revocation List (KRL): a compact binary file that tells OpenSSH which keys or certificates must no longer be trusted. You build it with ssh-keygen -k, merge more entries with -u, test with -Q, and make sshd enforce it through RevokedKeys.
RevokedKeys points at the KRL. Revocation is only enforced on systems that receive the updated KRL and are configured to use it; creating the file on the CA host does not revoke access globally by itself.
What can an OpenSSH KRL revoke?
| Credential / identifier | Can a KRL revoke it? |
|---|---|
| Plain SSH public key | Yes |
| User certificate | Yes |
| Host certificate | Yes |
| Certificate serial number | Yes |
| Range of certificate serials | Yes |
| Certificate Key ID | Yes |
| SHA256 public-key fingerprint | Yes |
| Entire CA / CA compromise | Remove that CA from the trust configuration and rotate it |
A few rules of thumb:
- Plain SSH keys are usually revoked by public key or fingerprint.
- Certificates are best revoked by serial number or Key ID.
- Serial-based KRLs are especially compact. OpenSSH documents that a KRL may use as little as one bit per certificate when you revoke by serial.
KRL vs removing a key from authorized_keys
| Situation | Best action |
|---|---|
One public key in authorized_keys on one server |
Remove that line |
| Same public key on many servers | A centrally distributed KRL may be easier |
| SSH certificate must stop before expiry | Revoke with a KRL |
| Short-lived certificate expires soon | Often let it expire |
| CA itself compromised | Remove CA trust and rotate the CA |
A KRL is not a replacement for careful authorized_keys hygiene on every host. Its biggest advantage is certificate revocation and one file you can push to many servers.
Lab topology
Minimal layout for these commands:
Ubuntu client + SSH CA
|
| presents SSH key / certificate
v
RHEL 10 SSH server
|
+-- trusts /etc/ssh/user_ca.pub
+-- checks RevokedKeys /etc/ssh/revoked_keysWith the companion CA flow spelled out:
SSH CA (Ubuntu)
|
+-- signs user certificate
|
v
Client
|
v
Server (RHEL)
|
+-- TrustedUserCAKeys
+-- RevokedKeys (KRL)Files used in the lab:
/etc/ssh/user_ca.pub # CA public key on the server
/etc/ssh/revoked_keys # KRL enforced by sshd
~/ssh-user-ca # CA private key (Ubuntu only)
~/.ssh/id_ed25519.pub # user public key
~/.ssh/id_ed25519-cert.pub # user certificateIf you do not already have a working user CA and a successful certificate login, complete that setup first in the certificate authentication guide, then return here for revocation.
Check your OpenSSH version
Confirm the client and server packages before you change sshd. Do not use ssh-keygen -V for this: that flag is certificate validity syntax, not a version switch.
Ask the client for its OpenSSH build:
ssh -VOpenSSH_10.2p1 Ubuntu-2ubuntu3.6, OpenSSL 3.5.5 27 Jan 2026On the RHEL server, ask sshd the same way:
sshd -VOpenSSH_9.9p1, OpenSSL 3.5.5 27 Jan 2026The RPM NEVRA on my RHEL 10.2 server was openssh-server-9.9p1-25.el10_2.x86_64. KRL support has existed for many OpenSSH releases, so this is not a RHEL-only feature.
Confirm the man pages document the flags you will use. Open the ssh-keygen page and look for -k, -u, and -Q in the KEY REVOCATION LISTS section:
man ssh-keygenThen open sshd_config and search for RevokedKeys. That entry also documents the unreadable-file failure mode:
man sshd_configThose man pages are the official reference for the specification directives in later sections.
Create a test SSH certificate with a serial number
For certificate revocation, deliberately issue a non-zero serial. OpenSSH uses that serial for compact KRL records, and serial 0 cannot be used for serial-based revocation.
On the Ubuntu CA/client host, sign the user's public key with Key ID deepak-2026-01 and serial 1001:
ssh-keygen -s ~/ssh-user-ca -I deepak-2026-01 -z 1001 -n deepak -V +8h ~/.ssh/id_ed25519.pubSigned user key /home/deepak/.ssh/id_ed25519-cert.pub: id "deepak-2026-01" serial 1001 for deepak valid from 2026-09-22T15:41:00 to 2026-09-22T23:42:26What those flags mean:
-Isets the certificate Key ID string-z 1001sets the certificate serial-n deepaksets the principal (login name)-V +8hsets a short validity window
Inspect the certificate so you can see the identifiers the KRL will use later:
ssh-keygen -L -f ~/.ssh/id_ed25519-cert.pub/home/deepak/.ssh/id_ed25519-cert.pub:
Type: ssh-ed25519-cert-v01@openssh.com user certificate
Public key: ED25519-CERT SHA256:Dh0YicssAH/zkefNQQTmvkkw9FIGvSbijtaP3nx6RVU
Signing CA: ED25519 SHA256:+axU8dFjZi4r2zKVN7n9jHJs+XaIvwS55hsp5eUhdhc (using ssh-ed25519)
Key ID: "deepak-2026-01"
Serial: 1001
Valid: from 2026-09-22T15:41:00 to 2026-09-22T23:42:26
Principals:
deepak
Critical Options: (none)
Extensions:
permit-X11-forwarding
permit-agent-forwarding
permit-port-forwarding
permit-pty
permit-user-rcConfirm login still works before you revoke anything. With TrustedUserCAKeys already pointing at the CA public key on the server, a certificate login should succeed. The ssh command options below force public-key auth so a password prompt cannot hide a failed cert:
ssh -o PreferredAuthentications=publickey -o PasswordAuthentication=no deepak@192.168.56.116 'echo BEFORE_REVOKE_OK'BEFORE_REVOKE_OKThe server log for that success named the certificate Key ID and serial, which is useful when you later match a revoke to a journal line.
Create a KRL that revokes one SSH certificate
Start with the simplest path: revoke the certificate file itself. Copy the certificate to the server (or build the KRL on the CA host and distribute it). On the RHEL server:
sudo ssh-keygen -k -f /etc/ssh/revoked_keys -s /etc/ssh/user_ca.pub /tmp/id_ed25519-cert.pubRevoking from /tmp/id_ed25519-cert.pubWhat this command does:
-kcreates a new KRL-fnames the KRL file-ssupplies the issuing CA public key- the final argument is the certificate to revoke
This creates a new KRL. It does not merge into an existing one. OpenSSH records certificate revocation by serial number when it can; if no usable serial exists, it may fall back to the certificate Key ID.
Check that the file appeared with sane ownership and mode:
ls -l /etc/ssh/revoked_keys-rw-r--r--. 1 root root 121 Sep 22 15:42 /etc/ssh/revoked_keysRoot-owned and world-readable is fine for a KRL that every sshd child must read. Do not make the path unreadable; that has a worse failure mode later.
Check whether the certificate is revoked
Before you change sshd, query the KRL directly:
ssh-keygen -Q -f /etc/ssh/revoked_keys /tmp/id_ed25519-cert.pub/tmp/id_ed25519-cert.pub (deepak@client): REVOKEDThe exit status is non-zero when at least one tested credential is revoked:
echo $?1Exit status meaning:
0means none of the tested credentials are revoked- non-zero means at least one credential is revoked, or an error occurred
That makes -Q useful in scripts after you ship a KRL update.
As a contrast, the plain public key is still marked ok in a KRL that only revoked the certificate file:
ssh-keygen -Q -f /etc/ssh/revoked_keys /tmp/id_ed25519.pub/tmp/id_ed25519.pub (deepak@client): okConfigure sshd to use the KRL
Create a drop-in so the main sshd_config stays untouched:
sudo tee /etc/ssh/sshd_config.d/70-revoked-keys.conf >/dev/null <<'EOF'
RevokedKeys /etc/ssh/revoked_keys
EOFValidate the config before you reload:
sudo sshd -tA silent exit means the syntax check passed. Reload sshd on RHEL-family hosts:
sudo systemctl reload sshdOn Ubuntu or Debian the unit name is usually ssh:
sudo systemctl reload sshConfirm the effective setting:
sudo sshd -T | grep revokedkeysrevokedkeys /etc/ssh/revoked_keysRevokedKeys cannot be read, OpenSSH refuses public-key authentication for all users. Fix path, mode, ownership, and SELinux labels before you point production sshd at a missing file.
Test a revoked certificate login
Attempt the same certificate login again:
ssh -o PreferredAuthentications=publickey -o PasswordAuthentication=no deepak@192.168.56.116 truedeepak@192.168.56.116: Permission denied (publickey,password).That client message alone is not enough. Read the server journal for the revoke reason. Unit filtering and time windows are covered in the journalctl reference:
sudo journalctl -u sshd -n 20 --no-pagersshd-session[59310]: error: Authentication key ED25519-CERT SHA256:Dh0YicssAH/zkefNQQTmvkkw9FIGvSbijtaP3nx6RVU revoked by file /etc/ssh/revoked_keys
sshd-session[59310]: Connection closed by authenticating user deepak 192.168.56.121 port 46360 [preauth]The revoked by file /etc/ssh/revoked_keys line is the proof that sshd enforced the KRL, not only that ssh-keygen -Q recognized the certificate.
Add another key or certificate to an existing KRL
This step is easy to get wrong. Running ssh-keygen -k again without -u against the same path creates a new KRL and can drop earlier revocations.
Sign a second certificate with serial 1002 and Key ID deepak-2026-02, then merge it into the existing file:
sudo ssh-keygen -k -u -f /etc/ssh/revoked_keys -s /etc/ssh/user_ca.pub /tmp/id_ed25519_alt-cert.pubRevoking from /tmp/id_ed25519_alt-cert.pubFlags:
-kstays in KRL mode-umerges into the existing KRL instead of replacing it
Query both certificates afterward:
ssh-keygen -Q -f /etc/ssh/revoked_keys /tmp/id_ed25519-cert.pub /tmp/id_ed25519_alt-cert.pub/tmp/id_ed25519-cert.pub (deepak@client): REVOKED
/tmp/id_ed25519_alt-cert.pub (deepak-alt@client): REVOKEDBoth stay revoked. That is the create-versus-update difference short tutorials often skip.
Revoke a plain SSH public key
KRLs are not only for certificates. By this point /etc/ssh/revoked_keys already exists and holds certificate revocations, so merge the plain public key with -u. Do not re-run bare ssh-keygen -k against the live path or you will create a new KRL and drop earlier entries.
sudo ssh-keygen -k -u -f /etc/ssh/revoked_keys /tmp/id_ed25519.pubRevoking from /tmp/id_ed25519.pubIf you only want a throwaway demo file, create a separate path such as /tmp/krl-plain-key with ssh-keygen -k instead of writing over /etc/ssh/revoked_keys.
Confirm the plain key is now revoked:
ssh-keygen -Q -f /etc/ssh/revoked_keys /tmp/id_ed25519.pub/tmp/id_ed25519.pub (deepak@client): REVOKEDRevoking the underlying public key also blocks authentication that presents a certificate for that same key. I tested a KRL that contained only the plain public key: ssh-keygen -Q reported the certificate REVOKED, and sshd logged both the certificate and the bare key as revoked by the file. If the private key is compromised, revoke the public key (or rotate), not only one certificate serial.
Revoke an SSH certificate by serial number
You do not need the original certificate file if you know the CA public key and the serial. Write a one-line KRL specification:
printf 'serial: 1001\n' | sudo tee /tmp/revoke-serial.txt >/dev/nullBuild a KRL from that specification:
sudo ssh-keygen -k -f /tmp/krl-serial -s /etc/ssh/user_ca.pub /tmp/revoke-serial.txtRevoking from /tmp/revoke-serial.txtQuery the certificate that carried serial 1001:
ssh-keygen -Q -f /tmp/krl-serial /tmp/id_ed25519-cert.pub/tmp/id_ed25519-cert.pub (deepak@client): REVOKEDA different serial from the same CA stays valid against that KRL:
ssh-keygen -Q -f /tmp/krl-serial /tmp/id_ed25519_alt-cert.pub/tmp/id_ed25519_alt-cert.pub (deepak-alt@client): okSerial 0 cannot be used for this form. Assign non-zero 64-bit serials when you issue certificates you expect to manage centrally.
Revoke a range of certificate serials
For an incident window or a bad issuance batch, revoke a contiguous range:
printf 'serial: 1000-1099\n' | sudo tee /tmp/revoke-range.txt >/dev/nullMerge that range into the serial KRL:
sudo ssh-keygen -k -u -f /tmp/krl-serial -s /etc/ssh/user_ca.pub /tmp/revoke-range.txtRevoking from /tmp/revoke-range.txtSerial 1002 is now revoked as part of the range:
ssh-keygen -Q -f /tmp/krl-serial /tmp/id_ed25519_alt-cert.pub/tmp/id_ed25519_alt-cert.pub (deepak-alt@client): REVOKEDPractical uses:
- certificates issued during a bad deployment window
- a group of certificates issued during the same compromised or incorrect signing window
- retiring a reserved serial allocation range
Serial-based revocation is compact, which is one of the strongest reasons to assign meaningful non-zero serials at issue time.
Revoke certificates by Key ID
The certificate inspected earlier carried Key ID deepak-2026-01. Write that as a specification:
printf 'id: deepak-2026-01\n' | sudo tee /tmp/revoke-id.txt >/dev/nullBuild a KRL from the Key ID:
sudo ssh-keygen -k -f /tmp/krl-id -s /etc/ssh/user_ca.pub /tmp/revoke-id.txtRevoking from /tmp/revoke-id.txtThe matching certificate is revoked:
ssh-keygen -Q -f /tmp/krl-id /tmp/id_ed25519-cert.pub/tmp/id_ed25519-cert.pub (deepak@client): REVOKEDA certificate with a different Key ID is not:
ssh-keygen -Q -f /tmp/krl-id /tmp/id_ed25519_alt-cert.pub/tmp/id_ed25519_alt-cert.pub (deepak-alt@client): okSerial vs Key ID
| Method | Effect |
|---|---|
| Serial (or serial range) | Targets one certificate or a numeric range |
| Key ID | May revoke every certificate from that CA that carries the same Key ID |
Key IDs are useful for identities or issuance batches. Assign them consistently, and do not reuse one Key ID across unrelated certificates unless you intend a group revoke.
Revoke a key by SHA256 fingerprint
When logs only give you a fingerprint, start from the public key or from sshd output:
ssh-keygen -lf ~/.ssh/id_ed25519.pub256 SHA256:Dh0YicssAH/zkefNQQTmvkkw9FIGvSbijtaP3nx6RVU deepak@client (ED25519)Put that fingerprint into a hash: specification:
printf 'hash: SHA256:Dh0YicssAH/zkefNQQTmvkkw9FIGvSbijtaP3nx6RVU\n' | sudo tee /tmp/revoke-hash.txt >/dev/nullBuild the KRL (no -s is required for a plain-key hash revoke):
sudo ssh-keygen -k -f /tmp/krl-hash /tmp/revoke-hash.txtRevoking from /tmp/revoke-hash.txtQuery the public key:
ssh-keygen -Q -f /tmp/krl-hash /tmp/id_ed25519.pub/tmp/id_ed25519.pub (deepak@client): REVOKEDKRLs also support sha256: records. That directive takes a public key line; OpenSSH stores the SHA256 hash of that key in the KRL. Prefer hash: when all you already have is the fingerprint from logs. SHA1 forms exist for older compatibility; use SHA256 for new revocations.
KRL specification file reference
| Directive | Use |
|---|---|
serial: 1001 |
One certificate serial |
serial: 1000-1099 |
Inclusive serial range |
id: deepak-2026-01 |
Certificate Key ID |
key: ssh-ed25519 ... |
Explicit public key |
sha256: ssh-ed25519 AAAA... |
Supply a public key; the KRL stores its SHA256 hash |
hash: SHA256:... |
Supply an already-known fingerprint from logs or ssh-keygen -l |
serial: and id: require the issuing CA public key via -s. Plain-key forms do not.
Inspect a KRL
Current OpenSSH can dump a readable summary with -Q -l:
ssh-keygen -Q -l -f /etc/ssh/revoked_keysAfter I revoked both certificates and the plain public key, the dump looked like this:
# KRL version 0
# Generated at 20260922T154248
hash: SHA256:Dh0YicssAH/zkefNQQTmvkkw9FIGvSbijtaP3nx6RVU # ssh-ed25519
# CA key ssh-ed25519 SHA256:+axU8dFjZi4r2zKVN7n9jHJs+XaIvwS55hsp5eUhdhc
serial: 1001-1002That is enough to see which CA and serials are covered. The on-disk format remains a compact binary; do not expect a full pretty-print of every historical input file.
Revoke a compromised SSH CA
Revoking one certificate and removing the trusted CA public key are different incidents.
If the user CA private key is compromised:
- Stop trusting that CA: remove or replace it in
TrustedUserCAKeys. - Generate a new CA key pair.
- Distribute the new CA public key to every server.
- Reissue valid user certificates from the new CA.
- Optionally add the old CA public key itself to a KRL, depending on your trust model.
Do not try to enumerate every certificate ever issued by a compromised CA if you can remove the trusted CA public key from TrustedUserCAKeys. Removing that trust (sometimes called the trust anchor) is the cleaner incident response.
Revoke host keys and host certificates
Keep this short and separate from user login revocation.
RevokedKeyson the server rejects credentials presented for public-key authentication, including host certificates used in some host-based flows when they appear as authentication material.- On SSH clients, host-key KRLs are configured with
RevokedHostKeysinssh_config. That is separate from the server-sideRevokedKeysdirective used for user authentication.
Do not confuse deleting a line from ~/.ssh/known_hosts with KRL-based revocation. A compromised host certificate CA is primarily a client trust problem: rotate the host CA and update @cert-authority (or equivalent) trust, then reissue host certificates. For the full host-certificate path, stay with the certificate authentication guide rather than expanding this page into a second lab.
KRL vs certificate expiration
| Situation | Expiry | KRL |
|---|---|---|
| Normal short-lived user certificate | Best primary control | Usually unnecessary |
| Laptop stolen before expiry | Too slow | Revoke immediately |
| Wrong principal issued | Too slow | Revoke |
| Certificate already expired | Already invalid | No need |
| Private key compromise | Future certs must also be addressed | Revoke the key / rotate |
| CA compromise | Expiry of individual certs is insufficient | Remove the trusted CA public key and rotate |
Use short validity windows for routine access. Use a KRL when something must stop now.
KRL vs authorized_keys removal
Plain key on one server
Remove the line from:
~/.ssh/authorized_keysSame key trusted across many servers
Distribute one KRL (or remove the key from every copy of authorized_keys). The KRL path scales better when the change rate is high.
Environments that use SSH certificates across many servers
A KRL is the native OpenSSH emergency revocation mechanism. Pair it with short-lived certificates so most access ends without a revoke at all.
Distribute a KRL across multiple SSH servers
A KRL only works on hosts that have the updated file. Creating it on the CA machine does not push revocation to the fleet by itself.
High-level options:
- configuration management (Ansible, Puppet, Salt, and similar)
- a controlled
rsyncorscpfrom a single source of truth - packaging the KRL with your config deployment system
When you update the production KRL, generate the new file separately and replace /etc/ssh/revoked_keys atomically rather than editing the live file in place. OpenSSH may consult that path on each authentication attempt, so an in-place rewrite can race with a login. Stage the new content under a temporary name next to the live path:
sudo install -m 0644 /tmp/revoked_keys.new /etc/ssh/revoked_keys.newThen move it over the live name so the replace is a single rename:
sudo mv /etc/ssh/revoked_keys.new /etc/ssh/revoked_keysAfter the file lands, validate the configuration first:
sudo sshd -tA silent exit means the syntax check passed. Reload so workers pick up the new KRL contents if your distribution requires it after the replace:
sudo systemctl reload sshdKeep the CA private key off the SSH servers. The servers need the CA public key and the KRL, not the signing key.
Check KRL permissions and availability
Confirm the path RevokedKeys names is present and readable:
ls -l /etc/ssh/revoked_keys-rw-r--r--. 1 root root 186 Sep 22 15:43 /etc/ssh/revoked_keysRevokedKeys is set but the file cannot be read, sshd refuses public-key authentication for all users. Treat a missing or unreadable KRL as an outage risk, not a soft warning.
Keep a recovery session open (console or an already authenticated session) while you change RevokedKeys or replace the file.
Troubleshooting OpenSSH KRL
| Problem | Likely cause | Fix |
|---|---|---|
| Revoked certificate still works | RevokedKeys not configured or not reloaded |
Check sshd -T | grep revokedkeys, then reload |
| Second revocation removed the first | Recreated the KRL without -u |
Use ssh-keygen -k -u |
ssh-keygen -Q says not revoked |
Wrong KRL, wrong key, or different certificate | Inspect serial, Key ID, and CA with ssh-keygen -L |
serial: rule fails |
Serial is 0, or wrong CA passed with -s |
Use a non-zero serial and the issuing CA public key |
| KRL blocks all public-key login | File unreadable or path wrong | Fix path, mode, ownership, SELinux; keep a recovery session |
| Key ID revoke hits more certificates than expected | Same Key ID reused | Use unique Key IDs; prefer serials for one-off revokes |
| Certificate already expired | Expiry rejected it, not the KRL | Check validity with ssh-keygen -L |
| Login still succeeds with a password | Only the key or cert was revoked | Review enabled authentication methods |
Operational recommendations
- Assign non-zero certificate serial numbers at issue time.
- Use meaningful, deliberate Key IDs.
- Prefer short-lived certificates for routine access control.
- Use a KRL for emergency revocation.
- Always use
-uwhen updating an existing KRL. - Test every change with
ssh-keygen -Qbefore and after reload. - Distribute KRL updates consistently to every server that trusts the CA.
- Replace the live KRL atomically (
installto a temp name, thenmv) rather than editing it in place. - Protect the CA private key separately from the KRL distribution path.
- Keep a recovery session open while changing
sshdrevoke settings.
Summary
An OpenSSH KRL is a compact binary revoke list. You create it with ssh-keygen -k, merge more entries with ssh-keygen -k -u, test credentials with ssh-keygen -Q, and make sshd enforce the file through RevokedKeys.
The beginner path starts with a real certificate file, then moves to specification directives: serial, serial range, Key ID, fingerprint, and plain public key. Serial-based revocation is especially efficient, which is why managed environments should issue non-zero serials instead of leaving -z unused.
The two operational mistakes that hurt most are recreating a KRL without -u (you drop earlier revocations) and pointing RevokedKeys at a missing or unreadable file (public-key authentication fails for everyone). Short-lived certificates reduce how often you need revocation. Use a KRL when access must stop before the certificate expires, after theft, or after a wrong principal. For CA compromise, remove the trusted CA public key and rotate rather than trying to list every old serial.
References
- ssh-keygen(1) — KEY REVOCATION LISTS — KRL create (
-k), update (-u), query (-Q), and specification directives - sshd_config(5) — RevokedKeys — server enforcement and the unreadable-file failure mode
- ssh_config(5) — RevokedHostKeys — client-side host-key and host-certificate KRL
- OpenSSH Portable release notes — version history for KRL and fingerprint hash support
Frequently Asked Questions
What is an OpenSSH KRL?
A Key Revocation List is a compact binary file that lists SSH public keys and certificates OpenSSH must refuse. You build it with ssh-keygen and point sshd at it with RevokedKeys.
How do I revoke an SSH certificate?
Create or update a KRL with ssh-keygen -k (add -u to merge), supplying the CA public key with -s and either the certificate file or a serial:/id: specification. Configure RevokedKeys, run sshd -t, reload sshd, and confirm with ssh-keygen -Q plus a failed login and the revoked-by-file journal line.
How do I revoke a normal SSH public key?
When a live KRL already exists, merge with ssh-keygen -k -u and the .pub file. Use ssh-keygen -k only when creating a new KRL on a separate path. You can also use a hash: SHA256 fingerprint specification when you only have the fingerprint from logs. Revoking the underlying public key also blocks certificates that wrap that same key.
What is the difference between ssh-keygen -k and -k -u?
ssh-keygen -k creates a new KRL. ssh-keygen -k -u merges new revocations into an existing KRL. Re-running -k without -u against the same path can replace the file and lose earlier entries.
Can I revoke an SSH certificate by serial number?
Yes. Put serial: 1001 in a specification file, pass -s with the issuing CA public key, and build or update the KRL. Serial 0 cannot be used for serial-based revocation, so issue non-zero serials when you plan to manage certificates centrally.
Can I revoke multiple SSH certificates at once?
Yes. Merge several certificate files with -u, or revoke a serial range such as serial: 1000-1099. Key ID revocation can also hit every certificate from that CA that shares the same Key ID.
What happens if the RevokedKeys file is missing or unreadable?
sshd refuses public-key authentication for all users until the path is readable again. Fix permissions and path before enabling RevokedKeys in production, and keep a recovery session open while you change it.
Does deleting a certificate from the client revoke it?
No. Removing the certificate file from the client only stops that client from presenting it. Any copy of the private key plus certificate still works until expiry or until servers enforce a KRL (or stop trusting the CA).
Should I use certificate expiry or a KRL?
Use short expiry as the everyday control. Use a KRL when access must stop immediately, when a wrong principal was issued, or when a private key is compromised before the certificate would have expired.
How do I revoke a compromised SSH CA?
Remove or replace the CA in TrustedUserCAKeys, generate a new CA, distribute the new CA public key, and reissue valid certificates. Enumerating every old serial is usually worse than removing the trusted CA public key. Optionally revoke the old CA public key itself in a KRL depending on your trust model.

