2020-05-25
|~7 min read
|1377 words
Update: RSA 4096 has been deprecated in favor of the Ed25519 algorithm (source: Github).
Update: Adding a section on the PEM format as it was a particularly painful lesson recently and I burned a several hours tracking down the answer. Thank you to Brian Redbeard on Stack Exchange for pointing me in the right direction!
SSH, also referred to as Secure Shell, is a protocol for authenticating services remotely. See SSH.com’s SSH Protocol article for more.
I’ve had to set up too many machines recently and each time, this is a learning curve. So, I’ll be documenting my process for generating SSH keys on MacOS, with some attention toward the ssh-config
toward the end:
The simplest way to generate a new SSH Key is to open a terminal and type:
ssh-keygen
The ssh-keygen
utility “generates, manages and converts authentication keys for ssh.”
The default key is generated using the RSA Cryptosystem. This will prompt you with a few questions:
/.ssh/id_ed25519
)Your identification has been saved in /Users/stephen/.ssh/id_ed25519.
Your public key has been saved in /Users/stephen/.ssh/id_ed25519.pub.
The key fingerprint is:
SHA256:7hM+mb0BnOdCZpWssayBAvAay9uKgpCA1I/EZiROBeU stephen@Stephens-MBP-2.attlocal.net
The key's randomart image is:
+---[ED25519 256]----+
|.+B+ |
|+oo* . . |
|=.=Eo . + |
|+= . o o * |
|+o. . . S . |
|o o. B.+ |
|o. . ..o=o |
|+ . .*... |
|o. .o.. |
+----[SHA256]-----+
That means you successfully created a new public/private key.
While the default approach will work fine, there are some convenient flags that are worth knowing:
-C
adds a comment. This is appended to the public key, which can make it easier to identify. For example, Github recommends adding your email address for use here.
-b
sets the bits in the key. The default is 3072, which is “generally […] considered sufficient”, however can be raised and lowered as needed.
-f
sets the file name of the output key file
-t
specifies the type of key that’s created (rsa-sha2-512
is the default, ed25519
is now recommended)
-m
sets the key format (default is Open SSH
, but some older systems may require that you use PEM
)
So, for example, this can look like:
ssh-keygen -t ed25519 -C "This is a comment" -f <the_file_name>
Some systems cannot process the Open SSH format and may require that the key is the PEM format.
If you know this in advance, you can create a new public/private key specifying the format upfront:
ssh-keygen -t ed25519 -m PEM -C "This is a comment" -f <the_file_name>
Alternatively, if you have to convert the public/private key after it’s been created, you can use the -e
flag:
ssh-keygen -f <the_file_name> -e -m PEM
Now that we’ve created it, let’s make sure it exists. If you used the default id_ed25519
, then it’s likely that your key is in the .ssh
directory of your user (i.e., ~/.ssh
).
You can verify that you have both a public and private key by listing the contents of that directory:
$ ssh-keygen -t ed25519 -C "<personal@host.com>" -f id_github_ed25519
$ ssh-keygen -t ed25519 -C "<work@host.com>" -f id_work_github_ed25519
$ ssh-keygen -t ed25519 -C "<personal@host.com>" -f id_gitlab_ed25519
$ ls -la ~/.ssh
total 48
drwx------ 8 stephen staff 256 Apr 27 13:47 .
drwxr-xr-x+ 49 stephen staff 1568 Apr 27 16:58 ..
-rw-r--r-- 1 stephen staff 84 Mar 11 18:58 config
-rw------- 1 stephen staff 3389 Mar 11 18:54 id_github_ed25519
-rw-r--r-- 1 stephen staff 751 Mar 11 18:54 id_github_ed25519.pub
-rw------- 1 stephen staff 3389 Mar 11 18:54 id_work_github_ed25519
-rw-r--r-- 1 stephen staff 751 Mar 11 18:54 id_work_github_ed25519.pub
-rw------- 1 stephen staff 3389 Mar 11 18:54 id_gitlab_ed25519
-rw-r--r-- 1 stephen staff 751 Mar 11 18:54 id_gitlab.pub
-rw------- 1 stephen staff 2635 Apr 27 13:47 id_ed25519
-rw-r--r-- 1 stephen staff 589 Apr 27 13:47 id_ed25519.pub
-rw-r--r-- 1 stephen staff 3353 Apr 24 16:47 known_hosts
Now that we’ve created multiple accounts, it’s time to set up the ssh config (here’s the manual page with all of the options)
This might look like:
Host github.com
HostName github.com
AddKeysToAgent yes
UseKeychain yes
IdentityFile ~/.ssh/id_github_ed25519
Host company.github.com
HostName github.com
AddKeysToAgent yes
UseKeychain yes
IdentityFile ~/.ssh/id_work_github_ed25519
Host gitlab.com
HostName gitlab.com
AddKeysToAgent yes
UseKeychain yes
IdentityFile ~/.ssh/id_gitlab_ed25519
Some notes and caveats:
If you don’t know add the keys to the ssh-agent
, it can be:
Host github.com
HostName github.com
IdentityFile ~/.ssh/id_github_ed25519
If the host is the same as the hostname (as the case for the personal account), you should be able to get away with:
Host github.com
HostName github.com
IdentityFile ~/.ssh/id_github_ed25519
Instead of a subdomain for the host, I’ve also seen appending the user name, for example:
Host github.com-<company-user>
HostName github.com
IdentityFile ~/.ssh/id_work_github_ed25519
There are a lot of gists out there to help with this approach: e.g., here, here, here and here).
The important thing to note about the above suggestions is that the hosts need to be different. How you distinguish them, though, is up to you (per this SuperUser conversation).
This means that if you have two Github profiles, you can distinguish them like so:
Host github.com
HostName github.com
IdentityFile ~/.ssh/id_github_ed25519
Host github.com-work
HostName github.com
IdentityFile ~/.ssh/id_<work>_github_ed25519
Similarly, this means that even if one GitHub account is enterprise and the other is free (and so distinguished by the HostName), you need to still differentiate the Hosts.
Host github.com
HostName github.com
IdentityFile ~/.ssh/id_github_ed25519
Host github.<work>.com
HostName github.<work>.com
IdentityFile ~/.ssh/id_<work>_github_ed25519
Then in my .gitconfig
(or more accurately, my /.git/config
file)1, I included the following:
# $HOME/work/.git/config
[url "git@github.<work>.com:"]
insteadOf = https://github.<work>.com/
(Remi Lavedrine put together a great walkthrough on Dev.To which I found as I was pulling this together. )
ssh-agent is a program to hold private keys used for public key authentication (RSA, DSA, ECDSA, Ed25519). ssh-agent is usually started in the beginning of an X-session or a login session, and all other windows or programs are started as clients to the ssh-agent program. Through use of environment variables the agent can be located and automatically used for authentication when logging in to other machines using ssh(1).
GitHub has put together a nice step-by-step guide on how to add a key to the ssh-agent.
Make sure that the ssh-agent
is running:
eval "$(ssh-agent -s)"
Then, once you’re done setting up the SSH Config (the previous step), add the new id to the agent:
ssh-add -K ~/.ssh/id_ed25519
If you’ve made it this far, it’s worth testing that your ssh connect is working as expected. One way to do that is with ssh -T
.2 For example:
ssh -T git@github.com
This will attempt to use the user git
to access github.com
(which was the Host we specified in the user specific config
file above). GitHub offers some handy debugging tips if this doesn’t work (e.g., if you receive an error permission denied (public key)).
That should be plenty for now. Typically, if a service has an option for connecting via SSH, it will provide documentation for where to put your public key, but what to do with the private key is a little bit more of a mystery. Hopefully this answers some of those questions.
1 See here for more about setting up multiple git configs
2 The use of the -T
flag is really to ensure the terminal does not attempt TTY. From the manual:
-T Disable pseudo-terminal allocation. -t Force pseudo-terminal allocation. This can be used to execute arbitrary screen-based programs on a remote machine, which can be very useful, e.g. when implementing menu services. Multiple -t options force tty allocation, even if ssh has no local tty.
Hi there and thanks for reading! My name's Stephen. I live in Chicago with my wife, Kate, and dog, Finn. Want more? See about and get in touch!