Is there a convenient way to ensure that all logins from a given user (ie me) use the same ssh-agent? I hacked out a script to make this work most of the time, but I suspected all along that there was some way to do it that I had just missed. Additionally, since that time there have been amazing advances in computing technology, like for example this website.
So the goal here is that
- whenever I log in to the box, regardless of whether it’s via SSH, or in a graphical session started from gdm/kdm/etc, or at a console:
- if my username does not currently have an
ssh-agent
running, one is started, the environment variables exported, andssh-add
called.- otherwise, the existing agent’s coordinates are exported in the login session’s environment variables.
This facility is especially valuable when the box in question is used as a relay point when
ssh
ing into a third box. In this case it avoids having to type in the private key’s passphrase every time you ssh in and then want to, for example, dogit push
or something.The script given below does this mostly reliably, although it botched recently when X crashed and I then started another graphical session. There might have been other screwiness going on in that instance.
Here’s my bad-is-good script. I source this from my
.bashrc
.# ssh-agent-procure.bash# v0.6.4# ensures that all shells sourcing this file in profile/rc scripts use the same ssh-agent.# copyright me, now; licensed under the DWTFYWT license.mkdir -p "$HOME/etc/ssh";function ssh-procure-launch-agent { eval `ssh-agent -s -a ~/etc/ssh/ssh-agent-socket`; ssh-add;}if [ ! $SSH_AGENT_PID ]; then if [ -e ~/etc/ssh/ssh-agent-socket ] ; then SSH_AGENT_PID=`ps -fC ssh-agent |grep 'etc/ssh/ssh-agent-socket' |sed -r 's/^S+s+(S+).*$/1/'`; if [[ $SSH_AGENT_PID =~ [0-9]+ ]]; then # in this case the agent has already been launched and we are just attaching to it. ##++ It should check that this pid is actually active & belongs to an ssh instance export SSH_AGENT_PID; SSH_AUTH_SOCK=~/etc/ssh/ssh-agent-socket; export SSH_AUTH_SOCK; else # in this case there is no agent running, so the socket file is left over from a graceless agent termination. rm ~/etc/ssh/ssh-agent-socket; ssh-procure-launch-agent; fi; else ssh-procure-launch-agent; fi;fi;
Please tell me there’s a better way to do this. Also please don’t nitpick the inconsistencies/gaffes ( eg putting
var
stuff inetc
); I wrote this a while ago and have since learned many things.
Solution:
I might as well throw my own variation into the mix:
function sshagent_findsockets { find /tmp -uid $(id -u) -type s -name agent.* 2>/dev/null}function sshagent_testsocket { if [ ! -x "$(which ssh-add)" ] ; then echo "ssh-add is not available; agent testing aborted" return 1 fi if [ X"$1" != X ] ; then export SSH_AUTH_SOCK=$1 fi if [ X"$SSH_AUTH_SOCK" = X ] ; then return 2 fi if [ -S $SSH_AUTH_SOCK ] ; then ssh-add -l > /dev/null if [ $? = 2 ] ; then echo "Socket $SSH_AUTH_SOCK is dead! Deleting!" rm -f $SSH_AUTH_SOCK return 4 else echo "Found ssh-agent $SSH_AUTH_SOCK" return 0 fi else echo "$SSH_AUTH_SOCK is not a socket!" return 3 fi}function sshagent_init { # ssh agent sockets can be attached to a ssh daemon process or an # ssh-agent process. AGENTFOUND=0 # Attempt to find and use the ssh-agent in the current environment if sshagent_testsocket ; then AGENTFOUND=1 ; fi # If there is no agent in the environment, search /tmp for # possible agents to reuse before starting a fresh ssh-agent # process. if [ $AGENTFOUND = 0 ] ; then for agentsocket in $(sshagent_findsockets) ; do if [ $AGENTFOUND != 0 ] ; then break ; fi if sshagent_testsocket $agentsocket ; then AGENTFOUND=1 ; fi done fi # If at this point we still haven't located an agent, it's time to # start a new one if [ $AGENTFOUND = 0 ] ; then eval `ssh-agent` fi # Clean up unset AGENTFOUND unset agentsocket # Finally, show what keys are currently in the agent ssh-add -l}alias sagent="sshagent_init"
And then every time I log in, if I want an agent attached (which I don’t always), I just type sagent
.