Picture this: you got your new machine set up with your development tools. You fire up a Terminal, SSH into your work’s server, and… it asks for your password. Panic sets in as you realize that you decommissioned away the old machine, along with the old SSH keys. You must now remember that password to that server - a password you seldom typed in thanks to your SSH keys - or if the SSH daemon installed on that particular server disallows password-based authentication, be forced to do the call-of-shame to your colleague or the administrator of the server to let you back in.

Humiliating! Embarrassing. And most importantly, annoying.

So what if there was a way to enable persistent access to a given server or machine? What if you didn’t have to go around updating every single machine with your new SSH key?

In this blog post we’ll go over how we can do just that!

1. GitHub

The first thing you have to do is make sure that your GitHub security is top-notch. Because anybody who gets access to your GitHub account will have access to all of your servers.

So make sure your GitHub account has a strong password, preferably set with a password manager, and make absolutely sure to enable 2FA.

Once you’ve done that, go over to Settings > SSH and GPG keys, and add your SSH keys here. This is where you will add all of your SSH keys and the new SSH keys you generate whenever you get a new machine or environment to work in. You only need to update GitHub, and the other machines will follow.

Done? Now let’s move over to the server or machine you want persistent access to.

2. Script

Remote into the target server, and start!

Make a script, update-ssh.sh, wherever you like in your home directory. Paste in the following:

#!/bin/bash

echo -e "Script started at $(date)"

curl "https://github.com/your-username-here.keys" > ~/.ssh/authorized_keys


echo "The following keys were added:"
cat ~/.ssh/authorized_keys

chmod 600 ~/.ssh/authorized_keys

Make sure you replace “your-username-here” with your GitHub username. For example, my public keys can be found at https://github.com/ericswpark.keys.

So what does this script do? Well, it fetches your public keys from your GitHub profile, and saves them to the authorized_keys file in your .ssh directory. Then it sets the relevant permissions to make sure that the SSH daemon will not reject the file, since the daemon will ignore authorized_keys files that have too open permissions.

Set the script as executable and try running the script. Afterwards, you will be able to log into the server without actually manually adding your new SSH key.

But we want to automate this, so that whenever you add a new key on GitHub, it syncs to all of your servers.

3. Automate

To make this script run periodically, we’ll use crontab.

Don’t know how to use crontab? Me too! Let’s just go over the basics.

The basic syntax of crontab is as follows:

20 * * * * ls

The first column is minutes, which has a range of 0 to 59, and the second column is hours, which has a range from 0 to 23. The third column is the day of month (1 - 31), the fourth column is the month (1 - 12), and the final column is the day of week (Sunday 0 to Saturday 6). A wildcard value matches to all possible values in that range.

Therefore, the crontab entry above will run every hour at 20 minutes (so, 2:20 PM, 3:20 PM, and so on).

There’s also patterns to make crontab entries repeat (/2 means every 2 units, and so on), but it’s not supported by all Linux distros, so be careful when using them!

Some enthusiasts will preach about systemd tasks, but I think cron is more prevalent (not so sure, don’t quote me). I haven’t seen a system yet that doesn’t have cron. But of course this is an option if you prefer systemd.

So still in that same target server, run crontab -e. A editor should pop up. In the last line, create the following entry:

42 * * * * ~/update-ssh.sh >> ~/update-ssh.sh.log

Change 42 to a random number between 0 and 59, to help lessen load on the server.

Wait, why don’t we just refresh every minute?

The reason I set the crontab here to refresh every hour is because I don’t want to put unnecessary strain on the server or GitHub’s servers. We don’t usually update SSH keys all that often, but we want to strike a balance, because if the interval is too long then we might as well just remote in with our password and change the keys ourselves. An hour is a reasonable interval that won’t put too much strain on the servers involved. You can set it to a shorter interval, say 5 minutes, if you change SSH keys frequently, but do keep in mind that you may be rate-limited.

The log pipe is not strictly necessary, but it’s good to have in case things go wrong.

The crontab entry means that your SSH keys will be updated each hour at the random minute you specified.

Conclusion

The next time you update your SSH keys, update them on GitHub, wait until an hour has elapsed, then remote in to your usual server!

Thanks for reading! I hope this blog post helped you out.