Sharing the same `ssh-agent` among multiple login sessions

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, and ssh-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 sshing 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, do git 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 in etc ); 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.