How to get asked for SSH key passphrase once and only when needed?

Don't add anything to any of your shell startup scripts, this is unnecessary hackery.

Instead, add

AddKeysToAgent yes

to your .ssh/config

Like this, ssh-add is run automatically the first time you ssh into another box. You only have to re-enter your key when it expires from ssh-agent or after you reboot.


Zsh has a preexec hook that executes a function before a command entered on the commandline is executed. Here's a hook that looks for ssh in your command line and if found, checks for the existence of an ssh agent. If that's not found, it runs keychain.

So this way, keychain is only run before ssh commands, and then only if needed.

Put this in your ~/.zshrc:

function check_ssh {
  [[ $3 =~ '\bssh\b' ]] || return
  [[ -n "$SSH_AGENT_PID" && -e "/proc/$SSH_AGENT_PID" ]] \
    && ssh-add -l >/dev/null && return
  eval `keychain --eval id_dsa --timeout 60`
}    
autoload -U add-zsh-hook
add-zsh-hook preexec check_ssh

What happens here is whenever a command is typed, check_ssh is called before the command is executed.

The first line of the function checks the expanded command for ssh using a Zsh regex. ssh must have word boundaries \b either side. If this is not found then the function returns.

The next line checks that there's an SSH agent process in the environment variable, and that that process exists in the process table still, and then that at least one key has been added to the agent. If all of that is OK, then ssh agent is set up and we don't need to do anything, so it returns.

Finally we start keychain, with the agent to be kept alive for an hour.

It still leaves the problem about embedded ssh stuff, like git or rsync or scp as that won't trigger the function (you could add these to the regex).


For zsh, I've written a set of utilities and wrappers to do more or less what you want: https://www.vinc17.net/unix/index.en.html#zsh-ssh-utils

Actually this does even more, because the ssh-agent will be shared by all the login sessions (desktop or via SSH, and GNU Screen is supported too if you start login shells from it, e.g. with shell -zsh in the ~/.screenrc file), and it will quit only after the last session terminates.

Note: I use only one passphrase for all my keys. I'm not sure of the behavior for different passphrases; there may need some changes.

Tags:

Ssh

Ssh Agent