Understanding ssh-agent and ssh-add

You may have come across the following message when doing some operation that uses your private key, such as working with git or ssh:

Enter passphrase for key '/home/user/.ssh/id_rsa':

So you go ahead an enter your password, allowing the key to be used. This is fine, at least for the first time. You definitely want a passphrase on your keys, so that there's some level of security against someone hijacking your computer, but you don't want the inconvenience of having to type your passphrase every damn time you use your key.

ssh-agent and ssh-add

You can fix this problem with a combination of ssh-agent and ssh-add. The agent should be running in the background, which allows us to use ssh-add to permanently authorise the use of our keys for the agent's session.

For too long I didn't understand the basic operation of these commands, so I took a shotgun approach to managing my key authorisation (mainly lifted from various blog posts, which were few and far between). For a long time, I lived with this code in my shell's configuration file without understanding what it was doing:

eval $(ssh-agent) > /dev/null

This created a new agent every time I started a new shell (i.e. a new terminal tab, or a new window in tmux). If I had 10 windows open, which isn't unusual, I would have 10 ssh-agents running. On top of this, I would have to run ssh-add in every shell to allow the use of my keys, or suffer the repeated requests for my key's passphrase.

This was clearly the wrong way of doing things, and I couldn't find a single post that seemed to recognise my problem, let alone offer a sensible solution. So I took a step back and started looking at how the agent worked.

A closer look at ssh-agent

Running ssh-agent in your terminal starts a daemon process and outputs a few lines of shell script:

$ ssh-agent
SSH_AUTH_SOCK=/tmp/ssh-MUyniqn10506/agent.10506; export SSH_AUTH_SOCK;
echo Agent pid 10507;

We can check that the agent is running:

$ ps x | grep ssh-agent
10507 ?        Ss   0:00 ssh-agent

If we take a closer look at the shell script that the command spat out, we can see that it's setting some environment variables. Specifically, it's setting $SSH_AUTH_SOCK and $SSH_AGENT_PID.

Unsurprisingly, $SSH_AGENT_PID is set to the PID of the agent daemon, which we confirmed by checking the process table. This is used by ssh-agent -k, which kills the agent whose PID is set in that environment variable. It's not essential for ssh-add, however.

$SSH_AUTH_SOCK contains the path of the unix file socket that the agent uses for communication with other processes. This is essential for ssh-add. If you try to run ssh-add without this environment variable set, or with an incorrect one, you will get the following error:

Could not open a connection to your authentication agent.

I don't fully understand the design decision behind ssh-agent, which prints fairly essential information out as executable code, and doesn't update the current shell with the required environment variables; that just seems a bit bizarre to me. But it is what it is, and the bottom line is that we need to keep track of our agent's file socket to be able to be able to remember the passphrases for our keys across multiple shell sessions.

Starting the ssh-agent and updating the current shell

Very simply, instead of running ssh-agent and having to copy and execute the output to your current shell, you can just evaluate the output:

$ eval $(ssh-agent) > /dev/null

The output redirect just gets rid of the printed "Agent pid blah blah".

We can then run ssh-add, which unlocks our key permanently (or start the agent with the -t switch to specify a lifetime), allowing us to have blissful, uninterrupted private-key-based activity; truly the stuff of dreams.

Using the same agent across multiple shell sessions

It would be a pain to have to manually set the $SSH_AUTH_SOCK environment variable in every new shell session. As first-world developer problems go, this ranks quite highly. Fortunately, a delightful chap named Wayne Walker has written a small bash script to locate compatible ssh-agent processes and update the environment accordingly - you can find it on github here.

Download it somewhere accessible (e.g. ~/.ssh-find-agent) and add the following to your shell's configuration file (e.g. ~/.bashrc, ~/.zshrc):

source ~/.ssh-find-agent/ssh-find-agent.bash

Each new shell session will look for an existing ssh-agent session and update the $SSH_AUTH_SOCK environment variable. If you have run ssh-add previously then you won't need to reauthorise your keys.

Nice one Wayne!

← Previous post: Creating a Cinch plugin part 3: a word game bot for IRC Next post: Using Vim as a multi-language IDE →
comments powered by Disqus