SSH Key Authentication Basics
SSH (Secure Shell) allows remotely accessing the command line interface (cli) of a remote machine. This is very useful for administration of a machine that may be in a completely different country or building.
Because of this SSH is a very attractive target for attackers.
Defaults
The default is to login with a username and password.
┌───────┐ ┌───────┐
│ │ │ │
│ │───────Username─────────▶│ │
│ │ │ │
│ SSH │◀────Request Password────│ SSH │
│Client │ │Server │
│ │───────Password─────────▶│ │
│ │ │ │
│ │◀────────Success!────────│ │
│ │ │ │
└───────┘ └───────┘
The problem with this model is that passwords can be bruteforced (weak passwords), they can be reused and then leaked in password breaches (credential stuffing). Generally SSH with only passwords is not a great idea.
Asymmetric Key Cryptography
The basis of SSH keys lies in asymmetric key cryptography. This is where you have a private key and a public key.
Given a piece of data, the private key can create a signature. The signature can be verified by the public key and the original data. However the public key can not create it's own signature.
┌─────────┐ ┌──────────┐
│ │ │ │
│ │ ┌─────────┐ │ │
│ Private │ Signs │ │ │ Public │
│ Key │───────┬─────▶ │Signature│ │ Key │
│ │ │ │ │ │ │
│ │ │ └─────────┘ │ │
└─────────┘ │ └──────────┘
│
┌────────┐
│ │
│ Data │
│ │
└────────┘
┌─────────┐ ┌──────────┐
│ │ │ │
│ │ ┌─────────┐ │ │
│ Private │ │ │ Verifies │ Public │
│ Key │ │Signature│───────┬─────▶│ Key │
│ │ │ │ │ │ │
│ │ └─────────┘ │ │ │
└─────────┘ │ └──────────┘
│
┌────────┐
│ │
│ Data │
│ │
└────────┘
┌─────────┐ ┌──────────┐
│ │ │ │
│ │ ┌─────────┐ │ │
│ Private │ │ │ Error! │ Public │
│ Key │ │Signature│ X ◀───┬──────│ Key │
│ │ │ │ │ │ │
│ │ └─────────┘ │ │ │
└─────────┘ │ └──────────┘
│
┌────────┐
│ │
│ Data │
│ │
└────────┘
These signatures are design to be mathematically infeasible to bruteforce or forge, meaning that they are very strong compared to passwords.
SSH Key Pairs
Using this knowledge we can now see how an SSH key works. The user (client) who wishes to authenticate to a server holds the private key, and the SSH server has the public key to verify the key is legitimate.
In reverse, the server with the public key can't use that to authenticate since it is only able to verify signatures - not create them.
┌───────┐ ┌───────┐
│ │ │ │
│ │───────Username─────────▶│ │
│ │ │ │
│ │◀────────Challenge───────│ │
│ │ │ │
│ │────┐ │ │
│ │ Private │ │
│ │Key Signs │ │
│ SSH │◀───┘ │ SSH │
│Client │ │Server │
│ │──────Signature─────────▶│ │
│ │ │ │
│ │ ┌─────│ │
│ │ Public Key │ │
│ │ Verifies │ │
│ │ └────▶│ │
│ │◀────────Success!────────│ │
│ │ │ │
└───────┘ └───────┘
Practical Setup Guide (Linux, MacOS)
These commands should all be performed as your regular user account, unless otherwise stated.
Creating the SSH Key Pair
On your SSH client (your destkop, laptop etc). Create a new ssh key pair in the default location
(/home/$USER/.ssh/id_ecdsa
). You will be prompted
for a passphrase. This is a passphrase to encrypt the private key when not in use.
ssh-keygen -t ecdsa
⚠️
/home/$USER/.ssh/id_ecdsa
is the private key. Never reveal this to anyone!
Add the Public Key to the Server (ssh-copy-id)
From the client you can automatically add the public key to the server. You will need to enter your username and password for this operation.
ssh-copy-id -f -i /home/$USER/.ssh/id_ecdsa.pub username@server-hostname
Add the Public Key to the Server (manual)
On the ssh client, view the public key. You may wish to copy-paste this files content.
cat /home/$USER/.ssh/id_ecdsa.pub
ssh to the server and run the following on the server.
cd ~
mkdir .ssh
touch .ssh/authorized_keys
chmod 600 .ssh/authorized_keys
$EDITOR .ssh/authorized_keys
In the editor, paste your ssh public key (one per line) and then save and quit.
SSH to the server
Now type ssh username@hostname
and you will use your key to authenticate!
Hardening the Server
Now that you have ssh key authentication configured you can harden your ssh server to only allow authentication with ssh keys.
As root (sudo -s
) add the following content to /etc/ssh/sshd_config.d/hardening.conf
UsePAM yes
PermitRootLogin no
PermitEmptyPasswords no
PasswordAuthentication no
AllowAgentForwarding no
Then restart sshd
systemctl restart sshd
Before logging out of root, ensure you can ssh to the server with key only. Try logging in with:
ssh -o PreferredAuthentications=password username@hostname
to ensure that password authentication is rejected correctly.