SSH Key Authentication Setup on Linux
The first time I read /var/log/secure on a public server I was a bit shocked. Failed root logins, minute after minute, from the moment the box went online. Public key authentication makes all of that pointless, and you stop typing passwords as a bonus.
Below: key generation, installing the key, turning passwords off, plus an agent and ~/.ssh/config to make life easier. Works the same on CentOS 7 and Ubuntu 16.04 except for the name of the SSH service. You need OpenSSH on your Linux or macOS workstation and a server you can still reach with a password.
Generate a key pair
I make one key per workstation rather than sharing one everywhere; if a laptop is lost, only that key needs revoking. RSA 4096 works everywhere. Ed25519 is shorter and faster and is supported by OpenSSH 6.5 and newer, which covers CentOS 7 and Ubuntu 16.04.
ssh-keygen -t ed25519 -C "yk@laptop"
Or, for maximum compatibility with older appliances:
ssh-keygen -t rsa -b 4096 -C "yk@laptop"
Accept the default path (~/.ssh/id_ed25519 or ~/.ssh/id_rsa) and set a passphrase. A passphrase protects the private key if someone copies the file; the agent (below) means you only type it once per session.
Install the public key
Easiest is ssh-copy-id, which appends the key to ~/.ssh/authorized_keys on the remote side and sets the correct permissions:
ssh-copy-id -i ~/.ssh/id_ed25519.pub deploy@203.0.113.20
Without ssh-copy-id, pipe the key across manually:
cat ~/.ssh/id_ed25519.pub | ssh deploy@203.0.113.20 \
'mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys'
Permissions matter here. sshd silently ignores authorized_keys if the file or the .ssh directory is writable by anyone else, and also if your home directory itself is group-writable.
Test first, then turn passwords off
I always test in a second terminal before touching sshd_config. Do it once wrong and you'll see why.
ssh -i ~/.ssh/id_ed25519 deploy@203.0.113.20
If you get a shell without being asked for the account password (only the key passphrase), the key works. Now edit /etc/ssh/sshd_config on the server:
PubkeyAuthentication yes
PasswordAuthentication no
ChallengeResponseAuthentication no
PermitRootLogin no
Validate and reload. On CentOS 7 the unit is sshd; on Ubuntu it is ssh:
sudo sshd -t
sudo systemctl reload sshd # CentOS 7
sudo systemctl reload ssh # Ubuntu 16.04
Keep your existing session open until you have confirmed that a fresh connection still works.
ssh-agent, so you type the passphrase once
Most desktop environments start an agent for you. If ssh-add -l complains that it cannot connect, start one manually:
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519
On macOS Sierra and later, ssh-add -K stores the passphrase in the keychain so it survives reboots.
One config entry per host
Typing IP addresses and options gets old fast. I keep everything in ~/.ssh/config:
Host web01
HostName 203.0.113.20
User deploy
IdentityFile ~/.ssh/id_ed25519
IdentitiesOnly yes
Host *
ServerAliveInterval 60
AddKeysToAgent yes
Now ssh web01 does the right thing. IdentitiesOnly yes prevents the client from offering every key in the agent, which avoids Too many authentication failures on servers with a low MaxAuthTries.
Checking it
From the workstation:
ssh -v web01 2>&1 | grep -E 'Offering|Authentication succeeded'
You should see Offering public key followed by Authentication succeeded (publickey). Then confirm passwords are really off by forcing password auth:
ssh -o PubkeyAuthentication=no -o PreferredAuthentications=password web01
The expected result is Permission denied (publickey).
When it goes wrong
Permission denied (publickey)even though the key is installed. Runsudo tail -f /var/log/secure(CentOS) or/var/log/auth.log(Ubuntu) while connecting. A line such asAuthentication refused: bad ownership or modes for directory /home/deploytells you exactly which permission is wrong.- SELinux on CentOS 7. If
authorized_keyswas created by copying from elsewhere, it may carry the wrong context.restorecon -Rv ~/.sshfixes it;ls -Z ~/.sshshould showssh_home_t. Agent admitted failure to sign using the key.The agent has a stale or mismatched key loaded. Runssh-add -Dand thenssh-addthe key again.WARNING: UNPROTECTED PRIVATE KEY FILE!The client refuses to use a private key readable by others.chmod 600 ~/.ssh/id_ed25519resolves it.
The bots keep trying afterwards, but now there's nothing to guess. Back up your private key somewhere safe, and prune old public keys from authorized_keys when a workstation is retired. I forget that second part more often than I'd like.