Skip to main content
RunBook Academy

LinuxXXVI · SSHKeys

SSH keys and known_hosts - the key-based authentication model

Foundation⏱ ~12 minssh-keygenssh

What you'll learn

  • Generate SSH key pairs with ssh-keygen
  • Deploy public keys to authorized_keys
  • Manage known_hosts and respond to fingerprint changes
  • Recognise insecure key configurations

Prerequisites

Verified against Ubuntu 24.04 LTS · Debian 12 (Bookworm) · RHEL 9.x · Rocky Linux 9.x · AlmaLinux 9.x · Linux kernel 6.1 LTS / 6.6 LTS · systemd 255+ · OpenSSH 8.7p1 (RHEL 9) / 9.6p1 (Ubuntu 24.04) · nftables 1.0.x · chrony 4.x · Pacemaker 2.1.x · Corosync 3.1.x · 2026-08-09

Not yet marked complete on this device.

SSH key-based authentication is the secure default. This lesson covers how keys work, how to generate and deploy them, and how to manage the trust store (known_hosts).

How SSH keys work

SSH uses asymmetric cryptography. Each user has a keypair:

  • Private key (~/.ssh/id_ed25519): kept secret. Used to sign authentication challenges.
  • Public key (~/.ssh/id_ed25519.pub): distributed to servers. Used to verify signatures.

When the client connects:

  1. Client proves it possesses the private key (via a signature).
  2. Server verifies the signature using the user’s public key in ~/.ssh/authorized_keys.

The private key never leaves the client.

Generate a key

ssh-keygen -t ed25519 -C "user@host"

Output:

Generating public/private ed25519 key pair.
Enter file in which to save the key (/home/user/.ssh/id_ed25519):
Enter passphrase (empty for no passphrase):
Your identification has been saved in /home/user/.ssh/id_ed25519
Your public key has been saved in /home/user/.ssh/id_ed25519.pub
The key fingerprint is:
SHA256:abc123... user@host

The passphrase protects the private key. A passphrase is mandatory in production.

Key types

TypeStrengthNotes
ed25519Strong, modernDefault in modern OpenSSH; small keys, fast
rsaGood with >= 3072 bitsOlder; widely compatible
ecdsaHas NIST curve concernsNot recommended
dsaDeprecatedDo not use

Always use ed25519 or rsa with at least 3072 bits.

Deploy the public key

Three methods:

ssh-copy-id:

ssh-copy-id user@server

The simplest. Prompts for the password, copies the public key to ~/.ssh/authorized_keys, and sets correct permissions.

Manual:

# On the client
cat ~/.ssh/id_ed25519.pub

# On the server
mkdir -p ~/.ssh
chmod 700 ~/.ssh
echo "<paste key here>" >> ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys

Configuration management: Ansible, Puppet, etc. can deploy keys at scale.

Permissions

The SSH server is strict about file permissions:

FileRequired mode
~/.ssh700
~/.ssh/authorized_keys600
~/.ssh/id_* (private)600
~/.ssh/known_hosts644 (read-only OK)

Wrong permissions cause silent auth failures. Test with:

ssh -v user@server 2>&1 | grep -i permission

known_hosts

After the first connection to a host, the server’s host key fingerprint is stored in ~/.ssh/known_hosts:

server.example.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI...

If the host key changes (server reinstall, MITM), ssh refuses to connect and prints REMOTE HOST IDENTIFICATION HAS CHANGED.

For automation, use known_hosts with hashed hostnames (ssh-keyscan -H) to avoid storing plaintext hostnames.

Responding to a host key change

This warning is the only man-in-the-middle defence SSH has. The common reflex - delete the entry, re-scan, reconnect - throws that defence away, because ssh-keyscan verifies nothing. It trusts whatever answers on port 22, which is precisely what an interceptor is doing. Re-scanning during a maintenance window that plausibly changed the key is how an attacker gets trusted permanently.

The rule: obtain the new fingerprint out of band first, then update known_hosts.

# ON THE SERVER, via console or out-of-band management,
# before touching any client:
for k in /etc/ssh/ssh_host_*_key.pub; do ssh-keygen -lf "$k"; done
# ON EACH CLIENT:
ssh-keygen -R server.example.com          # remove the stale entry
ssh-keyscan -t ed25519 server.example.com > /tmp/new_hk
ssh-keygen -lf /tmp/new_hk                # compare with the recorded fingerprint

# Only after the fingerprints match, character for character:
cat /tmp/new_hk >> ~/.ssh/known_hosts

If you cannot reach the server out of band to read its fingerprint, you cannot safely re-trust it. Treat the change as an incident until proven otherwise.

SSHFP and DNSSEC

For high-security environments, publish the host key fingerprint in DNS as SSHFP records. SSH can verify against the DNS record:

ssh -o "VerifyHostKeyDNS=yes" user@server

DNSSEC must be valid for this to be trustworthy.

Manage multiple keys

ssh-agent (covered in the next lesson) holds decrypted private keys. The ~/.ssh/config file selects which key to use:

Host server1
    HostName server1.example.com
    User admin
    IdentityFile ~/.ssh/server1_key

Host github.com
    User git
    IdentityFile ~/.ssh/github_key

Host * matches defaults for all hosts.

Insecure key configurations to avoid

  • No passphrase: a stolen key file gives the attacker access. Always passphrase-protect.
  • Old algorithms: DSA, ECDSA with NIST P-256 (prefer Ed25519).
  • Wide-open authorized_keys: from="*"command="*" is effectively no restriction. Always constrain.
  • Keys in version control: never commit private keys. Even public keys in repo can leak info about who has access.
  • Shared keys per user: every user should have their own keypair. Shared keys destroy accountability.

Knowledge check

Knowledge check · 3 questions

  1. Q1. What is the right ssh-keygen command for a modern key?

  2. Q2. The private SSH key can be safely committed to version control for backup.

  3. Q3. Which of the following are required file permissions for SSH? Select all that apply.

Passing score: 75%. Answers are checked in this browser.