81

I want to run ssh-agent (with maximum lifetime option), but not add any keys at startup, but instead add them on demand.

Like first time I login to some server it should ask for passphrase, next time (unless I waited for more than a hour) it should connect cleanly:

ssh server1
Enter passphrase for key '/home/vi/.ssh/id_dsa':
server1> ...

ssh server2
server2> # no passphrase this time

# wait for lifetime

ssh server2
Enter passphrase for key '/home/vi/.ssh/id_dsa':

I don't want to manually remember about running 'ssh-add' each time. (e.g. entered passphrase for just for ssh and "Oh, it hasn't remembered, need to retype").

How to configure ssh to automatically add key to ssh-agent if user provided the passphrase?

Vi.
  • 16,755
  • 32
  • 111
  • 189
  • possible duplicate of [Can I make ssh-agent wait until I use ssh to prompt for a password?](http://superuser.com/questions/201330/can-i-make-ssh-agent-wait-until-i-use-ssh-to-prompt-for-a-password) – u1686_grawity Aug 20 '11 at 17:56

4 Answers4

104

ssh supports adding a key to the agent on first use (since version 7.2).  You can enable that feature by putting the following into ~/.ssh/config:

AddKeysToAgent yes

This also works when using derivative tools, such as git.

From the 7.2 changelog:

  • ssh(1): Add an AddKeysToAgent client option which can be set to 'yes', 'no', 'ask', or 'confirm', and defaults to 'no'.  When enabled, a private key that is used during authentication will be added to ssh-agent if it is running (with confirmation enabled if set to 'confirm').
spheenik
  • 1,164
  • 1
  • 8
  • 4
  • This requires a ssh-agent to be running. Refer to https://stackoverflow.com/a/24347344/4573065 + its comments for a good way to start it (only once). – ST-DDT Jul 10 '18 at 09:23
  • 3
    you may want to make sure your ~/.ssh/config file has the right permissions with `chmod 600 ~/.ssh/config` – Kerem Jan 03 '20 at 18:56
  • This feature is so undesirable. I want to add the key to the agent for my git repo, not the key that I use to connect to the sandbox and if not for this conf option I would see no reason for them to be the same key. – Evan Carroll Aug 10 '23 at 16:37
  • @Evan Carroll this, or any option, in ~/.ssh/config applies only to host names as typed at the ssh command line (or configured into git as a remote to use) that match the host line preceding them. The entries on that host line can be aliases with the actual host name listed on a 'hostname' line; so you can even have different sets of options for the same server if that should be desirable. See https://linuxize.com/post/using-the-ssh-config-file/ or Google "SSH Config Syntax" and dig around. – SensorSmith Aug 18 '23 at 19:08
  • @SensorSmith that has nothing to do with anything I wrote. – Evan Carroll Aug 18 '23 at 19:21
  • @SensorSmith when you run `ssh -i priv.key foo@bar.com` on a host with `AddKeysToAgent` the `priv.key` is added to the agent when you connect. I want to be able to add a _different_ key as specified in my `~/.ssh/config` that gets added to the agent. – Evan Carroll Aug 18 '23 at 19:26
  • 1
    @EvanCaroll, oh you are wanting to preload other keys, probably for use with ForwardAgent so you can connect to B(git) from inside your connection to A(sandbox). Yes that would be a different sort of extremely handy. I don't think this can be done without scripting around `ssh-agent` and `ssh-add`. You might checkout [this answer](https://unix.stackexchange.com/a/90869/285587) and the options it lists, such as [ssh-ident](https://github.com/ccontavalli/ssh-ident), though they might not be Windows compatible if that is an issue. – SensorSmith Aug 18 '23 at 23:47
  • @SensorSmith that's exactly what I want, and that's why I want. I want to isolate my git key from my connection key. I don't want to add the connection key to the agent. – Evan Carroll Aug 19 '23 at 03:27
18

You could cheat and put something like alias ssh='ssh-add -l || ssh-add && ssh' on your .bashrc / .profile. This first runs ssh-add -l, which can return 0 (there are keys on agent), 1 (no keys) or 2 (no agent running); if it returns 0, ssh will run; if 1, ssh-add will run and then ssh; if 2, ssh-add will fail and ssh won't be run. Replace the && with ; if you want ssh to run even when there's no agent running.

Jessidhia
  • 2,900
  • 19
  • 10
  • 4
    It will request passphrase to the key even when further ssh command does not use it. – Vi. Sep 09 '11 at 15:02
  • @Vi. true, but rare are the commands that don't use them (unless you're connecting to a server that uses keyboard-interactive). The key will be in the agent whenever you need them afterwards though. Also, the alias fortunately (or unfortunately) doesn't change backend uses of ssh (such as with git or rsync). – Jessidhia Apr 03 '12 at 12:05
  • 2
    (thinking about writing auto-call-ssh-add patch for ssh client) – Vi. Apr 03 '12 at 17:48
  • Based on this answer you can create an aliases for a specific hosts: `alias ssh-hostname='(ssh-add -l | grep hostname > /dev/null) || ssh-add ~/.ssh/id_rsa_hostname && ssh -p 12345 username@hostname'`. You could even put that in a loop for all your ssh keys and generate aliases. A dirty hack, but it works. – dset0x Apr 19 '13 at 16:04
5

Until auto-call-ssh-add is supported by ssh, I added this in my .bashrc, based on Kovensky proposal:

ssh-add -l >/dev/null || alias ssh='ssh-add -l >/dev/null || ssh-add && unalias ssh; ssh'

The alias is created only if the identity is not added, and the alias destroys itself once run.

This way the regular ssh command is used after the identity has been added.

Marc MAURICE
  • 904
  • 8
  • 5
  • Will not work in my case because of ssh-add also have timeout configured, but the idea is good enough. – Vi. Sep 08 '12 at 12:04
  • @Vi. How would a timeout affect this? It seems to work great for me. – lanrat May 04 '14 at 19:22
  • 1
    @lanrat, This checks if key is present in ssh-agent and configures alias depending on the presence. But due to timeout (`ssh-add -t ...`) the key added to ssh-agent may go away abruptly, but and the alias will stay as it the key is still in memory. – Vi. May 05 '14 at 09:18
2

I'm using the following shell function:

ssh() {
    local possible_keys=($(/usr/bin/env ssh -G $@ | grep '^identityfile' \
                           | cut -d " " -f 2- | sed -e "s|^~|$HOME|"))
    for k in $possible_keys; do
        if [[ -f $k ]]; then
            local fingerprint=$(ssh-keygen -lf $k)
            ssh-add -l | grep -q "$fingerprint" || ssh-add $k
        fi
    done
    /usr/bin/env ssh $@
    return $?
}

It first resolves the configuration for the host I'm trying to connect to, then adds possible keys for that host to the ssh-agent if they're not added yet and finally connects to the host. I'm sure it can be improved, so I'm open for feedback.

mbrgm
  • 21
  • 1