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.