Beating the Secure Shell Password Rap

| No Comments

I am a fan of SSH (Secure Shell), which moves bits around safely in a myriad of amazing ways. Tunneling, X11 forwarding, keepalives, passwordless access, ... it just gets better and better.

One part I didn't get my head around until recently is the "passwordless" thing and exactly how far you can go with that.

First there were keys...

In the simplest case, you type ssh ssh.example.com, give a password, and you're in.

An alternative -- and potentially passwordless -- way to make an SSH connection is with "keys" (i.e. using public-key cryptography).

For this, you have a pair of keys, the "private" one on the client and the "public" one on the server. (Conceptually) The SSH client encrypts something with the private key and, if it decrypts successfully with the public key, then it must have come from a Good Guy, and you're in.

You can make a passwordless key pair by typing:

ssh-keygen -t rsa -N ''

Copy the public key that's generated over to the server and put it in ~/.ssh/authorized_keys and you're off. (Actually, it's very fussy about permissions and things; never mind, there are hundreds of how-tos about that all over the 'net.)

The security problem here is that, if someone gets at your client account (as you, as root, by nicking your laptop, ...), they've got your private key and can use it.

The first step back from the brink is to put a "passphrase" (a password in high heels) on your private key. Leave off the -N argument to ssh-keygen. (You can also use ssh-keygen to add a passphrase to a previously-passwordless key.)

But, strangely, we're back where we started: Giving a passphrase every time you use a key feels exactly the same as giving a password each time.

... And then there were agents

The tool you want (and the main point of this note) is ssh-agent.

It is a program that starts up, you tell it about your keys (i.e. hand over the passphrases), and then the SSH client cooperates with the agent to hand out keys when required -- no passphrases.

So: machine boots up, you login... quick session with ssh-agent... no passphrases after that. Perfect.

Nowadays an ssh-agent is started for you as part of the login process. Do env | grep SSH_, and if you see something for the environment variable SSH_AUTH_SOCK, then you are already agent'd up.

How do you tell the agent about your keys (or "identities" as it likes to call them)? That's what ssh-add is for. If you have just one key (not unusual), then just type:

ssh-add

give your private key's passphrase, and declare victory.

You can list keys/identities managed by the agent (ssh-add -l), or delete a key (ssh-add -d), or lock your agent with a password while you go to lunch (ssh-add -x).

How does the SSH client know which ssh-agent to chat with about your keys? It gets the information from those environment variables SSH_AUTH_SOCK and SSH_AGENT_PID.

And what about cron jobs? (or other scripted tasks)

A hard passwordy problem is cron jobs, with something like backups being a common and nasty example. You need to move bits from one machine to another (so SSH is just the thing) but you need to do it as root. It must run completely unattended.

Putting the root password in a backup script -- no doubt often done... -- is a complete non-starter.

Passphrase-less keys are much better, and OpenSSH provides many extra ways to mitigate the risk, e.g. only allowing connections from certain IP addresses.

But the fact remains: If someone gets one of root's passphraseless private keys, it's fairly worrying.

So can we play the ssh-agent game to limit this risk? Yes.

It is possible to start up an agent by hand (or by script), and save the SSH_ environment variables (which it will emit) in a Well Known Location. Scripts can then source those variables (from the Well Known Location) and get the benefit of the agent.

Is that the best we can do?

Yes. When a machine (re)boots, an ssh-agent can be started, the needed environment-variables recorded, and someone ssh-adds all of the keys that will be needed (i.e. gives their passphrases). That is the least human interaction possible for really quite-secure unattended SSHing.

As long as the machine stays up, scripts should be able to work without any passphrases.

Lingering risks

The SSH_AUTH_SOCK environment variable points to a socket in the filesystem (with restricted permissions). Surely, if I can get read/write permission to that socket (e.g. if I'm root), then I can use the ssh-agent to take advantage of post-passphrase SSH keys?

Yes, that's right. Two things: (a) If someone is already on your system, perhaps as root, you already have a big problem, never mind SSHing. (b) The bad guy can use your key through the agent, but cannot get a copy of the private key itself.

Summary points

There are almost-as-convenient ways to use passphrase-laden SSH keys as the much-more-vulnerable passphrase-less ones. Use them!

You can get comparable security even for unattended automated tasks (scripting).

[An earlier version of this note appeared in Verilab's internal newsletter.]

Leave a comment

About this Entry

This page contains a single entry by Will Partain published on February 17, 2009 1:23 AM.

It shouldn't be this hard was the previous entry in this blog.

RPM capabilities is the next entry in this blog.

Find recent content on the main index or look in the archives to find all content.