Skip to content

SSH Key Authentication

SSH Basics ended every connection with a password prompt, and its closing note already flagged the problem: a password can be brute-forced, it has to be typed by hand on every login, and if it leaks anywhere, anyone who has it can get in. The standard fix is authentication with an SSH key pair. This article covers how a key pair actually works, how to generate one, and how to install it on a server.

Asymmetric Cryptography, the Practical Part

SSH key authentication is built on asymmetric cryptography: two mathematically related keys are generated together —

  • the private key — stays on your machine only, and is never sent anywhere, to anyone;
  • the public key — can be copied to any number of servers, because the private key cannot be reconstructed from it.

During authentication, the server sends a piece of random data, the client signs it with the private key, and the server verifies that signature using the public key it already has on file. If the signature checks out, the client must hold the matching private key — no password ever crosses the network.

The rule that follows from this is simple: the public key goes to servers; the private key never leaves your machine. Mixing the two up, or copying a private key onto a server, is a common and serious mistake.

ssh-keygen: Generating a Key Pair

ssh-keygen -t ed25519 -C "alice@laptop"
  • -t ed25519 — selects the key algorithm. Ed25519 is modern, fast, and cryptographically strong, and it's the default choice for new systems. On older servers that don't support it, -t rsa -b 4096 (4096-bit RSA) is the fallback;
  • -C — attaches a comment to the key, usually in the form user@machine; this makes it easier later to tell which key came from where, once you accumulate several.

Once the command runs, it prompts for a few things:

Generating public/private ed25519 key pair.
Enter file in which to save the key (/home/alice/.ssh/id_ed25519):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
  • there's usually no need to change the file path — the default location (~/.ssh/id_ed25519) is where most tools look for it automatically;
  • the passphrase encrypts the private key file itself (covered separately below).

This produces two files:

~/.ssh/id_ed25519       # private key — never share this
~/.ssh/id_ed25519.pub   # public key — safe to copy to servers

Checking the file permissions:

ls -l ~/.ssh/id_ed25519*
-rw------- 1 alice alice 411 Jul 25 10:02 /home/alice/.ssh/id_ed25519
-rw-r--r-- 1 alice alice  98 Jul 25 10:02 /home/alice/.ssh/id_ed25519.pub

The private key file must be 600 (readable and writable only by its owner) — the OpenSSH client refuses to use a key file with broader permissions than that. The reasoning behind this kind of permission model is covered in File Permissions.

Installing the Public Key on a Server

ssh-copy-id [email protected]

This connects to the server using whatever authentication method already works (usually a password), appends the contents of ~/.ssh/id_ed25519.pub to the remote ~/.ssh/authorized_keys file, and sets the correct directory and file permissions along the way. A successful run looks like this:

Number of key(s) added: 1

Now try logging into the machine, with:   "ssh '[email protected]'"
and check to make sure that only the key(s) you wanted were added.

Installing It by Hand (When ssh-copy-id Isn't Available)

cat ~/.ssh/id_ed25519.pub | ssh [email protected] "mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"

This one line does several things at once: it creates ~/.ssh if it doesn't exist, sets it to 700, appends the public key to the end of authorized_keys, and sets that file to 600. Every one of those permission steps matters — the OpenSSH server will silently ignore, or outright refuse, an overly permissive .ssh directory or authorized_keys file, for security reasons explained below.

authorized_keys: Structure and Logic

~/.ssh/authorized_keys lives in each user's home directory on the server and lists the public keys allowed to log in as that user. Each line is one key:

ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGx3k9F... alice@laptop
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHq2mPZ... alice@work-desktop

For a single user to log in from several devices (a laptop, a work desktop), each device's public key is added as a separate line in this file — a single key should not be reused across multiple devices, because if one device is compromised, removing just that one line is enough to shut it out.

Once key authentication is set up, connecting no longer asks for a password:

Enter passphrase for key '/home/alice/.ssh/id_ed25519':

(If a passphrase was set when the key was generated — this is not a server-side password, it's the passphrase protecting the private key file itself, explained next.)

Passphrases: Why and When

A passphrase ensures the private key file itself is stored encrypted on disk. If a laptop is stolen or the private key file is accessed without authorization, a passphrase-free key can be used immediately; a passphrase-protected key still requires the passphrase first.

Tip

Setting a passphrase is recommended for keys on a personal workstation or laptop. Keys used by automated scripts or CI/CD systems are usually generated without one, because an automated process can't type a passphrase interactively — in that case, the key needs to be kept in a dedicated, access-restricted service account instead.

Having to type a passphrase on every use can get tedious — that's solved with ssh-agent, which asks for the passphrase once per session and keeps it in memory from then on. This is covered in SSH-Agent and Host Verification.

Practical Scenario: Diagnosing "Permission Denied (publickey)"

Problem: the key was generated, ssh-copy-id ran successfully, but ssh [email protected] still returns:

[email protected]: Permission denied (publickey).

Step 1 — see which key the client is actually offering:

Look for Offering public key lines in the -v output — the wrong key file might be tried first (for instance, if several keys exist and the wrong one takes priority).

Step 2 — check the contents of authorized_keys on the server (if another access method is still available):

cat ~/.ssh/authorized_keys

Confirm the entry is present and matches the contents of the client's id_ed25519.pub file exactly.

Step 3 — check the permissions:

ls -ld ~/ ~/.ssh ~/.ssh/authorized_keys
drwxr-xr-x 5 alice alice 4096 Jul 25 09:40 /home/alice
drwx------ 2 alice alice 4096 Jul 25 09:41 /home/alice/.ssh
-rw------- 1 alice alice  103 Jul 25 09:41 /home/alice/.ssh/authorized_keys

The OpenSSH server is strict here for a security reason: if the user's home directory, the .ssh directory, or authorized_keys itself is writable by group or others (drwxrwxr-x, for instance), the server deliberately ignores that file — because, in principle, some other user could have modified it. No error message is produced in this case; the key simply doesn't work.

Step 4 — confirm from the server logs (if you can still get in another way):

sudo journalctl -u ssh --since '5 min ago' | grep -i authentication

The log usually states the exact cause — for example, Authentication refused: bad ownership or modes for directory.

Step 5 — fix it and verify:

chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys

Reconnect from the client and confirm the password prompt no longer appears.

Step 6 — document it: note exactly which permission was wrong and why (for example, the file was created with a umask of 022 instead of a stricter value by some other process).

Common Mistakes

Copying the Private Key to a Server, or Anywhere Else

A private key should never leave the machine it was generated on — not even to another server you own. If several devices need access, each generates its own key pair, and only the public keys get added to servers.

Adding a Key to authorized_keys the Wrong Way

Opening the file with > (overwrite) deletes every previously stored key; always use >> (append) or ssh-copy-id.

Ignoring File Permissions

As the scenario above showed, this is the single most common reason key authentication "mysteriously" stops working. When it does, check the permissions on ~, ~/.ssh, and authorized_keys first.

Letting the Client Offer Too Many Keys at Once

When several private keys exist, or an ssh-agent is loaded with many identities, ssh offers them one at a time — and the server counts each as a failed attempt. Past the server's MaxAuthTries limit it drops the connection with Received disconnect ... Too many authentication failures, before ever reaching the key that would have worked. Pin the exact key to stop this:

ssh -o IdentitiesOnly=yes -i ~/.ssh/id_ed25519 [email protected]

IdentitiesOnly=yes (which can also go per-host in ~/.ssh/config, covered in SSH Configuration) tells the client to offer only the key named by -i/IdentityFile, instead of every identity it knows about.

Sharing a Single Key Across Multiple People or Services

Every person or service should have its own key. A shared key makes it impossible to later determine exactly who logged in and when — a real problem for auditing and incident response.

Exercises

  1. Generate a new key pair with ssh-keygen -t ed25519, then explain, from the ls -l ~/.ssh/ output, why the private and public key files have different permissions.
  2. Install the public key on a lab server with ssh-copy-id and confirm that passwordless login now works.
  3. Deliberately run chmod 777 on ~/.ssh on the server, attempt to connect and observe the failure, then find the cause via journalctl and correct the permission.
  4. Generate a second key pair with a different filename (for example, ssh-keygen -t ed25519 -f ~/.ssh/id_work), add its public key to authorized_keys as well, and connect using specifically that key with ssh -i ~/.ssh/id_work ....

Verification criterion: for exercise 3, ssh -v must show the server actively rejecting the key due to permissions (visible in journalctl, not just a generic failure) before you apply the fix — if no such log entry appears, you likely broke something other than the intended permission.

References