working with ssh-keygen

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:

Generating A New SSH Key

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:

  1. Enter the file in which to save the key (the default is /.ssh/id_ed25519)
  2. Enter passphrase (empty for no response)
  3. Enter same passphrase again If you just keep pressing Enter, eventually you’ll see an output like:
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.

Passing Options

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>

PEM Format And Converting SSH Keys

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

Reviewing SSH Keys

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

Setting Up the SSH Config

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:

$HOME/.ssh/config
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:

  1. If you don’t know add the keys to the ssh-agent, it can be:

    $HOME/.ssh/config
    Host github.com
      HostName github.com
      IdentityFile ~/.ssh/id_github_ed25519
  2. If the host is the same as the hostname (as the case for the personal account), you should be able to get away with:

    $HOME/.ssh/config
    Host github.com
      HostName github.com
      IdentityFile ~/.ssh/id_github_ed25519
  3. Instead of a subdomain for the host, I’ve also seen appending the user name, for example:

    $HOME/.ssh/config
    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:

    $HOME/.ssh/config
    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.

    $HOME/.ssh/config
    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
     # $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. )

(Optional) Adding SSH Keys to ssh-agent

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

Testing that you’ve connected

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)).

Wrap Up

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.

Reference Material

Footnotes

  • 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.

Related Posts
  • Setting Up A New Macintosh Computer


  • 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!