Recently, a bug hunter in Nahamsec’s Discord server asked a question about using certificates for SSH authentication. He was running into a common problem: he has multiple devices that he uses to connect to his server, and feels that keeping track of all the passwords is too much of a pain. This gets worse for bug hunters because we spin up and tear down systems frequently. It’s a lot to track!
I recommended using certificates, both because it’s more secure and and it’s just easier; in fact, implementing cert-based auth will make logging in to your servers seamless… and there’s no password to remember or track down.
I’m assuming that you’re familiar with SSH and why we need it.
I also assume that you have a *nix server with SSH on it; this could be a virtual machine (VM, ex: Kali VM), a virtual private server (VPS, ex: DigitalOcean Droplet / EC2 instance), or a physical or virtual server in your home lab environment. I use Ubuntu Server 18.04 for this.
After you review this post, you will be able to access your server from any machine with an SSH client installed. Your server will also be hardened*, since we’ll disable password authentication.
* well, mostly hardened; disabling remote root login is a best practice, but this may limit us so it will be optional.
1. [OPTIONAL] Generate an SSH keypair
Note: If you already have keys on your main machine (not the server!), you can use them.
Important: If your client is a Kali VM, be sure to regenerate your keys.
Then, follow the prompts. Do not change the default path. “/home/<username>/.ssh/id_rsa” if good and should not be changed. The private key will be called
id_rsa and the associated public key will be called
id_rsa.pub. You can safely share the public key (
id_rsa.pub), but you must guard the
If you’re prompted for a password for the key, just hit enter a couple times to set an empty password. This is useful for bug hunters, but a terrible idea for prod or otherwise important systems.
2. Connect to your host:
You will be prompted to accept the server’s fingerprint; do so, then enter your password:
If you can authenticate with your password, then you’re in good shape for the next step.
Disconnect from the server:
3. Copy SSH public key to the server
Next up, we’ll copy the public key to the server. From your local host:
You will be prompted for your password again… for the last time.
3.5. Copy a public key manually
If you’re on Windows or any other system that does not have
ssh-copy-id, you can manually copy your public key onto the server. You’ll need to google where your app stores its keys; once found, open the public key file (name ends with “.pub”), copy it, SSH to your server, then append the key to your user’s authorized_keys file:
On your server:
echo “<public key block>” >> ~/.ssh/authorized_keys
4. Test cert-based authentication
If everything is correct, you will log in immediately (without a password prompt!)
NOTE: At this point, you can stop if you want. Cert-based auth works and your life is a little easier. We should secure this, though.
5. Lock down SSH
We should prevent password-based logins. There’s no need for them if we have certs, so let’s do this with tricky one-lines:
sudo sed -i “s/.*RSAAuthentication.*/RSAAuthentication yes/g” /etc/ssh/sshd_config
sudo sed -i “s/.*PubkeyAuthentication.*/PubkeyAuthentication yes/g” /etc/ssh/sshd_config
sudo sed -i “s/.*PasswordAuthentication.*/PasswordAuthentication no/g” /etc/ssh/sshd_config
sudo sed -i “s/.*AuthorizedKeysFile.*/AuthorizedKeysFile\t\.ssh\/authorized_keys/g” /etc/ssh/sshd_config
OPTIONAL: Preventing root login is generally a good idea, but will break some VPSs such as DigitalOcean where the default user is “root”.
To disable root logins:
sudo sed -i “s/.*PermitRootLogin.*/PermitRootLogin no/g” /etc/ssh/sshd_config
Finally, restart SSHd, the reconnect to confirm it’s all working:
sudo service sshd restart
Done! You should be able to access your server from any device, assuming you copy the public key over.
Want to make your life a little easier? Use ssh config!
SSH’s default behavior can be changed and improved by modifying ~/.ssh/config. The most useful capability is defining “hosts” to make connections better and easier. Here’s an example:
We’re using the “Host” entry to define some information about a given host, including giving it a name. This is gold, since we can connect directly to servers using the name we set (and avoid IPs, because gross).
You may notice
user rootin this example. You don’t need to specify a username; SSH will use your local username if you don’t. This is convenient if you use the same username across systems, but that might not always be possible or convenient.
With this Host entry added to your ~/.ssh/config, connect over SSH using the name you set:
This is a good time to mention: you need a naming scheme. I used “reconDO” in my examples, but it’s far too easy to forget which generically-named system is intended for what purpose. Consider meaningful names and IDs, such as “kali01”, “dns03”, “vps-do-recon”. It’ll be much easier to keep track of.