On Linux systems it’s common to use ssh-agent (manpage) to store SSH keys. When you run the agent its output can be used to configure it within your shell. The variables defined allow ssh
and ssh-add
to find the agent once it’s started.
$ ssh-agent SSH_AUTH_SOCK=/tmp/ssh-RRekSLl29890/agent.29890; export SSH_AUTH_SOCK; SSH_AGENT_PID=29891; export SSH_AGENT_PID; echo Agent pid 29891;
I use an Ubuntu VM, and regularly log in using PuTTY. It’s easy to connect to the agent on login, but I wanted a way to keep connecting back to the same one so I could add keys and leave them there. There’s loads of solutions available, but I wanted to try and write a simpler version.
Strategy:
- Store the agent settings into a file under
~/.ssh
- Load the file on login
- Check whether the agent can be found, and if it can’t start it
This is slightly more subtle than it first appears: it’s necessary to cope with the file not existing and containing out-of-date data, and I wanted to do this as tidily as possible.
Here’s my solution:
[ -f ~/.ssh/agent_env ] && . ~/.ssh/agent_env kill -0 $SSH_AGENT_PID 2> /dev/null || . <(ssh-agent | tee ~/.ssh/agent_env)
First we check if the file exists:
[ -f ~/.ssh/agent_env ]
If it does then we execute its contents using a bash shortcut (the ‘.
‘):
. ~/.ssh/agent_env
If the file did exist then we should have a value for the SSH_AGENT_PID
. We check whether it’s possible to send a signal to the process this identifies using kill -0
:
kill -0 $SSH_AGENT_PID
The nice thing about this is that if the variable isn’t defined then we end up passing garbage on to kill
, and it’ll return false in the same way as if the process didn’t exist. We add a redirect to /dev/null
so we don’t see its helpful error message.
kill -0 $SSH_AGENT_PID 2> /dev/null
Now we just need to run the agent, store its output in the file, and use that output to configure the shell. We can use a bash trick to load the agent and configure the shell in one tidy step:
. <(ssh-agent)
The redirect here has the effect of attaching the ssh-agent output to a file descriptor, and then returning the path to that file descriptor. It’s convenient when you want to pass the output of a command to one which is expecting a filename.
Finally we insert a call to tee
which writes out our file.
. <(ssh-agent | tee ~/.ssh/agent_env)