80

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.

3
  • 1
    KeyError: 'DWTFYWT' not found; did you mean WTFPLv2? May 14, 2010 at 18:53
  • @grawity: thanks for that link, their FAQs made my day: By the way, with the WTFPL, can I also… Oh but yes, of course you can. But can I… Yes you can. Can… Yes! hahahahahaha May 14, 2010 at 19:06
  • @grawity: No, that's just what I wanted you to think, mwahahaha.
    – intuited
    May 14, 2010 at 20:58

20 Answers 20

33

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.

9
  • 2
    if [ ! -x "$(which ssh-add)" ]; should be replaced with if ! which ssh-add; or if ! command -v ssh-add. (Remember, [ is just a command) May 14, 2010 at 19:13
  • Well, you can do that, but it would actually need to be if ! which ssh-add > /dev/null to prevent the path from being printed, at which point I'm not really sure it's any clearer, though I suppose it does save you one extra command invocation.
    – Zed
    May 14, 2010 at 20:32
  • so basically the answer is no, then. crap. Well this looks to be more evolved than my hack, so probably it will be useful. Weird that there's not a more structured way of doing this though, it seems like something that would be quite useful.
    – intuited
    May 14, 2010 at 20:56
  • I'm in a fit of repositorifying everything these days, so I set up a github repo for your script. Thanks again. I hope I was formal enough with the licensing :~/
    – intuited
    Jul 27, 2010 at 2:03
  • I don't mind. Please comment here if someone submits improvements to it, though.
    – Zed
    Aug 27, 2010 at 19:37
51

ssh -A [user@]remotehost

I think this might be what you're looking for. Use the -A switch when running ssh forward your ssh-agent. Here's a usecase:

I have a remote server that has some git repos on it with a remote pointing to github. Without an ssh-agent running in a screen session, I have to enter the passphrase for my key in order to do a "git pull origin master". Booo! In addition, I must have my private key installed on the remote server - more Boooo!

Instead, simply using ssh -A [user@]remotehost passes along my locally running ssh-agent. Now, I no longer need my private key to even exist on the remote host. I don't believe you need to do any scripting at all with ssh-agent.

6
  • 5
    Did not know about this, but it turned out to be exactly what I was looking for when I made my way to this question. Nov 17, 2011 at 14:34
  • 2
    This is even better than what I was looking for! Great answer!
    – WhyNotHugo
    Jan 28, 2013 at 5:30
  • 4
    See also man 5 ssh_config for the ForwardAgent config setting. It enables agent forwarding by default, removing the need for the -A argument. Before using agent forwarding be aware that there is a security risk where other privileged users on the remote machine could access the forwarded agent socket. This is also mentioned on the man page. This is explained well here.
    – starfry
    Jun 23, 2014 at 10:00
  • 1
    I think the AllowAgentForwarding option must be set to yes on the server, though
    – Ziofil
    Jan 11, 2019 at 15:48
  • 1
    to clarify, this forwards your local ssh-agent to the remote machine, the original question is about sharing the remote machine's ssh-agent across multiple logins on that machine. Both are useful!
    – JBCP
    Sep 30, 2020 at 14:18
25

Here's a pretty nice one that works in Cygwin as well:

SSH_ENV=$HOME/.ssh/environment

function start_agent {
     echo "Initialising new SSH agent..."
     /usr/bin/ssh-agent | sed 's/^echo/#echo/' > ${SSH_ENV}
     echo succeeded
     chmod 600 ${SSH_ENV}
     . ${SSH_ENV} > /dev/null
     /usr/bin/ssh-add;
}

# Source SSH settings, if applicable

if [ -f "${SSH_ENV}" ]; then
     . ${SSH_ENV} > /dev/null
     #ps ${SSH_AGENT_PID} doesn't work under cywgin
     ps -efp ${SSH_AGENT_PID} | grep ssh-agent$ > /dev/null || {
         start_agent;
     }
else
     start_agent;
fi

Add it to your .bash_profile or .bashrc

Source: http://www.cygwin.com/ml/cygwin/2001-06/msg00537.html

5
  • Also works fine with Git Bash (mingw64) for windows
    – Dolphin
    May 4, 2016 at 16:39
  • 1
    ${SSH_ENV} needs to be "${SSH_ENV}" if your windows username has a space in it
    – rgvcorley
    Jan 23, 2017 at 14:15
  • 1
    This answer seems to be bouncing around the internet. Here it is on a much bigger stackoverflow thread. The best/simplest approach IMHO.
    – Luke Davis
    Jul 13, 2018 at 19:34
  • Yup, just quote SSH_ENV variable, it is the solution to use. Jan 5, 2021 at 19:35
  • I use this solution with git and windows terminal. I just replaced this line (in start_agent function) : bash> /usr/bin/ssh-add; by bash> ssh-add -t 3600 ~/.ssh/my-private-key.rsa This private key is stored in my .ssh for sure (with public key) I enter just one time my passphrase for this key and it's available for 1 hour. (-t 3600) Each time I open new git-bash console, my certificate is available : no needs to enter anew passphrase. You can control availability with this command : bash> ssh-add -l => my key is well available Jan 28 at 14:59
13

Try using keychain, its made for that. http://www.gentoo.org/doc/en/keychain-guide.xml

1
9

I have recently started using:

https://github.com/ccontavalli/ssh-ident

All I have to do is add:

  alias ssh=/path/to/ssh-ident

In my .bashrc file. The script takes care of:

  • creating an agent when it is first needed
  • load the necessary keys on demand
  • share agents across multiple login sessions
  • manage multiple agents, one for each 'identity' that I use online, and use the right agent based on the host I'm connecting to or the current working directory.
1
  • 1
    ssh-ident is fantastic! It unlocks the key and loads the agent when I try to ssh instead of having to unlock the key in advance. This makes key timeouts useful. More importantly, it keeps my agents separate for different uses (a major security risk; root on one machine has my access level to all other machines that the current agent has keys for!) Sep 30, 2016 at 1:38
8

I prefer to keep things as simple as possible: (snippet from ~/.profile)

check-ssh-agent() {
    [ -S "$SSH_AUTH_SOCK" ] && { ssh-add -l >& /dev/null || [ $? -ne 2 ]; }
}

# attempt to connect to a running agent
check-ssh-agent || export SSH_AUTH_SOCK="$(< ~/.tmp/ssh-agent.env)"
# if agent.env data is invalid, start a new one
check-ssh-agent || {
    eval "$(ssh-agent -s)" > /dev/null
    echo "$SSH_AUTH_SOCK" > ~/.tmp/ssh-agent.env
}

I didn't think of using -a before, but it might be easier:

check-ssh-agent || export SSH_AUTH_SOCK=~/.tmp/ssh-agent.sock
check-ssh-agent || eval "$(ssh-agent -s -a ~/.tmp/ssh-agent.sock)" > /dev/null
1
  • Nice. I've simplified it somewhat in my answer (below).
    – Ether
    Mar 6, 2015 at 20:15
3

In simple do this

eval $(ssh-agent | tee agent.env)

then from other terminals or subsequent sessions,

source agent.env

Tighten up the permissions to be slightly more secure,

chmod go-rwx agent.env

https://unix.stackexchange.com/questions/439254/use-my-already-running-ssh-agent-process

1
  • FWIW if you use ~/.ssh/agent.env then you get a bit of a bonus since your .ssh should already be go-rwx Feb 26, 2023 at 16:34
2

Again an example to put in your .bash_profile immediately and asking to add your default key at logon. Forwarding was not an option in my case.

do-ssh-agent() {
  # function to start the ssh-agent and store the agent details for later logon
  ssh-agent -s > ~/.ssh-agent.conf 2> /dev/null
  . ~/.ssh-agent.conf > /dev/null
}

# set time a key should be kept in seconds
keyage=3600

if [ -f ~/.ssh-agent.conf ] ; then
  . ~/.ssh-agent.conf > /dev/null
  ssh-add -l > /dev/null 2>&1
  # $?=0 means the socket is there and it has a key
  # $?=1 means the socket is there but contains no key
  # $?=2 means the socket is not there or broken
  stat=$?
  if [ $stat -eq 1 ] ; then
    ssh-add -t $keyage > /dev/null 2>&1
  elif [ $stat -eq 2 ] ; then
    rm -f $SSH_AUTH_SOCK
    do-ssh-agent
    ssh-add -t $keyage > /dev/null 2>&1
  fi
else
  do-ssh-agent
  ssh-add -t $keyage > /dev/null 2>&1
fi
2

This is my solution, adapted from https://superuser.com/a/141233/5255 (in this thread):

# attempt to connect to a running agent - cache SSH_AUTH_SOCK in ~/.ssh/
sagent()
{
    [ -S "$SSH_AUTH_SOCK" ] || export SSH_AUTH_SOCK="$(< ~/.ssh/ssh-agent.env)"

    # if cached agent socket is invalid, start a new one
    [ -S "$SSH_AUTH_SOCK" ] || {
        eval "$(ssh-agent)"
        ssh-add -t 25920000 -K ~/.ssh/id_rsa
        echo "$SSH_AUTH_SOCK" > ~/.ssh/ssh-agent.env
    }
}
2

In my case I have posh-git setup in PowerShell and wanted cygwin to use the same ssh-agent. I had to do some path manipulation since they use different tmp folders, and the .env file created was UTF16 with BOM and CR\LF so that was fun to deal with. Adding the following to the .bashrc used by cygwin should work:

# Connect to ssh-agent started by posh-git
SSH_AGENT_ENV=$(cygpath "$LOCALAPPDATA\Temp")
if [ -z $SSH_AUTH_SOCK ] && [ -z $SSH_TTY ]; then  # if no agent & not in ssh
  if [ -f "$SSH_AGENT_ENV/.ssh/SSH_AUTH_SOCK.env" ]; then
    AUTH_SOCK=$(iconv -c -f UTF-16LE -t US-ASCII "$SSH_AGENT_ENV/.ssh/SSH_AUTH_SOCK.env" | tr -d '\r\n')
    export SSH_AUTH_SOCK="${AUTH_SOCK/\/tmp/$SSH_AGENT_ENV}"
    ssh-add -l > /dev/null
    if [ $? = 2 ] ; then
      echo "Failed to setup posh-git ssh-agent using $AUTH_SOCK"
      unset SSH_AUTH_SOCK
    else
      echo "Found posh-git ssh-agent $AUTH_SOCK"
    fi
  else #Start new agent if you want (not shared by posh-git)
    echo "failed to setup posh-git ssh-agent"
    #eval `ssh-agent -s` > /dev/null
  fi
fi
1

create file ~/ssh-agent.sh

agent_out_file="$HOME/ssh-agent.out"

function initialize {
    pgrep ssh-agent && kill $(pgrep ssh-agent)
    ssh-agent -s > $agent_out_file 
    . $agent_out_file
}

pgrep ssh-agent
if [ $? -eq 0 ]; then # ssh agent running
    ssh-add -l > /dev/null 2>&1
    status=$?
    if [ $status -eq 0 ]; then # can connect to ssh agent and keys available
        echo nothing to do
    elif [ $status -eq 1 ]; then # can connect to ssh agent and no keys available
        echo nothing to do
    elif [ $status -eq 2 ]; then # cannot connect to ssh agent
        . $agent_out_file
    fi
else # ssh agent not running
    initialize   
fi

include the file in .bashrc

. ~/ssh-agent.sh
1

This is something I've added which works for me. It first checks to see if you have an agent running, if yes it'll set the proper environments for it, if not it'll create it. Also eliminates creating extra agents:

Just put it in your .bashrc

function start_agent() {
    killall ssh-agent  2> /dev/null
    ssh-agent | sed 's/ Agent pid//' > $SSH_ENV
    . $SSH_ENV > $SSH_PID_FILE
    ssh-add ~/.ssh/bb_readonly_rsa 2> /dev/null
}

mkdir -p "$HOME/.ssh/agent"
SSH_ENV="$HOME/.ssh/agent/env"
SSH_PID_FILE="$HOME/.ssh/agent/pid"

if [[ -e $SSH_PID_FILE ]]; then
    SSH_PID=$(< $SSH_PID_FILE) 
    PROCESS=$(ps -p $SSH_PID -o comm=)

    if [[ $PROCESS == 'ssh-agent' ]]; then
        . $SSH_ENV > $SSH_PID_FILE
    else 
        start_agent
    fi  
else
    start_agent
fi
1

I know this is an old thread, and there are a lot of solutions already suggested. I just wanted to provide my super simple solution to this. In my shell's profile file I simply put this:

function __source_ssh_agent_env() {
  source "$HOME/.ssh/agent_env" > /dev/null
}

function __start_ssh_agent() {
  ssh-agent > ~/.ssh/agent_env
  __source_ssh_agent_env
}

## Make use of already running ssh-agent process
if [[ -f ~/.ssh/agent_env ]]; then
  __source_ssh_agent_env

  if ! ps -p "$SSH_AGENT_PID" > /dev/null; then
    __start_ssh_agent
  fi
else
  __start_ssh_agent
fi

What it does is simply just saving the output of ssh-agent into a file in my ~/.ssh directory. Then just sourcing the file, checking if the pid is running. If it's not running, start a new agent. Works well!

1
  • 1
    Welcome to Super User! Before answering an old question having an accepted answer (look for green ✓) as well as other answers ensure your answer adds something new or is otherwise helpful in relation to them. Here is a guide on How to Answer. There is also tour for the site tour, and help center for the help center. Jun 23, 2022 at 8:31
0

I have a variation on this problem, too, taken straight from my .bashrc:

# File for storing SSH agent information
OSH=".agent.${HOSTNAME}"

# Test if an agent file exists
if [ -f ${OSH} ];

    # We have one, so let's use it
    then eval `cat ${OSH}` >/dev/null

else

    # No file exists, so we must spawn a new agent
    eval `ssh-agent | tee ${OSH}` >/dev/null

fi

# Try to list agent keys
ssh-add -l &>/dev/null

# Determine the agent status
case $? in

    # Current and SSH keys installed, nothing to do here
    0) ;;

    # Current but no SSH keys installed, so we must add them
    1) ssh-add ;;

    # Stale, so we must redo from scratch with a new agent, then add keys
    *) eval `ssh-agent | tee ${OSH}` >/dev/null && ssh-add ;;

esac

This solution stores a copy of the SSH agent information in your home directory. In case you have an NFS-automounted home directory that might be shared between multiple hosts, the hostname is used as part of the filename to differentiate between them, so logging in from one machine won't clobber the agent file in use on another.

Behaviour:

1) First-time user sessions are prompted for a key passphrase.

2) Second-, third- and fourth- (et cetera) sessions inherit the SSH agent and key(s) added in the first.

3) If the agent is killed or crashes, the first subsequent session will create a new agent, overwrite the agent file with the new one - and prompt for a key passphrase again. Subsequently-created sessions will behave like scenario 2), as long as the new SSH agent remains running.

0

(this refers to the post 2 higher, I was unable to add a comment)

@raghavan: Your example is useful, but would suggest changing the two lines that have

pgrep ssh-agent

to

pgrep -u $USER ssh-agent >/dev/null

so that only agents running under the current user are found, and the pid is not echoed to the screen (cleaner).

Would also sugegst changing $HOME/ssh-agent.out to $HOME/.ssh-agent.out

Regards

0

I read your original solution and a number of the suggested ones, but decided to simplify the process for my own use. This is what I added in my own .bashrc :

    # get active ssh-agent, or launch new
    SSH_AGENT_PID=$(ps -fC ssh-agent | grep "ssh-agent -a ${HOME}/.ssh/ssh-agent-socket" | awk '{print $2}')
    if [ -z "${SSH_AGENT_PID}" ]; then
      # If there is no ssh-agent running, we'll make sure one hasn't left a socket file dangling
      rm ${HOME}/.ssh/ssh-agent-socket &> /dev/null
      # And of course start one
      eval $(ssh-agent -a ${HOME}/.ssh/ssh-agent-socket)
    else
      # We found a process matching our requirements, so sticking with that
      export SSH_AGENT_PID
      export SSH_AUTH_SOCK="${HOME}/.ssh/ssh-agent-socket"
    fi

I've made a couple of assumptions here:

  • That the ~/.ssh directory exists.
  • That you only want one ssh-agent socket per user on the system.
  • That the HOME environment variable is set (because why wouldn't it, right?).
  • That you will manually handle a situation where there is a process running, but it for some reason doesn't use the socket file designated.

All in all I think it feels like a simple solution.

0

I found that I often had multiple ssh-agent processes running, and that the PID inside the socket filename never actually matched the PID of a running ssh-agent, so I hacked something up to try to recover from these conditions, based on numerous examples above.

It's a single function, it uses a Zsh variable for user ID if it's there, and tries to spend less time parsing possibly huge /tmp directories by restricting find(1) a bit more.

It's probably still error-prone, and convoluted, but some cursory testing indicates it mostly works for my use cases, so here goes:

attach_ssh_agent () {
  if [ -n "$SSH_AGENT_PID" ]; then
    ssh-add -l >/dev/null
    ret=$?
    if [ $ret -ge 2 ]; then
      echo "Agent pid $SSH_AGENT_PID is less than useful (ret=$ret) - killing..."
      kill $SSH_AGENT_PID
      unset $SSH_AGENT_PID
    elif [ $ret = 1 ]; then
      echo "Agent pid $SSH_AGENT_PID is less than useful (ret=$ret) - will be seeding it..."
    else
      echo "Agent pid $SSH_AGENT_PID"
      return
    fi
  fi
  if [ -S "$SSH_AUTH_SOCK" ]; then
    ssh-add -l > /dev/null
    ret=$?
    if [ $ret = 2 ]; then
      echo "Socket $SSH_AUTH_SOCK is dead - deleting..."
      rm -f $SSH_AUTH_SOCK
      unset SSH_AUTH_SOCK
    elif [ $ret = 1 ]; then
      echo "Socket $SSH_AUTH_SOCK points to an agent with no keys..."
      ssh-add
    else
      echo "Found ssh-agent $SSH_AUTH_SOCK (ret=$ret)"
      return
    fi
  fi
  for sf in $(find /tmp/ -mindepth 2 -maxdepth 2 -uid ${UID:-$(id -u)} -path '/tmp/ssh-*/agent.*' -type s); do
    test -r $sf || continue
    export SSH_AUTH_SOCK=$sf
    SSH_AGENT_PID=$(basename $SSH_AUTH_SOCK | cut -d. -f2)
    # races with other process forks, argh
    try=50
    while [ $try -gt 0 ]; do
      try=$(($try-1))
      export SSH_AGENT_PID=$(($SSH_AGENT_PID+1))
      echo "Testing $SSH_AUTH_SOCK -> $SSH_AGENT_PID"
      ssh_agent_running=$(ps -u $USER | grep ssh-agent)
      if [ -z "$ssh_agent_running" ]; then
        echo "Socket $SSH_AUTH_SOCK does not contain a link to any running agent - deleting..."
        rm -f $SSH_AUTH_SOCK
        continue
      fi
      if echo "$ssh_agent_running" | \
           awk '$1 == '$SSH_AGENT_PID' {
                  found=1;
                  exit(0);
              }
              END {
                  if (!found) {
                      print "did not find running PID '$SSH_AGENT_PID'";
                      exit(1);
                  }
              }'; then
        ssh-add -l > /dev/null
        ret=$?
        if [ $ret -ge 2 ]; then
          echo "Socket $SSH_AUTH_SOCK does not contain a link to a useful agent at $SSH_AGENT_PID - deleting..."
          rm -f $SSH_AUTH_SOCK
          kill $SSH_AGENT_PID
          unset SSH_AGENT_PID
          continue 2
        elif [ $ret = 1 ]; then
          echo "Socket $SSH_AUTH_SOCK contains a link to a less than useful agent at $SSH_AGENT_PID - seeding..."
          ssh-add
          if ! ssh-add -l > /dev/null; then
            echo "Socket $SSH_AUTH_SOCK still contains a link to a less than useful agent at $SSH_AGENT_PID - aborting."
            return
          else
            break
          fi
        else
          break
        fi
      else
#        echo "Could not match socket $SSH_AUTH_SOCK to agent PID $SSH_AGENT_PID - skipping..."
        continue
      fi
    done
    if [ $try -gt 0 ]; then
      echo "Found ssh-agent $SSH_AUTH_SOCK"
      echo "Agent pid $SSH_AGENT_PID"
      return
    fi
  done
  if [ -n "$try" -a -n "$SSH_AUTH_SOCK" -a -n "$ssh_agent_running" ]; then
    echo "We tried many times, but could not match $SSH_AUTH_SOCK to any of the running agents, sigh"
    echo "$ssh_agent_running"
    echo "Leaving these leftovers behind and starting a new agent..."
  fi
  eval $(ssh-agent -t 28800)
  ssh-add
}
0

Here is my spin on this. I 'source' the below script from my .bash_profile:

MYAGENTS=(`pgrep -U $USER -f ^ssh-agent$|sort -n`)

echo "Found ${#MYAGENTS[@]} ssh-agents."

# Let's try to take over the agents, like we do everynight Pinky!
if [[ "${MYAGENTS[@]}" ]];then
  KEEPER=${MYAGENTS[0]}
  echo KEEPER: $KEEPER
  OUTCAST=${MYAGENTS[@]:1}
  [[ "$OUTCAST" ]] && { echo "Goodbye agent $OUTCAST"; kill $OUTCAST; }
  SSH_AUTH_SOCK=`awk '/tmp\/ssh/ {print $NF}' /proc/$KEEPER/net/unix`
  export SSH_AUTH_SOCK;
  SSH_AGENT_PID=$KEEPER; export SSH_AGENT_PID;
else
  NEWAGENT="`ssh-agent`"
  echo $NEWAGENT;
  eval $NEWAGENT
fi

ssh-add -l | grep "The agent has no identities" && ssh-add
0

Here's a simple script that will always re-use the same ssh-agent, or start ssh-agent if it isn't running. The key is to use the -a option to use the same socket name. Otherwise, by default it will choose a random socket name every time. You can easily combine these 3 lines into a 1 line alias as well.

# set SSH_AUTH_SOCK env var to a fixed value
export SSH_AUTH_SOCK=~/.ssh/ssh-agent.sock

# test whether $SSH_AUTH_SOCK is valid
ssh-add -l 2>/dev/null >/dev/null

# if not valid, then start ssh-agent using $SSH_AUTH_SOCK
[ $? -ge 2 ] && ssh-agent -a "$SSH_AUTH_SOCK" >/dev/null

source

0

A lot of answers mostly valid, but I share my short and simple way. Add it to yours ~/.bashrc or ~/.zshrc. It's similar to some upper responses.

# export socket variable
export SSH_AUTH_SOCK=~/.tmp/ssh-agent.sock
[ ! -d ~/.tmp ] && mkdir ~/.tmp # create dir if not exist ~/.tmp

# check is ssh-agent running and socket is valid
check-ssh-agent() {
    [ -S "$SSH_AUTH_SOCK" ] && { ssh-add -l >& /dev/null || [ $? -ne 2 ]; }
}

# if socket or agent is not valid/running create ssh-agent with socket from env variable
check-ssh-agent || eval "$(ssh-agent -s -a ${SSH_AUTH_SOCK})"

You can add all keys from ~/.ssh/config by this line:

cat ~/.ssh/config | grep IdentityFile | awk '{print $NF}' | sort | uniq | xargs ssh-add

You can add it after ssh-agent code in ~/.bashrc or ~/.zshrc or as alias:

alias ssh-add-keys="cat ~/.ssh/config | grep IdentityFile | awk '{print $NF}' | sort | uniq | xargs ssh-add"

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .