Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I want to communicate between several computers on my network (static ethernet), through ssh. In order to do that I need to run ssh-add every time I login on specific machine, how can I do it so that it's set up once and it doesn't ask me for passphrase every time I login or reboot my machine?

I know that there is a way that you should add some lines to bash_profile file, but I still need to type the password every time I reboot/login to a specific machine.

if [ -z "$SSH_AUTH_SOCK" ] ; then
    eval `ssh-agent -s`
    ssh-add
fi
share|improve this question
    

This is a typical example of a trade-off between security and convenience. Luckily there are a number of options. The most appropriate solution depends on the usage scenario and desired level of security.

ssh-key with passphrase, no ssh-agent

Now the passphrase has to be entered every time the key is used for authentication. While this is the best option from a security standpoint, it offers the worst usability. This may also lead to a weak passphrase being chosen in order to lessen the burden of entering it repeatedly.

ssh-key with passphrase, with ssh-agent

Adding the following to ~/.bash_profile will automatically start ssh-agent and load the ssh-key(s) on login:

if [ -z "$SSH_AUTH_SOCK" ] ; then
  eval `ssh-agent -s`
  ssh-add
fi

Now the passphrase must be entered upon every login. While slightly better from a usability perspective, this has the drawback that ssh-agent prompts for the passphrase regrdless of if the key is to be used or not during the login session.

On desktops, ssh-agents included with the desktop environment, such as the Gnome Keyring SSH Agent, can be a better approach as they typically can be made to prompt for the passphrase the first time the ssh-key is used during a login session and store the decrypted private key in memory until the end of the session.

ssh-key with passphrase, with keychain

keychain is a small utility which manages ssh-agent on your behalf and allows the ssh-agent to remain running when the login session ends. On subsequent logins, keychain will connect to the existing ssh-agent instance. In practice, this means that the passphrase must be be entered only during the first login after a reboot. On subsequent logins, the unencrypted key from the existing ssh-agent instance is used. This can also be useful for allowing passwordless RSA/DSA authentication in cron jobs without passwordless ssh-keys.

To enable keychain, install it and add something like the following to ~/.bash_profile:

eval `keychain --eval id_rsa`

From a security point of view, this approach is worse than session specific ssh-agent instances, but it offers a high level of convenience. To improve the security of keychain, some people add the --clear option to their ~/.bash_profile keychain invocation. By doing this passphrases must be re-entered on login as above, but cron jobs will still have access to the unencrypted keys after the user logs out. The keychain README has more information and examples.

ssh-key without passphrase

From a security standpoint, this is the worst option since the private key is entirely unprotected in case it is exposed. This is, however, the only way to make sure that the passphrase need not be re-entered after a reboot.

ssh-key with passphrase, with ssh-agent, passing passphrase to ssh-add from script

While it might seem like a straightforward idea to pass the passphrase to ssh-add from a script, e.g. echo "passphrase\n" | ssh-add, this is not as straighforward as it seems as ssh-add does not read the passphrase from stdin, but opens /dev/tty directly for reading.

This can be worked around with expect, a tool for automating interactive applications. Below is an example of a script which adds a ssh-key using a passphrase stored in the script:

#!/usr/bin/expect -f
spawn ssh-add /home/user/.ssh/id_rsa
expect "Enter passphrase for /home/user/.ssh/id_rsa:"
send "passphrase\n";
interact

Note that as the passphrase is stored in plaintext in the script, from a security perspective, this is hardly better than having a passwordless ssh-key. If this approach is to be used, it is important to make sure that the expect script containing the passphrase has proper permissions set to it, making it readable, writable and runnable only by the key owner.

share|improve this answer
    
Okay, but when I put your code to ~/.bash_profile I have to type in password every time I login, I don't want that either. I am not concerned about security at all. echo "pass\n" | ssh-add doesn't work – zdun8 Sep 17 '13 at 12:59
1  
@user1607072 Yeah, that is how the ssh-agent snippet in ~/.bash_profile behaves as explained in the answer. You might want to look at the keychain utility. With keychain you need to enter the password on first login after reboot, but on subsequent logins keychain will connect to an existing ssh-agent instance with the decrypted key in memory. Apart from that there's the option of generating a ssh-key without a passphrase, but this is of course not recommended. – Thomas Nyman Sep 17 '13 at 13:35
    
So there is no other way to do it than to leave my passphrase empty? Hmm that is sad. Anyway thanks a lot for your answer, it's the most comprehensive answer I've ever received! – zdun8 Sep 17 '13 at 15:43
2  
@user1607072 While I would strongly suggest one of the more secure approaches, there is a way to pass the passphrase to ssh-add from a script. The reason echo "pass\n" | ssh-add does not work is that ssh-add does not read the password from stdin, but opens /dev/tty directly for reading. Updated the answer to include a workaround for this, using an utility called expect. – Thomas Nyman Sep 17 '13 at 18:03
1  
@user1607072 It might be a bit overkill for your use case, but Kerberos in combination with ssh GSSAPI support can also be used for passwordless ssh logins. The corresponding authentication method in ssh is called gssapi-with-mic. This is usually used in larger networks, but of course if you have interest in this it might be worth looking into. – Thomas Nyman Sep 18 '13 at 11:54

Add this to your ~/.bashrc:

if [ ! -S ~/.ssh/ssh_auth_sock ]; then
  eval `ssh-agent`
  ln -sf "$SSH_AUTH_SOCK" ~/.ssh/ssh_auth_sock
fi
export SSH_AUTH_SOCK=~/.ssh/ssh_auth_sock
ssh-add -l | grep "The agent has no identities" && ssh-add

This should only prompt for a password the first time you login after each reboot. It will keep reusing the ssh-agent as long as it stays running.

share|improve this answer
    
very neat, this way you only have one ssh-agent running (: Multiple agents as in @thomasNyman's second solution seems a security risk to me... – drevicko Feb 10 at 11:54
1  
After researching in various sites and reading various solutions, this one here seems to be the clearest, straight to the point. Very nice. +1 – Dr Beco Jul 18 at 0:40
    
better to do this: `alias ssh=ssh-check-agent", and have the check-agent version do the above. that way: a) you only get one agent and b) you only get the agent if you need it – Erik Aronesty 1 hour ago

what ssh-agent does is to cache various unlocked ssh-keys, so you can have ssh-keys protected by passwords but without having to type them every single time.

in order to cache unlocked keys, it obviously needs to unlock those keys. for unlocking keys that are locked with a passphrase, it obviously needs to know these passphrases. any method that does not require authorization from a human being (e.g. "typing in a password") will not only make your system insecure, it will also render the entire purpose of the ssh-agent meaningless.

having said all this, you can simply use ssh-keys that are not password protected (hit [Enter] when asked for a password during key-generation). since there is no password, ssh-agent doesn't need to ask you for one in order to (not) cache it.

share|improve this answer
    
thanks, i updated my answer to be hopefully more correct. – umläute Sep 16 '13 at 12:48
    
I agree, as long as your keys are properly user-only-permissioned, there is little advantage to ssh-agent over permissionless keys. i like to ssh into a login server, and then, that server has a bunch of permssionless keys, each of which can only be used to unlock one other server. the login server does nothing else, so it's much harder to hack/spoof, etc... the other servers have no password access, are key-only. – Erik Aronesty 1 hour ago

I won't recommend you ssh-add (which need to open a ssh-agent) at login. This is because you can't control when the ssh-agent section ends, and can create security risk when you need not use the keyfiles at one login section.

Rather, I recommend to write a script which opens a ssh-agent's section sub-shell, with all keyfiles auto added, and be called when needed to use ssh. If you could adopt so, read on.

You would have two choices:

  1. Remove all passphrases for your keys, which have weak security if your key files are stolen. (thus not recommended)

  2. Use the same passphrase for your keys. Then when you ssh-add keyfile1 keyfile2 ..., you will only need to type the passphrase once, per section.

In both cases, you could write such script file "ssh_keys_section.sh" as below:

#!/bin/bash
# This script run a ssh-agent on a sub-shell and automatically ssh-add all keyfiles at once.
# This agent ends when you type `exit` to close the sub-shell.
exec ssh-agent bash -c "ssh-add /path/to/keyfile1 /path/to/keyfile2 ...; exec bash"

Remarks:

  • Command to change or delete passphrase: ssh-keygen -p -f keyfile
  • Within the sub-shell, you might even fork more terminals which share the same unlocked keys, by using maybe a command like /path/to/yourterminal & (depends on OS)
share|improve this answer

Here is a workaround to automate your ssh passphrase:

  1. Create a one-liner script which prints your passphrase to standard output, e.g.:

    echo 'echo my_passphrase' > ~/.echo_ps && chmod 700 ~/.echo_ps
    

And use one of the below methods.

  • using a standard input approach:

    $ cat ~/.ssh/id_rsa | SSH_ASKPASS=~/.echo_ps ssh-add -
    
  • or named pipe approach:

    1. Create a named pipe (you could also try a process substitution, see):

      $ mkfifo -m=600 ~/.fifo
      
    2. Run ssh-add by specifying the program used for the authentication:

      $ cat ~/.ssh/id_rsa >~/.fifo | SSH_ASKPASS=~/.echo_ps ssh-add ~/.fifo
      

    See: man ssh-add to read more about SSH_ASKPASS.

share|improve this answer

I used to use the script mentioned by steampowered, I've made the below one now, because it doesn't leave files lying around. (Tested on zsh only)

#!/bin/sh

AGENT_BIN=`which ssh-agent`
AGENT_ADD_BIN=`which ssh-add`
AGENT_PID=`ps -fe | grep ${AGENT_BIN} | awk -vuser=$USER -vcmd="$AGENT_BIN" '$1==user && $8==cmd{print $2;exit;}'`
if [ -z "$AGENT_BIN" ]; then
    echo "no ssh agent found!";
    return
fi
if [ "" -eq "$AGENT_PID" ]; then
    if read -sq "YN?Do you want to unlock your ssh keys?"; then
        echo ""
        output=`$AGENT_BIN | sed 's/echo/#echo/g'`
        eval $output
        $AGENT_ADD_BIN
    fi
else
    for f in "/proc/"*
    do
        cmdline=`cat "$f/cmdline"`
        if [ "${AGENT_BIN}" -ef "${cmdline}" ]; then
            export SSH_AUTH_SOCK=`cat $f/net/unix | grep --binary-file=text -oP '((/[^/]*?)+/ssh-[^/]+/agent\.\d+$)'`
            export SSH_AGENT_PID=${f##*/}
            break;
        fi
    done
fi
share|improve this answer

Add this to your ~/.bashrc file:

ssh-add -L|grep identities > /dev/null && ssh-add /path/to/ssh/private/key
share|improve this answer
    
I don't see how this relates to the question, which is about not being prompted for the password on subsequent logins. – Chris Down Jan 6 '14 at 13:23

In order to add a (possibly passwordless) key and ensure that ssh-add will not prompt for a password, no matter what, even when running under X:

DISPLAY= ssh-add -k /path/to/key </dev/null &>/dev/null

Exit status indicates success or failure.

share|improve this answer
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 -ef | grep ${SSH_AGENT_PID} | grep ssh-agent$ > /dev/null || {
         start_agent;
     }
else
     start_agent;
fi

Giving credit here: https://www.cygwin.com/ml/cygwin/2001-06/msg00537.html

This solution is also endorsed here: http://mah.everybody.org/docs/ssh

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.