24

(I have read many of the questions on this site that look related and I believe this is a genuinely new question.)

I have lots of keys on lots of servers and they're all protected with passphrases.

I like entering passphrases about as much as I like entering passwords - it's a real productivity drain.

  • ssh-agent + ssh-add commands can be used on a login shell to mean you only have to enter your passphrase once at login

  • keychain can be used to hold an ssh-agent alive beyond logout, so for example you can have it so you only have to enter the passphrase once at boot, or you can have it keep it alive for an hour or so.

The problem I have is that both of these solutions typically get initiated in a shell login (e.g. .zshrc) rely on me entering my passphrase when I log in, even if I'm not going to need it unlocked. (I'm not happy with keychain keeping an agent alive indefinitely.)

What I would like is to be prompted for a passphrase (for an agent) only when needed.

So I can log in to server A, do some stuff, then ssh to server B and at that point be asked for the passphrase. Do some stuff on server B, log out. Back on A, do some more stuff, ssh to B again and not need my passphrase (it's held by an agent).

I note that this is possible on graphical desktops like Gnome - you get a pop-up asking for the passphrase to unlock your private key as soon as you try to ssh. So this is what I'm after but from a console.

artfulrobot
  • 2,929
  • Why not just generate ssh-keys without passphrases? If you are going to go through all this trouble anyway? – devnull Jan 20 '15 at 16:00
  • 3
    If someone breaks in and there's password-less keys (or an active ssh agent), they can have access to many other servers, too. Also passphrase-less keys can be stolen and used elsewhere. – artfulrobot Jan 20 '15 at 16:11
  • As far as I know, there is no way to do what you want without sacrificing some level of security, which sounds like you don't want to do. There was an in-depth answer by Thomas Nyman here that goes into many possibilities if you haven't already read it: http://unix.stackexchange.com/a/90869/82289 . I get around this at my company by the use of an intermediate server that manages ssh sessions with Tmux. – devnull Jan 20 '15 at 16:31
  • @DevNull seems weird that you can do it with a desktop but not with a terminal, no? Surely it just needs the agent to jump to the tty if no keys have been added? This must be the way the gui ones work? – artfulrobot Jan 20 '15 at 17:30
  • You might have a look on my answer here: http://unix.stackexchange.com/a/184160/89706 (Question's link: https://unix.stackexchange.com/questions/90853/how-can-i-run-ssh-add-automatically-without-password-prompt) – Johnny Wong Feb 11 '15 at 04:28

3 Answers3

27

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.

Michael Mrozek
  • 93,103
  • 40
  • 240
  • 233
Toby
  • 411
  • I wish people would comment when down voting. If it's not right is important we know why it's not right. Thanks for posting, I've not had time to try your suggestion myself. – artfulrobot Nov 01 '16 at 22:11
  • I wondered too, maybe because of my cross-posts? – Toby Nov 02 '16 at 19:09
  • 1
    This works for me. However it's a very recent addition to openssh (7.2). In case it helps anyone, openssh 7.3 is available in Debian Sid. – artfulrobot Nov 03 '16 at 10:27
  • @artfulrobot: Strange, as I had this very same behaviour (auto-ssh-add at first call of ssh) working for years, until it finally stopped some time ago. Searching for the cause, I found AddKeysToAgent and assumed that the reason it stopped was that by accident I must have cleaned out my .ssh/config and AddKeysToAgent along with it. Now I wonder why it was working long before OpenSSH 7.2 got released? I am not imagining this :-) – Toby Nov 04 '16 at 21:46
  • 2
    @Toby this is exactly what I need. Unfortunately, ssh-agent doesn't seem to start automatically in kubuntu, so that's the next thing I need to solve. – Ogaday Mar 05 '18 at 14:36
9

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).

artfulrobot
  • 2,929
  • Even without zsh, one could create a short script with the same effect and place it PATH before the actual ssh client. Might even work with rsync et al, if they read PATH instead of running /usr/bin/ssh directly. – ilkkachu Aug 27 '16 at 15:58
2

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.

vinc17
  • 12,174
  • Wow that's quite a lot of code. Nice work and thanks for sharing. I think I need something simpler - SSH is a pretty core tool for me. – artfulrobot Jan 21 '15 at 09:44