Using ssh-agent#

The OpenSSH program ssh-agent is a program to hold private keys used for public key authentication (RSA, DSA). The idea is that you store your private key in the ssh authentication agent and can then log in or use sftp as often as you need without having to enter your passphrase again. This is particularly useful when setting up a ssh proxy connection (e.g., for the Tier-1 system muk) as these connections are more difficult to set up when your key is not loaded into an ssh-agent.

This all sounds very easy. The reality is more difficult though. The problem is that subsequent commands, e.g., the command to add a key to the agent or the ssh or sftp commands, must be able to find the ssh authentication agent. Therefore some information needs to be passed from ssh-agent to subsequent commands, and this is done through two environment variables: SSH_AUTH_SOCK and SSH_AGENT_PID. The problem is to make sure that these variables are defined with the correct values in the shell where you start the other ssh commands.

Starting ssh-agent: Basic scenarios#

There are a number of basic scenarios

  1. You’re lucky and your system manager has set up everything so that ssh-agent is started automatically when the GUI starts after logging in and the environment variables are hence correctly defined in all subsequent shells. You can check for that easily: type

    $ ssh-add -l
    

    If the command returns with the message

    Could not open a connection to your authentication agent.
    

    then ssh-agent is not running or not configured properly, and you’ll need to follow one of the following scenarios.

  2. Start an xterm (or whatever your favourite terminal client is) and continue to work in that xterm window or other terminal windows started from that one:

    $ ssh-agent xterm &
    

    The shell in that xterm is then configured correctly, and when that xterm is killed, the ssh-agent will also be killed.

  3. ssh-agent can also output the commands that are needed to configure the shell. These can then be used to configure the current shell or any further shell, e.g., if you’re a bash user, an easy way to start a ssh-agent and configure it in the current shell, is to type

    $ eval `ssh-agent -s`
    

    at the command prompt. If you start a new shell (e.g., by starting an xterm) from that shell, it should also be correctly configured to contact the ssh authentication agent. A better idea though is to store the commands in a file and excute them in any shell where you need access to the authentication agent, e.g., for bash users:

    $ ssh-agent -s >~/.ssh-agent-environment
    . ~/.ssh-agent-environment
    

    and you can then configure any shell that needs access to the authentication agent by executing

    $ . ~/.ssh-agent-environment
    

    Note that this will not necessarily shut down the ssh-agent when you log out of the system. It is not a bad idea to explicitly kill the ssh-agent before you log out:

    $ ssh-agent -k
    

Managing keys#

Once you have an ssh-agent up and running, it is easy to add your key to it. Assuming your key is ~/.ssh/id_rsa_vsc, type the following at the command prompt:

$ ssh-add ~/.ssh/id_rsa_vsc

You will then be asked to enter your passphrase.

To list the keys that ssh-agent is managing, type

$ ssh-add -l

You can now use the OpenSSH commands ssh, sftp and scp without having to enter your passphrase again.

Starting ssh-agent: Advanced options#

In case ssh-agent is not started by default when you log in to your computer, there’s a number of things you can do to automate the startup of ssh-agent and to configure subsequent shells.

Ask your local system administrator#

If you’re not managing your system yourself, you can always ask your system manager if he can make sure that ssh-agent is started when you log on and in such a way that subsequent shells opened from the desktop have the environmental variables SSH_AUTH_SOCK and SSH_AGENT_PID set (with the first one being the most important one).

And if you’re managing your own system, you can dig into the manuals to figure out if there is a way to do so. Since there are so many desktop systems avaiable for Linux systems (gnome, KDE, Ubuntu unity, …) we cannot offer help here.

A semi-automatic solution in bash#

This solution requires some modifications to .bash_profile and .bashrc. Be careful when making these modifications as errors may lead to trouble to log on to your machine. So test by executing these files with source ~/.bash_profile and source ~/.bashrc.

This simple solution is based on option 3 given above to start ssh-agent.

  1. You can define a new shell command by using the bash alias mechanism. Add the following line to the file .bashrc in your home directory:

    alias start-ssh-agent='/usr/bin/ssh-agent -s >~/.ssh-agent-environment; . ~/.ssh-agent-environment'
    

    The new command start-ssh-agent will now start a new ssh-agent, store the commands to set the environment variables in the file .ssh-agent-environment in your home directory and then “source” that file to execute the commands in the current shell (which then sets SSH_AUTH_SOCK and SSH_AGENT_PID to appropriate values).

  2. Also put the line

    [[ -s ~/.ssh-agent-environment ]] && . ~/.ssh-agent-environment &>/dev/null
    

    in your .bashrc file. This line will check if the file ssh-agent-environment exists in your home directory and “source” it to set the appropriate environment variables.

  3. As explained in the GNU bash manual, .bashrc is only read when starting so-called interactive non-login shells. Interactive login shells will not read this file by default. Therefore it is advised in the GNU bash manual to add the line

    [[ -s ~/.bashrc ]] && . ~/.bashrc
    

    to your .bash_profile. This will execute .bashrc if it exists whenever .bash_profile is called.

You can now start a SSH authentication agent by issuing the command start-ssh-agent and add your key as indicated above with ssh-add.

An automatic and safer solution in bash#

One disadvantage of the previous solution is that a new ssh-agent will be started every time you execute the command start-ssh-agent, and all subsequent shells will then connect to that one.

The following solution is much more complex, but a lot safer as it will first do an effort to see if there is already a ssh-agent running that can be contacted:

  1. It will first check if the environment variable SSH_AUTH_SOCK is defined, and try to contact that agent. This makes sure that no new agent will be started if you log on onto a system that automatically starts an ssh-agent.

  2. Then it will check for a file .ssh-agent-environment, source that file and try to connect to the ssh-agent. This will make sure that no new agent is started if another agent can be found through that file.

  3. And only if those two tests fail will a new ssh-agent be started.

This solution uses a Bash function.

  1. Add the following block of text to your .bashrc file:

    start-ssh-agent() {
    #
    # Start an ssh agent if none is running already.
    # * First we try to connect to one via SSH_AUTH_SOCK
    # * If that doesn't work out, we try via the file ssh-agent-environment
    # * And if that doesn't work out either, we just start a fresh one and write
    #   the information about it to ssh-agent-environment for future use.
    #
    # We don't really test for a correct value of SSH_AGENT_PID as the only
    # consequence of not having it set seems to be that one cannot kill
    # the ssh-agent with ssh-agent -k. But starting another one wouldn't
    # help to clean up the old one anyway.
    #
    # Note: ssh-add return codes:
    #   0 = success,
    #   1 = specified command fails (e.g., no keys with ssh-add -l)
    #   2 = unable to contact the authentication agent
    #
    sshfile=~/.ssh-agent-environment
    #
    # First effort: Via SSH_AUTH_SOCK/SSH_AGENT_PID
    #
    if [ -n \"$SSH_AUTH_SOCK\" ]; then
      # SSH_AUTH_SOCK is defined, so try to connect to the authentication agent
      # it should point to. If it succeeds, reset newsshagent.
      ssh-add -l &>/dev/null
      if [[ $? != 2 ]]; then
        echo \"SSH agent already running.\"
        unset sshfile
        return 0
      else
        echo \"Could not contact the ssh-agent pointed at by SSH_AUTH_SOCK, trying more...\"
      fi
    fi
    #
    # Second effort: If we're still looking for an ssh-agent, try via $sshfile
    #
    if [ -e \"$sshfile\" ]; then
      # Load the environment given in $sshfile
      . $sshfile &>/dev/null
      # Try to contact the ssh-agent
      ssh-add -l &>/dev/null
      if [[ $? != 2 ]]; then
        echo \"SSH agent already running; reconfigured the environment.\"
        unset sshfile
        return 0
      else
        echo \"Could not contact the ssh-agent pointed at by $sshfile.\"
      fi
    fi
    #
    # And if we haven't found a working one, start a new one...
    #
    #Create a new ssh-agent
    echo \"Creating new SSH agent.\"
    ssh-agent -s > $sshfile && . $sshfile
    unset sshfile
    }
    

    A shorter version without all the comments and that does not generate output is

    start-ssh-agent() {
    sshfile=~/.ssh-agent-environment
    #
    if [ -n \"$SSH_AUTH_SOCK\" ]; then
      ssh-add -l &>/dev/null
      [[ $? != 2 ]] && unset sshfile && return 0
    fi
    #
    if [ -e \"$sshfile\" ]; then
      . $sshfile &>/dev/null
      ssh-add -l &>/dev/null
      [[ $? != 2 ]] && unset sshfile && return 0
    fi
    #
    ssh-agent -s > $sshfile && . $sshfile &>/dev/null
    unset sshfile
    }
    

    This defines the command start-ssh-agent.

  2. Since start-ssh-agent will now first check for a usable running agent, it doesn’t harm to simply execute this command in your .bashrc file to start a SSH authentication agent. So add the line

    start-ssh-agent &>/dev/null
    

    after the above function definition. All output is sent to /dev/null (and hence not shown) as a precaution, since scp or sftp sessions fail when output is generated in .bashrc on many systems (typically with error messages such as \”Received message too long" or “Received too large sftp packet”). You can also use the newly defined command start-ssh-agent at the command prompt. It will then check your environment, reset the environment variables SSH_AUTH_SOCK and SSH_AGENT_PID or startk a new ssh-agent.

  3. As explained in the GNU bash manual, .bashrc is only read when starting so-called interactive non-login shells. Interactive login shells will not read this file by default. Therefore it is advised in the GNU bash manual to add the line

    [[ -s ~/.bashrc ]] && . ~/.bashrc
    

    to your .bash_profile. This will execute .bashrc if it exists whenever .bash_profile is called.

You can now simply add your key as indicated above with ssh-add and it will become available in all shells.

The only remaining problem is that the ssh-agent process that you started may not get killed when you log out, and if it fails to contact again to the ssh-agent when you log on again, the result may be a built-up of ssh-agent processes. You can always kill it by hand before logging out with ssh-agent -k.