networking · difficulty ◆◆
ssh-keygen — keys, fingerprints and 10-minute access
One binary for keys, fingerprints, host-key resets and short-lived certificates.
The fingerprint next to your key is a tiny ASCII cathedral — and reading it out loud once is how you beat the most common SSH attack.
fully AI-generatedThis text is fully AI-generated and was published without human editorial review.$ ssh-keygenTwo files, one direction
ssh-keygen writes a keypair: a private key (id_ed25519) and a public key (id_ed25519.pub). The public one is a padlock — paste it in tickets, chat, cloud consoles, anywhere. The private one is the key itself and never travels: whoever holds the file is you. That asymmetry is the whole design, and it is also why most "Permission denied (publickey)" failures are simply file modes: ~/.ssh wants 700, the private key wants 600, and sshd quietly refuses an authorized_keys file that group or others can write.
Comments are for future you
If you don't pass -C, ssh-keygen signs the key with user@host — on this box, literally kmail@nuc. Fast-forward a year: that machine is retired, you have three identical-looking keys and a wall of ssh-ed25519 AAAAC3Nza... lines. The comment is the only human-readable field in the file, so write one that still means something after the hardware is gone — host, role, or the app that owns the key.
Certificates instead of more keys
Copying a key onto every box doesn't scale and can't be revoked: removing access means finding every authorized_keys that trusts it. ssh-keygen can instead sign a user's existing key with a CA, binding principals and a validity window into a certificate file (id_ed25519-cert.pub). sshd trusts the CA once via TrustedUserCAKeys, and access expires on its own — no cleanup round, no orphaned keys. -V +10m is not a typo; ten minutes is a normal number here.
Example
$ ssh-keygen -t ed25519 -C "kmail@bev" -f ./id_ed25519_kmail -N ""Generating public/private ed25519 key pair.
Your identification has been saved in ./id_ed25519_kmail
Your public key has been saved in ./id_ed25519_kmail.pub
The key fingerprint is:
SHA256:/v8qZ+cSMBKRwsV3TqmaJqW70wUjg7YDmuBHPbLOHyE kmail@bev
The key's randomart image is:
+--[ED25519 256]--+
| . ooo . |
| o + . + |
| .. . o = |
|. .oooo = + . |
|oo.Eoo.=S* o |
|o. o+ +.+ . . |
| + o =.. . |
| o + ... + . |
| ...o .=o*o |
+----[SHA256]-----+-N "" means no passphrase: correct for a deploy key that lives in a secret store and gets used by CI, wrong for the key on your laptop. The comment is the -C value; omit -C and user@host sticks to the key forever.
$ ssh-keygen -lvf ./id_ed25519_kmail.pub256 SHA256:/v8qZ+cSMBKRwsV3TqmaJqW70wUjg7YDmuBHPbLOHyE kmail@bev (ED25519)
+--[ED25519 256]--+
| . ooo . |
| o + . + |
| .. . o = |
|. .oooo = + . |
|oo.Eoo.=S* o |
|o. o+ +.+ . . |
| + o =.. . |
| o + ... + . |
| ...o .=o*o |
+----[SHA256]-----+-l prints the fingerprint (bits, then base64), -v adds the randomart. It reads only the public half, so this is the line that is safe to read out loud when verifying a key over the phone.
$ ssh -o UserKnownHostsFile=./kh -o StrictHostKeyChecking=yes deploy@127.0.0.1@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
It is also possible that a host key has just been changed.
The fingerprint for the ED25519 key sent by the remote host is
SHA256:tA4bluLZyLcWHo/d1BZ5nJ2/z7IVjFJbRvZxZ6XwsQ4.
Please contact your system administrator.
Add correct host key in ./kh to get rid of this message.
Offending ED25519 key in ./kh:1
remove with:
ssh-keygen -f './kh' -R '127.0.0.1'
Host key for 127.0.0.1 has changed and you have requested strict checking.
Host key verification failed.Captured verbatim on this box against a scratch known_hosts (hence ./kh); on a normal machine the same banner names /home/you/.ssh/known_hosts and the line number of the offending entry. This is what you see after a VM is rebuilt — or after a real man-in-the-middle. Find out which one before you continue.
$ ssh-keygen -f ./kh -R 127.0.0.1# Host 127.0.0.1 found: line 1
./kh updated.
Original contents retained as ./kh.oldThe remedy ssh itself recommends. -R drops the stale entry and leaves a known_hosts.old backup, so a mistake is recoverable — but only run it once you have confirmed out of band that the host really was reinstalled.
$ ssh-keygen -A -f ./image-root
ls ./image-root/etc/ssh/ssh-keygen: generating new host keys: RSA ECDSA ED25519
ssh_host_ecdsa_key
ssh_host_ecdsa_key.pub
ssh_host_ed25519_key
ssh_host_ed25519_key.pub
ssh_host_rsa_key
ssh_host_rsa_key.pub-A generates every missing host-key type and skips the ones that already exist, which is why it is the standard first-boot step. With -f it works against a build root instead of /etc/ssh — handy for baking host keys into a container image. Note the missing DSA: only RSA, ECDSA and ED25519 are offered here.
$ ssh-keygen -s ./ca -I deploy-2026-10-17 -n deploy,kmail -V +10m ./id_ed25519_kmail.pub
ssh-keygen -Lf ./id_ed25519_kmail-cert.pubSigned user key ./id_ed25519_kmail-cert.pub: id "deploy-2026-10-17" serial 0 for deploy,kmail valid from 2026-10-17T09:01:00 to 2026-10-17T09:12:28
./id_ed25519_kmail-cert.pub:
Type: ssh-ed25519-cert-v01@openssh.com user certificate
Public key: ED25519-CERT SHA256:/v8qZ+cSMBKRwsV3TqmaJqW70wUjg7YDmuBHPbLOHyE
Signing CA: ED25519 SHA256:HLPkDP/2Jx/JPoVncsPnfuOhDfVxKmKZnKgmiu6RXuk (using ssh-ed25519)
Key ID: "deploy-2026-10-17"
Serial: 0
Valid: from 2026-10-17T09:01:00 to 2026-10-17T09:12:28
Principals:
deploy
kmail
Critical Options: (none)
Extensions:
permit-X11-forwarding
permit-agent-forwarding
permit-port-forwarding
permit-pty
permit-user-rcA CA key (./ca) signs the user's own public key rather than issuing a new one: the private key never moves, and the certificate is what carries the scope. -I is the Key ID that shows up in auth logs, -n the principals it is valid as, -V the window. -L is how you audit a certificate someone hands you before trusting it.
$ cp ./id_ed25519_kmail ./id_pass && chmod 600 ./id_pass && ssh-keygen -p -f ./id_pass -P "" -N "s3cret"Key has comment 'kmail@bev'
Your identification has been saved with the new passphrase.Adds a passphrase to a key that had none, or rotates an existing one, without regenerating the key — the public half, authorized_keys and every server that trusts it stay valid. Drop -P/-N to get interactive prompts instead of secrets in shell history.
Common flags
- -t ed25519
- Key type. On this OpenSSH 9.6 build a bare ssh-keygen with no -t already produces ed25519, and that stays the right answer: compact keys, no weak parameters to tune.
- -b 3072
- Key size, only meaningful for RSA. Plain -t rsa without -b gave 3072 bits here — never go back to 1024, and prefer ed25519 unless a legacy peer forces RSA.
- -f path
- Where to write the keypair. Also what makes the run non-interactive, and the reason ssh-keygen refuses to clobber an existing key instead of quietly overwriting it.
- -C comment
- Free-text comment baked into the key, defaulting to user@host. It shows up in -l output and in every authorized_keys line — write something that ages well.
- -l
- Print the fingerprint of a public key or certificate file. Add -v for randomart, -f for the file path, -L to dump the full contents of a certificate.
- -R host
- Remove a host's entry from known_hosts, e.g. ssh-keygen -R 192.168.1.13. Prints the line numbers it removed and keeps known_hosts.old as a backup.
- -A
- Generate missing host-key types (here RSA, ECDSA, ED25519) and leave existing ones untouched. -f points the whole operation at a build root rather than /etc/ssh.
- -p
- Change the passphrase of an existing private key in place. Non-interactive as -P old -N new, with the caveat that those values end up in shell history.
History
A sniffer in Helsinki, 1995
Tatu Ylönen wrote the first SSH in 1995 after a password-sniffing attack on the network at Helsinki University of Technology — telnet and rlogin sessions were handing out credentials in plaintext. ssh-keygen shipped inside that first release as the key-management half of the idea. The licence tightened later, so in December 1999 the OpenBSD team forked the last freely licensed version (1.2.12) into OpenSSH, and that fork is the ssh-keygen running on this machine.
The Debian bug that shrank the keyspace to 32,767
In 2006 a patch in Debian's OpenSSL package deleted the lines that fed uninitialised memory into the PRNG, purely to silence valgrind warnings. The effect was catastrophic: the only remaining seed was the process ID, so every key generated on affected Debian and Ubuntu systems had roughly 32,767 possible values per key type. Luciano Bello spotted it in May 2008 (DSA-1571-1), a blacklist shipped, and everyone on those systems had to regenerate every key they owned. Two removed lines, two years of silently guessable keys.
Fun facts
Pros & cons
pros
- + One binary does key generation, fingerprints, host-key surgery and certificate signing — nothing to install and no daemon to babysit.
- + An ed25519 public key is about 68 characters of base64, so it survives copy-paste through chat clients, tickets and web consoles.
- + Certificates bound to principals and a validity window replace the copy-a-key-per-host ritual, and expire without a cleanup round.
cons
- − The host-key-changed banner ships with its own ready-made fix, which trains people to run -R without first asking what actually happened.
- − Passphrase handling on the command line leaks into shell history and process listings in a way file permissions never will.
- − A plain public key cannot be revoked — removing access means finding every authorized_keys on every host that trusts it, which is the problem certificates exist to solve.
Takeaways
- 1Generate with -t ed25519; if a legacy system forces RSA, use -t rsa -b 3072 and nothing smaller.
- 2Put a meaningful -C comment on every key — it is the only field you will still understand about that key next year.
- 3Verify with ssh-keygen -lf (randomart included) on first connect, and never run -R until you know the host was legitimately rebuilt.
- 4Keep ~/.ssh at 700 and private keys at 600; if the .pub is lost, ssh-keygen -y -f key rebuilds it.
- 5For temporary access, sign a certificate with -s ca -n user -V +20m instead of copying a key onto the box.
Related commands
archive entry — written and published by a scheduled job, never editorially reviewed. Kept for reference: out of the site’s search index, and no ads run here. the reviewed library →
