/commands/ssh-protocol/create-ssh-user-certificate
ssh-keygen -s ca -I id -n user key.pub: create an SSH user certificate
- tool
- SSH protocol
- versions
- OpenSSH 5.4+ (certificates), OpenSSH 10.x
- os
- linux, macos, windows
ssh-keygen -s user_ca -I alice@example -n alice -V +52w alice.pub signs Alice's public key with a certificate authority key and writes alice-cert.pub. A server that lists the CA's public key in TrustedUserCAKeys then accepts that certificate for the principals named with -n (here the Unix user alice), until the validity period ends. No authorized_keys entry per user is needed.
Sign a key and inspect the certificate
ssh-keygen -q -t ed25519 -N '' -C 'user CA' -f user_ca
ssh-keygen -q -t ed25519 -N '' -C alice@laptop -f alice
ssh-keygen -s user_ca -I alice@example -n alice,deploy -V 20260101000000Z:20270101000000Z -z 42 alice.pub 2>&1 \
| sed 's/ valid from.*//'
TZ=UTC ssh-keygen -L -f alice-cert.pub | grep -v SHA256Output
Signed user key alice-cert.pub: id "alice@example" serial 42 for alice,deploy
alice-cert.pub:
Type: ssh-ed25519-cert-v01@openssh.com user certificate
Key ID: "alice@example"
Serial: 42
Valid: from 2026-01-01T00:00:00 to 2027-01-01T00:00:00
Principals:
alice
deploy
Critical Options: (none)
Extensions:
permit-X11-forwarding
permit-agent-forwarding
permit-port-forwarding
permit-pty
permit-user-rc-V with two absolute UTC times keeps the example reproducible; in practice relative values such as -V +8h or -V -5m:+52w are common. ssh-keygen -L prints the times in the local time zone, hence TZ=UTC.
Options
| Option | Meaning |
|---|---|
| -s CA_KEY | Private key of the certificate authority that signs. |
| -I KEY_ID | Free-form identity, written to the server log when the certificate is used. |
| -n alice,deploy | Principals: user names (or host names with -h) the certificate is valid for. |
| -V +52w | Validity interval: absolute YYYYMMDD[HHMM[SS]] times (Z suffix for UTC), relative -/+ times, or always and forever. |
| -z 42 | Serial number, used by revocation lists. |
| -h | Create a host certificate instead of a user certificate. |
| -O source-address=10.0.0.0/8 | Restrict where the certificate may be used from; other -O options remove forwarding rights. |
| -L -f FILE-cert.pub | Print the contents of a certificate. |
By default a user certificate gets the extensions permit-X11-forwarding, permit-agent-forwarding, permit-port-forwarding, permit-pty and permit-user-rc, as the output shows. -O clear removes them all; -O permit-pty adds back only what you list.
Trust the CA on the server
# on the server, as root
cp user_ca.pub /etc/ssh/user_ca.pub
echo 'TrustedUserCAKeys /etc/ssh/user_ca.pub' >> /etc/ssh/sshd_config
sshd -t && systemctl reload sshd # the unit is called ssh on Debian and UbuntuPitfalls
- A login that fails with
Permission denied (publickey)while the certificate is offered usually means the principal does not match the target user, or the certificate has expired; the server log (journalctl -u sshor/var/log/auth.log) names the reason. - Clocks matter: a certificate valid from "now" can be rejected by a server whose clock is behind. Start the interval a few minutes in the past (
-V -5m:+8h). - Host certificates (
-h) are trusted by clients through a@cert-authorityline inknown_hosts, which removes the first-connection fingerprint prompt.
FAQ
Does the user need anything besides the -cert.pub file?
No. Keep id_ed25519-cert.pub next to id_ed25519 and ssh offers the certificate automatically. If the files live elsewhere, point to it with CertificateFile in ~/.ssh/config or -o CertificateFile=PATH.
How do I revoke a certificate before it expires?
Add its serial number or key ID to a key revocation list with ssh-keygen -k, and set RevokedKeys in sshd_config to that file. Short validity periods reduce the need for revocation.
What happens if I leave out -n?
The certificate is signed without a list of principals. sshd does not accept such certificates for logins through TrustedUserCAKeys, so the login fails. Always set -n for user certificates.