You have forty devices in the field, three people who need shell access, and an authorized_keys file on every one of them. Someone leaves, and you get to touch forty files. Someone gets a new laptop, and you get to touch forty files again. A device gets reflashed, and everyone's terminal shouts that the host key changed.

SSH certificate authentication fixes both directions of that problem with tools you already have. One CA key signs user keys, every server trusts that one CA, and a second CA signs host keys so clients stop asking "are you sure you want to continue connecting?". No extra daemon, no vendor, just ssh-keygen and two lines of sshd_config.

This guide is the hands-on version. If you're still deciding whether certificates are worth it for your team, read SSH certificate authorities vs public key auth for teams first. Every command below was run against OpenSSH 9.6 while writing this.

Quick Summary: What You'll Learn

  • How SSH certificate authentication works, in one paragraph.
  • How to create a user CA and sign a short-lived user certificate with ssh-keygen -s.
  • How to make sshd trust the CA with TrustedUserCAKeys and map roles with AuthorizedPrincipalsFile.
  • How host certificates replace the trust-on-first-use prompt with one @cert-authority line.
  • What "Certificate invalid: name is not a listed principal" means, in both places it shows up.
  • How to revoke a certificate early with a KRL, and how to roll this out without locking yourself out.

How does SSH certificate authentication work?

A user still has a normal key pair. Instead of copying the public key to every server, you sign it with a CA key. The signature produces a third file, id_ed25519-cert.pub, which contains the user's public key plus metadata: a key ID, a serial number, a list of principals (the account or role names it is valid for), a validity window and a set of permissions.

The server holds only the CA's public key. When a user connects with a certificate, sshd checks three things: the CA signature is valid, the certificate is inside its validity window, and one of its principals is allowed for the account being logged into. If all three pass, the user is in. No authorized_keys entry is involved.

Host certificates are the same idea in reverse. A host CA signs each server's host key, and clients trust the host CA instead of remembering individual host keys in known_hosts.

OpenSSH certificates are not X.509. The ssh-keygen man page calls them "a different, and much simpler, format". You don't need OpenSSL, a PKI team or a CRL server.

What do you need before you start?

  • OpenSSH on clients and servers. Certificate support has been in OpenSSH for well over a decade, so any supported distro is fine.
  • A machine to hold the CA private keys. Treat it like a root password: ideally offline or a locked-down signing host, never a server in the fleet.
  • A naming plan for principals. Principals are just strings. Roles work better than people: fleet-ops, deploy, readonly. You decide on each server which roles may log into which account.
  • One SSH session left open on a test server while you change sshd_config. You will want it if something goes wrong.

How do you create the SSH certificate authority keys?

Create two CA keys, one for users and one for hosts. Keeping them separate means a leak of one doesn't let an attacker forge the other kind of certificate.

ssh-keygen -t ed25519 -f user_ca -C "user-ca 2026" ssh-keygen -t ed25519 -f host_ca -C "host-ca 2026" 

Give both a strong passphrase when prompted. You now have user_ca and host_ca (private, stay on the signing machine) and user_ca.pub and host_ca.pub (public, go to servers and clients).

Ed25519 is a sensible default for a new CA. If you have very old devices that only understand RSA, check what they support before you pick; a CA nobody can verify is not much use.

How do you sign a user certificate with ssh-keygen -s?

The user generates a key pair as usual and sends you only the .pub file. You sign it:

ssh-keygen -s user_ca \ -I ops-laptop-03 \ -n fleet-ops,deploy \ -V -5m:+8h \ -z 1042 \ ops_key.pub 

What each flag does, per the ssh-keygen man page:

  • -s user_ca: sign with this CA private key.
  • -I ops-laptop-03: the key ID. It is written to the server's auth log on every login and can be used to revoke the certificate. Make it something you can trace back to a device or a request.
  • -n fleet-ops,deploy: the principals. Without at least one principal, sshd refuses the certificate when it is trusted via TrustedUserCAKeys.
  • -V -5m:+8h: valid from five minutes ago until eight hours from now. The five-minute back-dating absorbs small clock drift between the signing machine and your devices.
  • -z 1042: a serial number. It defaults to zero, so set it yourself; serials make revocation precise.

The result is ops_key-cert.pub, next to the key. Inspect any certificate with ssh-keygen -L:

$ ssh-keygen -L -f ops_key-cert.pub ops_key-cert.pub: Type: ssh-ed25519-cert-v01@openssh.com user certificate Public key: ED25519-CERT SHA256:ohGkf96o... Signing CA: ED25519 SHA256:msQOMhsA... (using ssh-ed25519) Key ID: "ops-laptop-03" Serial: 1042 Valid: from 2026-10-20T20:57:52 to 2026-10-21T05:02:52 Principals: fleet-ops deploy Critical Options: (none) Extensions: permit-X11-forwarding permit-agent-forwarding permit-port-forwarding permit-pty permit-user-rc 

Can you restrict what a certificate is allowed to do?

Yes, with -O. By default a user certificate permits X11 forwarding, agent forwarding, port forwarding, a PTY and ~/.ssh/rc. For a tighter certificate, clear everything and add back what you need:

ssh-keygen -s user_ca -I ops-laptop-03 -n fleet-ops -V +8h \ -O clear -O permit-pty ops_key.pub 

Two critical options are worth knowing for automation:

  • -O source-address=10.0.0.0/8: the certificate only works from these CIDR ranges.
  • -O force-command=/usr/local/bin/backup.sh: whatever the client asks for, this command runs instead. Useful for a backup job's certificate.

Order matters with clear: put it before the permit-* options, or it wipes them.

How do you configure sshd to trust the CA?

Copy user_ca.pub to each server and add this to /etc/ssh/sshd_config:

TrustedUserCAKeys /etc/ssh/user_ca.pub AuthorizedPrincipalsFile /etc/ssh/auth_principals/%u 

TrustedUserCAKeys tells sshd which CAs may sign user certificates. The file can hold more than one CA public key, one per line, which you will need when you rotate the CA.

AuthorizedPrincipalsFile maps principals to local accounts. %u expands to the username being logged into, so the file for the ops account is /etc/ssh/auth_principals/ops:

fleet-ops deploy 

Any certificate carrying fleet-ops or deploy as a principal can now log in as ops. Without an AuthorizedPrincipalsFile, the rule is stricter and less flexible: the certificate must list the literal username as a principal. That works for a single account, but role names scale better across a fleet where every device has the same ops and deploy users.

Validate the config before reloading, from the session you kept open:

sudo sshd -t && sudo systemctl reload ssh 

The service is called ssh on Debian and Ubuntu and sshd on most other distros. Now open a second terminal and log in. Don't close the first one until the second works.

How does the client use the certificate?

Mostly, it just works. If the certificate sits next to the key with the -cert.pub suffix, ssh loads it automatically for any IdentityFile you use. You can also point at it explicitly in ~/.ssh/config:

Host *.fleet.example.com User ops IdentityFile ~/.ssh/ops_key CertificateFile ~/.ssh/ops_key-cert.pub 

If you use ssh-agent, ssh-add picks up the certificate along with the key:

$ ssh-add ~/.ssh/ops_key Identity added: /home/you/.ssh/ops_key (ops-laptop) Certificate added: /home/you/.ssh/ops_key-cert.pub (ops-laptop-03) 

When an eight-hour certificate expires, the key is still fine. The user gets a fresh signature and carries on. That renewal step is the part teams usually automate later, with a small signing service or a tool like step-ca, which the comparison post walks through.

How do host certificates get rid of the "authenticity of host" prompt?

On each device, sign its existing host public key with the host CA. Note the -h flag, which makes it a host certificate:

ssh-keygen -s host_ca \ -I device-042 \ -h \ -n device-042.fleet.example.com,10.20.0.42 \ -V +52w \ /etc/ssh/ssh_host_ed25519_key.pub 

For host certificates, principals are the names clients will connect with: hostnames and IPs. Then tell sshd to present it:

HostCertificate /etc/ssh/ssh_host_ed25519_key-cert.pub 

On every client, one line in ~/.ssh/known_hosts (or /etc/ssh/ssh_known_hosts for all users) replaces forty individual entries:

@cert-authority *.fleet.example.com,10.20.0.* ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAA... host-ca 2026 

Now a reflashed device with a new host key and a fresh certificate connects without a warning, and an impostor without a valid certificate still fails. If you want the background on why that first-connection prompt exists at all, see SSH host key verification explained.

Why does SSH say "Certificate invalid: name is not a listed principal"?

This message shows up in two different places, and they mean different things.

On the client, before login. The server presented a host certificate, but the name you typed isn't one of its principals. You signed the cert for device-042.fleet.example.com and connected to device-042 or to an IP you didn't list. OpenSSH prints the error and falls back to normal host key checking, so you get the old trust-on-first-use prompt again (or "Host key verification failed" if StrictHostKeyChecking is on). Fix: re-sign the host key with every name people actually use in -n.

In the server's auth log. The user certificate's principals don't include the account name, and there's no AuthorizedPrincipalsFile to map them. The client sees only Permission denied (publickey). Fix: add the username to the certificate's principals, or set up a principals file for that account.

If you do use an AuthorizedPrincipalsFile, the server-side wording changes. A certificate whose principals aren't in the file is logged as Certificate does not contain an authorized principal. Check the file for the account you're logging into, and check for typos; principals are exact string matches.

Two quick ways to see what's going on:

ssh-keygen -L -f ~/.ssh/ops_key-cert.pub # what the cert actually says ssh -v ops@device-042.fleet.example.com # which cert the client offers 

How do you revoke an SSH certificate before it expires?

Short validity is your first line of defense: an eight-hour certificate that leaks is useless by tomorrow. For anything longer lived, or when you can't wait, use a Key Revocation List (KRL).

Write a small spec file:

serial: 1042 id: ops-laptop-03 

Generate the KRL with the CA public key:

ssh-keygen -k -f revoked.krl -s user_ca.pub krl.spec 

To add more entries later, use -u to update instead of replacing. To check whether a given certificate is revoked, -Q exits non-zero if it is:

ssh-keygen -Q -f revoked.krl ops_key-cert.pub 

Distribute revoked.krl to every server and reference it:

RevokedKeys /etc/ssh/revoked.krl 

One warning from the sshd_config man page: if the RevokedKeys file is not readable, public key authentication is refused for all users. Deploy the file before the config line, and keep its permissions right.

How do you roll SSH certificates out to a fleet without locking yourself out?

Do it in an order where every step is reversible:

  • Push user_ca.pub, the principals files and the two sshd_config lines to a handful of devices. Leave authorized_keys alone. Both methods now work side by side.
  • Issue certificates to the people who need access and confirm they can log in with the certificate alone (ssh -o IdentitiesOnly=yes -i ~/.ssh/ops_key ... with no matching authorized_keys entry).
  • Roll the same config to the rest of the fleet with whatever you already use: Ansible, your image build, cloud-init.
  • Only then remove the old public keys from authorized_keys. Keep one break-glass key, stored offline, for the day the CA machine is unavailable.

For CA rotation later: add the new CA public key as a second line in TrustedUserCAKeys, start signing with the new CA, wait until every old certificate has expired, then remove the old line. With short-lived certificates, that wait is hours, not months. The same overlap pattern is covered in more detail in SSH key rotation best practices.

When is an SSH certificate setup overkill?

Honestly, for a lot of people. If you have five servers and two people, a well-kept authorized_keys and one key per device is fewer moving parts than a CA. You also take on new responsibilities: protecting the CA key, keeping clocks roughly in sync across the fleet (validity checks depend on it), and building a renewal habit so nobody is locked out at 2 AM because their certificate expired at midnight.

Certificates start paying off when one of these is true: the number of devices grows faster than you can edit files, people join and leave regularly, devices get reflashed often, or an auditor wants to know who logged in where. That last one is a quiet win: every login logs the key ID and serial, so "which certificate was used" is in the auth log by default. For the broader picture of team access, SSH key management for teams covers the options side by side.

Where does termique fit?

termique is a desktop and mobile SSH manager, so it sits on the client side of this picture, not the CA side. Its documentation covers key-pair authentication: generating ed25519 or RSA keys, importing existing keys in PEM or OpenSSH format, and storing private keys encrypted on your device before anything syncs. The docs don't describe certificate support, so for logins that depend on a -cert.pub file, use OpenSSH directly as shown above.

Where it helps around a certificate rollout:

  • A single host list with groups, synced across your devices. Free covers 3 hosts; a whole fleet needs Pro, which removes the host cap.
  • Keys and passwords for the hosts still on plain key auth, including your break-glass key, encrypted end to end so the sync server only stores ciphertext. Host entries, groups and snippets sync as plaintext metadata; the security page spells out exactly what is and isn't encrypted.
  • Per-host command logs on Pro, which pair well with the key ID in sshd's auth log when you need to answer "who ran what". The post on per-command audit logs for shared SSH access explains how that works.

Keep the CA private keys out of every day-to-day tool, termique included. They belong on the signing machine and nowhere else.

FAQ

What is the difference between an SSH certificate and an SSH key?

An SSH key is a key pair the server trusts because its public half is listed in authorized_keys. An SSH certificate is that same public key plus a CA signature, principals, a validity window and permissions. The server trusts the CA instead of each key, so adding or removing a user no longer means editing every server.

How long should an SSH user certificate be valid?

As short as your renewal process allows. A working day (-V -5m:+8h) is a common choice for people, because a stolen certificate expires before most incidents are even noticed. Automation that can renew itself can go shorter. Long-lived user certificates bring back the revocation problem certificates were meant to solve.

Do SSH certificates work with ssh-agent?

Yes. When you run ssh-add on a key that has a matching -cert.pub file next to it, the agent loads both, and ssh-add -l lists the key and the certificate as separate entries.

Can one certificate log into different usernames on different servers?

Yes, that's what principals plus AuthorizedPrincipalsFile are for. Give the certificate a role principal like fleet-ops, then list fleet-ops in /etc/ssh/auth_principals/ops on the devices where that role should be able to log in as ops.

Do I need step-ca or Vault to use SSH certificates?

No. Everything in this guide uses ssh-keygen and sshd alone. Tools like step-ca or Vault add automated issuance, short-lived certificates through SSO and an API, which matter once manual signing becomes a bottleneck.

Try termique

Certificates handle trust for the fleet. You still need a sane way to keep track of hosts, the keys that remain and what was run where. termique is a free, native SSH manager with end-to-end encrypted credentials, on desktop and mobile. Download termique and add your first hosts.