SSH Keys and ssh-agent on Windows/Linux/Mac

Why am I Writing This

Using SSH to securely connect to remote servers is well understood by anyone needing to do it. However, when you ask people to use a public/private keys to connect, it starts to get a little murkier - mainly because the process is not well understood by some folks. This article breaks down the confusion and simplifies the process to a point where you'll wonder why you haven't been doing this all along.

Standard SSH

Let's assume you need to connect to server1.domain.com as user superman. You can do this with the following command.

ssh superman@server1.domain.com

This approach is fine but it involves sending your password to the server for authentication and there is no verification of who you are. Consequently, anyone with your password can get in and eavesdropping on your connection is a possibility, albeit difficult.

SSH Keys

SSH keys use the public/private key paradigm to verify the authenticity of a connection and your password is never sent to the server you're connecting to. The private key is secret, known only to you, and stored on the client whereas the public key is well known and provided to the server. When a connection attempt is made, a challenge/response routine takes place that authenticates who you are and sets up a secured connection. This is more secure than a password and greatly reduces/eliminates the possibility of a successful brute force attack.

In fact, SSH servers can be configured to only allow communication through the use of public/private keys; AWS Linux EC2 servers default to this behavior. I'll show how this can be done at the end of the article.

Environment

For the sake of this article, I assume you are working from a command-line interface. On Windows, I assume you are working from within cygwin. Although, the concepts are easily applied to however you are connecting.

The first thing we need to do is make sure you have the ability to create SSH keys.

On Windows

Best option: Download/install cygwin and choose OpenSSH from the package list.

Other option: download/install OpenSSH as its own application

On Mac OSX / Linux

Turn your computer on.

From a command prompt, type ssh and then hit tab twice. You should see the ssh programs we'll be working with:

  • ssh
  • ssh-add
  • ssh-agent
  • ssh-keygen

Create Your Key Pair

Creating a key pair is very simple but there is one very important guideline to remember - though not required, you should include a passphrase on your private key. Failing to use a passphrase lowers your effective security. Your private key is used to unlock encrypted messages. It's akin to leaving the key to your house under the mat. Adding a passphrase is akin to locking your key in a lock box and putting it under the mat. I say under the mat because the typical location of these keys is pretty standard.

Weak Argument Against Using a Passphrase: I'll have to enter a password every time I use SSH and I don't want to :(

My rebuttal: Use ssh-agent and stop complaining.

To create your public/private key pair on a command line, run the following command.

ssh-keygen

The default algorithm used to create the keys is RSA. We'll stick with defaults here. When prompted, enter a passphrase (or don't - your choice). You should see output similar to the screen shot below.

You can also use a putty program on Windows called puttygen.exe. To use puttygen to generate your keys, open the program and click Generate key pair... from the Key menu.

You can add a passphrase and save both keys after the randomness is done.

That's it. Now we need to share the public key with the server we'll be connecting to. You can get the file to the server anyway you want.

HowTo: Install a Public Key on a Linux Server

Here's a one-liner that'll do it.

cat ~/.ssh/server1.pem.pub | ssh superman@server1.domain.com 'cat - >> ~/.ssh/authorized_keys2'

This pipes the content of your public key to SSH which in turn connects to your server. Once the connection is established, it takes the contents of standard in (result of piping content through ssh) and appends it to a file called authorized_keys2 in your account's .ssh folder.

Note: You will be prompted for a password. This is your standard ssh password and should be the last time you'll need to enter it in this context. Also, if .ssh directory does not exist, this command will not create one. You'll need to do that yourself and then re-run the command.

HowTo: Install a Public Key on a Windows Server

This is a bit trickier, but only because we need to know what ssh server the Windows instance is running.

I'm Assuming WinSSHD

If you're connecting to WinSSHD on Windows, you'll need to import your account's public key into the application using the graphical interface. From the control panel of WinSSHD, click "Open easy settings" from the settings area.

For WinSSHD Virtual accounts, click the third tab - the one named Virtual Accounts. If you connect to WinSSHD using Windows accounts, click the second tab - the one named Windows Accounts.

In either case, find your username, and click the edit icon in the keys column, then click Manage. You can import your key from this screen. After you import, you'll see your entry in the list.

Connect to the Server Using Your SSH Key

The next step is using your SSH client to connect. From a command line, run the following command.

ssh -i ~/.ssh/server1.pem superman@server1.domain.com

In putty, open SSH from the Connection drop down and then click Auth. You'll be able to import your private key there.

Important for Putty users: if you didn't use puttygen to generate your private key but you want to use putty for your SSH needs, you'll need to convert your private key into a .ppk file. This is simple. Open puttygen and select Import key from the Conversions menu. Browse to your private key and and enter its password (if you supplied one). You can then save the private key in the .ppk format that putty expects. You don't have to bother with the corresponding public key.

When you make the connection you will be prompted for a password but it is

not

the account password.  The password you are prompted for is for

unlocking your private key

. Enter it correctly and SSH will use the key to communicate with the server having never sent your actual password to the server.

Stop Repeatedly Entering Passwords

We could stop here and feel good about augmenting our connection security but we can still simplify our lives further by reducing the number of times we'll need to enter the key's password.

 Mac OSX

On a Mac, this really couldn't be simpler. Not only is ssh-agent started each time your computer starts up, it also loads into itself any SSH keys it finds in your keychain. Further, when connecting over SSH to a server using a key that isn't in the keychain, keychain will pop up and ask for the password and [optionally] store it for you. If you choose to store it, ssh-agent will never prompt you for it again. Instead, it will just get it from keychain whenever it needs it. Check it out.

By running the following command, I'm prompted to store the password in keychain.

ssh -i ~/.ssh/superman.pem superman@server1.domain.com

Since ssh-agent is already running, it will get the password from the keychain when I attempt to connect. This is a Mac-Specific feature and really sweet.

Now that the server's identity has been added to ssh-agent (automattically), I never have to point to my private key again.

ssh superman@server1.domain.com

...will work without [prompting for] a password now.

Linux / Cygwin

ssh-agent still works fine with Linux and cygwin but it's a bit more manual.

First, you need to start the ssh-agent by running the command ssh-agent.

Run the following command to add your private key identity to the ssh-agent.

ssh-add ~/.ssh/superman.pem

The screen shot below describes what's happening.

ssh-add -D removes all identities from the ssh-agent.

ssh-add -l lists all identities in the ssh-agent.

ssh-add superman.pem add the private to the ssh-agent (notice I'm inside my .ssh directory)

ssh-add -l shows the newly added identity.

Once added, I can now ssh to server1 using the standard ssh connection string:

ssh superman@server1.domain.com

Loading ssh-agent at Startup

It's important to note that ssh-agent is session-based. It only stores identities during the current session. As soon as your computer is shutdown/rebooted, the agent no longer contains identities.

Mac OSX: ssh-agent is started and loaded automatically. You don't need to do anything else.

 Linux

Some distros will start ssh-agent on start up. To check if you're currently running ssh-agent, run this command:

ps aux | grep ssh-agent

If it's running, you're good and don't need to do anything else. If it's not running, you can put the following bit of shell code in your .bashrc file.

Cygwin

Coming soon...