An SSH public key added to authorized_keys grants access until somebody remembers to remove it. On a fleet of any size nobody does, so servers collect keys that belong to people who left, laptops that were replaced and pipelines that no longer exist. OpenSSH has had a better mechanism for years: certificates signed by an authority, valid for minutes.
What goes wrong with static keys
A plain SSH key pair has no expiry, no owner field and no link to your directory. The server only knows that a public key appears in a file.
- Offboarding depends on memory. Removing a person means finding every host and every account where their key was pasted.
- Keys are copied. A private key on a laptop is also in its backups, and sometimes in a chat message from the day somebody needed access quickly.
- Audit is weak. A log line that says a key fingerprint logged in as
ubuntudoes not say which person that was. - Access is all or nothing. The key either works on a host or does not. It carries no conditions.
Certificates remove the problem instead of managing it.
How OpenSSH certificates work
An OpenSSH certificate is a public key plus a set of statements about it, signed by a certificate authority (CA). It is OpenSSH's own format, not X.509. The CA is simply another SSH key pair whose public half the servers are told to trust.
A user certificate contains:
- the user's public key
- a key ID, a free-text label that
sshdwrites to its log on every login - a serial number
- a list of principals, the names this certificate may log in as
- a validity window, with a start and an end time
- critical options, such as
force-commandandsource-address - extensions, such as
permit-ptyandpermit-port-forwarding
When a client presents a certificate, the server checks that it was signed by a trusted CA, that the current time falls inside the validity window and that one of the principals is allowed for the account being requested. No per-user file on the host is consulted.
A worked example
Create a CA key, then sign a user's public key for five minutes:
# once: create the certificate authority
ssh-keygen -t ed25519 -f user_ca -C "user CA"
# per session: sign alice's public key
ssh-keygen -s user_ca \
-I "alice@example.com" \
-n deploy,readonly \
-V +5m \
-z 1042 \
alice_key.pubThis writes alice_key-cert.pub. On each server, trust the CA once:
# /etc/ssh/sshd_config
TrustedUserCAKeys /etc/ssh/user_ca.pub
AuthorizedPrincipalsFile /etc/ssh/principals/%uWith /etc/ssh/principals/deploy containing the line deploy, a certificate that lists the principal deploy may log in to the deploy account. Alice's own key never appears on the host.
The certificate authority
The CA private key is now the thing to protect. Whoever holds it can mint access to every server that trusts it, so it should not sit on a laptop or a jump host.
In practice the CA sits behind a signing service. The service authenticates the person, checks what they are entitled to, signs a certificate for exactly that and records the act. Engineers never see the CA key and never run ssh-keygen -s themselves.
Two further points:
- Use separate CAs for users and hosts. A user CA signs people in. A host CA signs each server's host key, so clients can verify servers with one
@cert-authorityline inknown_hostsinstead of trusting on first use. - Plan for the CA's own lifetime. Replacing a CA means updating
TrustedUserCAKeyson every host.sshdaccepts several CA keys in that file, so old and new can overlap during a change.
Principals and expiry
Principals
Principals are how a certificate expresses what it is for. You can use account names directly, or treat principals as roles (db-admin, web-readonly) and map them to local accounts in the principals files on each host. The second approach keeps your directory groups and your server accounts loosely coupled: the signing service turns a group into a principal, and each host decides which accounts that principal reaches.
Expiry
The validity window is the feature that changes the security model. A certificate valid for minutes covers the moment of connection. An established session continues after the certificate expires, because the check happens at authentication, but nobody can open a new one with it.
Short expiry also changes how revocation works. OpenSSH supports key revocation lists through the RevokedKeys option, but a list has to reach every host to matter. If certificates last a few minutes, there is very little to revoke. Stopping issuance is enough, and the exposure after a stolen laptop is bounded by the lifetime you chose.
The practical requirement is that hosts keep reasonably accurate clocks, because validity is checked against local time.
What it does for offboarding and audit
Offboarding becomes a directory change. Access is granted at signing time, from current group membership. Remove a person from the group and the next request for a certificate is refused. There is nothing on any host to clean up, because nothing about that person was ever stored there.
Audit gains a name. sshd logs the certificate's key ID and serial at login. If the signing service sets the key ID to the person's identity, every server's log states who connected. The signing service holds the other half of the record: who asked, for which target, when, and whether it was granted.
Rolling it out
- Stand up the CA behind a signing service and distribute its public key to a few hosts.
- Add
TrustedUserCAKeysalongside existingauthorized_keys. Both methods work during migration. - Move teams to certificates one group at a time.
- Remove the old
authorized_keysentries, and alert on any that reappear. - Keep a documented break-glass path for when the signing service is unreachable, and test it.
How AuthFI does it
AuthFI issues SSH certificates as part of its server access. Each project has its own SSH authority, held in the project's key service as described in why every secret key lives in one place. A server trusts that one authority, not a list of keys.
A person who has been granted access to a target receives a certificate for one session, valid for five minutes. Access follows the same groups as applications and cloud roles, so removing someone from a group removes their server access too. A target with no grants refuses everyone.
There is deliberately no revoke action for a session certificate: the short life is the revocation. Every session is recorded as an event on the project's audit record.
Rules for privileged commands on the host (allow, refuse, or allow after a fresh second step) and session recording are in pilot. The console states, per host, whether a rule is actually enforced there. The current status of each part is on the apps and cloud access page.
Key takeaways
- A static SSH key has no expiry and no owner. A certificate has both, plus the names it may log in as.
- Servers trust one CA public key. Nothing about an individual user is stored on the host.
- Protect the CA by putting it behind a signing service that checks entitlement and records every signature.
- With lifetimes of minutes, offboarding is a group change and revocation lists stop being the main control.
- Set the key ID to the person's identity so every server log names who connected.



