Rotate and upgrade your SSH keys
SSH is an invaluable tool for us developers and sysadmins, and it continues to be perhaps the most secure way to access and operate remote machines, despite being introduced almost 30 years ago.
The time came for me to rotate my client keys again and this time I decided write down why and how to do so. I hope it helps someone else.
Why rotate SSH keys? #
When establishing a connection to a server through SSH, your computer authenticates itself to the host through public-key cryptography using a key pair. Like most other types of credentials, it is good security hygiene to regurlarly review and rotate your key pairs to maintain a strong security posture.
Maybe you, like many others, have been moving the same SSH keys from one device to another for a decade to avoid the hassle of configuring everything again. Or maybe you experienced a catastrophic failure and restored a backup of your old computer to a new one. Meaning the keys could still be lying around on old laptops, company devices, or unencrypted disks.
Importantly, SSH keys are meant to be per-host, ie. a separate pair of keys for each device you use. So when you get a new computer you should generate a new key pair and configure access to each server or service you use. But in my experience, most developers do not realize this (including myself for a long time). And if they are aware, many still choose to not follow the practice because of the perceived hassle.
Some people even use folder syncing services like Dropbox or rsync to copy the same key pair to multiple devices. You really shouldn’t do that.
Maybe you’ve only ever had one key pair on the same device for many years, but it was generated back when the recommended key size was a lot smaller. These days the default size for new RSA keys is 3072 bits, while the recommended size is 4096 bits. So if your key is, say 1024 bits or fewer, then it’s also time for an upgrade.
Why switch to a different type of key? #
While we usually just refer to them as “SSH keys”, that is just a generic term for different types of key pairs based on various cryptographic algorithms. One doesn’t need understand or even know about the cryptography or mathematics behind these algorithms, we can instead rely on the recommendations from industry professionals.
Let’s look at the main types available in our local SSH client1:
- DSA (
ssh-dsa
) 🛑
DSA is considered insecure and should not be used2. It was deprecated by the OpenSSH project in 2015 and was removed from the latest FIPS standard3.
- RSA (
ssh-rsa
) ⚠️
Based on prime numbers and has been the most commonly used algorithm for decades. It is still going strong and is considered to be secure, but you do have to check the length of the key. If it is less than a 1024 bits, it should be considered insecure. On the other hand, if your key is 3072 or more bits (many are 4096 bits) then you’re all good!4.
- ECDSA (
ecdsa-sha2-nistp256
and others) 👎
An elliptic curve implementation of DSA that has been standardized and used widely for many years. This and other algorithms coming out of NIST are subject to speculation. Many believe they are safe, while others believe that they are “backdoored” by the NSA5. For practical purposes, it doesn’t really matter whether that is true or not, because these implementations are vulnerable to some of the same issues as DSA anyway. Furthermore, they also rely on securely generating random numbers, which is always difficult and can lead to real problem as we saw with the PlayStation 3 hack6. So there are multple reasons to avoid this category if you can.
- Ed25519 (
ssh-ed25519
) ✅
Based on Edwards elliptic curves and comes from the modern EdDSA family of signature schemes.7 Despite the confusingly similar names, it is unrelated the above ECDSA family. Ed25519 is widely regarded as the recommended public-key signature algorithm today. It is faster, safer to use, and more secure than alternative algorithms.8 The keys and signature are significantly smaller than those of RSA and it is designed to be more resilient to side channel attacks than ECDSA9. And it does not rely on random numbers as input, meaning less problems for implementers and users.
Since many of us use git
over SSH for our daily work, it is worth noting that GitHub dropped support for DSA keys and RSA keys used with a dated signature algorithm (SHA-1) in late 2021. And since March 2022 only ECDSA, Ed25519, and RSA (with SHA-2 signatures) are supported.10
Which type to choose? #
To sum up the previous section, you could create a fresh set of RSA keys and be reasonably secure, as long as is 4096 bits or more and uses SHA-2. One could even argue that it is overkill for our daily development work.
But security is a moving target and modern elliptic curve cryptography offers quite a few advantages that you might as well take advantage of when generating new keys. So for the rest of this post I will walk you through how to generate a new key pair based on Ed25519 and how to use it to connect to GitHub.
Which type are your current keys? #
Check the folder #
Navigate to the default SSH folder and list out all the files:
The default filename for new key pairs is id_
, followed by the key type. For example: id_rsa.pub
, id_ecdsa.pub
, or id_ed25519.pub
- meaning RSA, ECDSA, and Ed25519 type keys respectively.
🔑 This might seem obvious, but always bears repeating:
The file with the extension .pub
is your PUBLIC key, which is the one you copy to remote machines or paste into services like GitHub, AWS, etc. The one without a file extension (like id_rsa
), is your PRIVATE key which you must NEVER copy or share anywhere.
Ask the agent #
As shown above, it is common to look in the ~/.ssh
folder on your computer to find your keys, but there might be SSH keys in use that are located elsewhere.
So let’s ask the ssh-agent
which keys it knows about, using the list option:
The command prints a list of keys and their details in the following format:
Which tells us that the key in this example is a 4096-bit RSA key.
(This is assuming that the agent is running and working correctly. If it is not working for you, take a look at this article: Generating a new SSH key and adding it to the ssh-agent | GitHub Docs).
Archive the old keys #
You can have as many key pairs on your computer as you want and it is even prudent to use different key pairs for different contexts. But as time passes it is easy to forget which keys were made when and for what purpose.
So I recommend that you archive all your current ones, generate a new key pair, and then later generate purpose-specific ones as the need arises.
Back up #
We don’t want to simply delete the old keys right away, because we could get accidentally locked out. By renaming and moving the keys first, we can gradually migrate away without the risk of losing access.
You can back up the entire folder using the archive option of the copy utility:
The result is a full copy of the folder, hopefully with permissions and everything intact in case you need later.
Rename #
If you already have an existing id_ed25519
key pair, rename the files to something else to avoid confusion and conflicts, for example:
Inform the agent #
As mentioned earlier, the SSH agents keeps track of the keys in use on your computer. But unless configured to do so, it does not automatically react to changes you make to the key files.
So once you have archived and renamed your existing key(s), you need to remove them from the SSH agent.
You can do so using the -D
or -d
options in ssh-add
:
Generate a new key pair #
Unless you know what you are doing, you should not generate key pairs without a passphrase. So first, generate a very strong passphrase in your password manager of choice and copy it.
Then, generate a new SSH key pair:
Explanation of the options:
-t
: sets the key type to Ed25519 instead of RSA, as discussed above.-a
: set the number of Key Derivation Function rounds to perform. In short: The higher the number is, the slower the verification of the passphrase is, meaning bruteforce attempts get slowed down. But it also means that verification of your passphrase is slower in general use, so it is a tradeoff of performance vs security. The default value is16
.-C
: adds a comment to the key to make it easier to identify later. The comment is stored as a string at the end of the public key and in encrypted form inside the private key. It can be changed later, so don’t worry too much about it, just don’t put anything sensitive here. The default value isuser@hostname
.
A note on comments:
Many guides suggest that you use your email address, and some even seem to imply that it’s mandatory. It’s really not and there’s no good reason to do so. Though if you are working with other people and connect to machines that store multiple public keys, it’s a good idea to use some sort of identifier like your initials or username so it is easier to tell the keys apart.
When you run the command, you have to choose where to put the file (default is fine) and enter a passphrase for the key (paste the one you generated earlier):
Update your config #
Make sure to update your SSH configuration to use the new identity. To update it, you can open the ~/.ssh/config
file in your editor of choice.
Brief warning about using *
in your config:
It is tempting to use a wildcard like Hosts *
in your SSH config file. It is very common in tutorials and shared configurations and seems like a nice convenience. But you SHOULD NOT be using *
unless you really know what you are doing. Malicious servers can abuse it to list all your public keys. And using a wildcard in combination with SSH forwarding leaves you vulnerable to attacks like SSH Forward Agent exploitation. Instead, you should set a Hosts
configuration for each trusted server and point to the public key to use, like I’ve done for GitHub below.
Here is an example of how to set a configuration for GitHub:
Inform the agent, again #
The SSH agent needs to be told about new keys manually, we can do so using ssh-add
:
You might need the --apple-use-keychain
option if you are on MacOS.
Then, use the list option to verify that the new key is listed and the old ones are no longer there:
Test the new key #
To test the new key, you can use a service that offers SSH access like GitHub.
-
Follow the steps in their guide, to associate your key with your account: Adding a new SSH key to your GitHub account - GitHub Docs
-
Connect to GitHub to test that the key is working:
Authenticity and fingerprints #
When connecting, you may see a notice about the authenticity of the server. Make sure that the fingerprint you are seeing in the response, matches one of the SSH key fingerprints GitHub has published publicly: GitHub’s SSH key fingerprints - GitHub Docs
So for example:
At the time of writing, the fingerprint in the SSH response (SHA256:+DiY3wvvV6TuJJhbpZisF/zLDA0zPMSvHdkr4UvCOqU
) matches the one GitHub has published for Ed25519 on their site. So I can reasonably conclude that I am in fact connecting to the real GitHub and not an imposter. I accept the connection by typing yes
.
If everything has gone as planned, you should see this response:
Congrats, you have successfuly rotated and upgraded your SSH keys to keep up with the latest standard in security and performance!
-
You can list the available key types in your local client using:
ssh -Q key
. For this post I am using the default OpenSSH version that ships with MacOS Ventura. ↩︎ -
DSA Is Past Its Prime | Cryptography Dispatches by Filippo Valsorda ↩︎
-
From Section 4 in FIPS 186-5: Digital Signature Standard, published in 2023:
“This standard no longer approves the DSA for digital signature generation.” ↩︎ -
See more about key length and the estimations of how long they will stay secure at Keylength.com. ↩︎
-
Accusations of untrustworthy algorithms and interference from intelligence services goes back many years. Read more: How a Crypto ‘Backdoor’ Pitted the Tech World Against the NSA | WIRED by Kim Zetter. ↩︎
-
Story about the presentation from 2010: PS3 hacked through poor cryptography implementation | Ars Technica by Casey Johnston. ↩︎
-
Read more about Ed25519 on Wikipedia and SafeCurves.cr.yp.to and Ed25519.cr.yp.to. ↩︎
-
Let Soatok be your guide to the various choices in: Guidance for Choosing an Elliptic Curve Signature Algorithm in 2022 | Dhole Moments. ↩︎
-
If you are curious about the technical details, I highly recommend: A Deep dive into Ed25519 Signatures by Cendyne. ↩︎
-
Improving Git protocol security on GitHub | The GitHub Blog ↩︎