31

I want to put ssh-add /path/to/special_key at the top of a script. This works fine, but it always prompts for the passphrase. This is strange, and a little annoying, as it still asks for the passphrase even when ssh-add -l shows the key has already been added.

Is there a way to tell it: "add this key and ask the passphrase if not already been added, otherwise do nothing" ?

2

6 Answers 6

31

I don't see any options to ssh-add that help achieve your desired result, but it's pretty easy to work around this, given that you're concerned with one key in particular.

First, grab the fingerprint for your special_key:

ssh-keygen -lf /path/to/special_key  | awk '{print $2}'

Let's say this fingerprint looks like 6d:98:ed:8c:07:07:fe:57:bb:19:12:89:5a:c4:bf:25

Then, at the top of your script, use ssh-add -l to check whether that key is loaded, before prompting to add it:

ssh-add -l |grep -q 6d:98:ed:8c:07:07:fe:57:bb:19:12:89:5a:c4:bf:25 || ssh-add /path/to/special_key

You can fold all this together into one line if you wish:

ssh-add -l |grep -q `ssh-keygen -lf /path/to/special_key  | awk '{print $2}'` || ssh-add /path/to/special_key
3
  • The one-liner is working nicely, thanks! Commented Jun 1, 2014 at 2:09
  • 3
    I find this simplified one-liner to be a bit more comprehensible, and preferable since it avoids ssh-keygen (after all, I don't want to generate any keys), instead using the key path: ssh-add -l | grep -q 'path/to/key' || ssh-add /path/to/key
    – mattsilver
    Commented Jan 17, 2017 at 14:58
  • 1
    ssh-keygen in the answer does not generate a key - same as ssh-add -l in your example does not actually add anything. Flags modify the behaviour of the commands so it does not exactly match the name. Note that these versions functionally differ - if checking by path and the key at that path changes, your version would not pick it up. The version in the answer would also detect existing key no matter where it was loaded from.
    – Richlv
    Commented May 15, 2019 at 11:18
12

You might have particular reasons to be using ssh-add explicitly, but if you just want "I want to be prompted for my passphrase the first time I use the key, but not after that," openssh has a simpler solution:

Put AddKeysToAgent yes in your .ssh/config file.

2
  • Thanks. That was apparently added in ssh 7.2 (Ubuntu 18 appears to be on version 7.6). Commented Apr 29, 2019 at 16:43
  • Yup, "AddKeysToAgent isn't supported by my openssh version" is a good reason to use ssh-add explicitly ;-)
    – Nate
    Commented Apr 29, 2019 at 23:52
5

There is no direct way to check using just ssh-add but you can make use of ssh-keygen and some scripting to check.

$ if  ssh-add -l | \
    grep -q "$(ssh-keygen -lf /path/to/special_key | awk '{print $2}')"; \
    then echo yes; \
    else echo no; \
  fi

The above would then print yes if the fingerprint represented by the file /path/to/special_key was present in ssh-add -l's output.

Example

$ if  ssh-add -l | \
    grep -q "$(ssh-keygen -lf /path/to/special_key | awk '{print $2}')"; \
    then echo yes; \
    else echo no; \
  fi
yes

Where the contents of output from ssh-keygen -lf /path/to/special_key looks like this:

$ ssh-keygen -lf /path/to/special_key
2048 8a:6a:5a:44:20:c8:3a:da:ab:dd:1c:12:2c:e4:20:0c  dev-servers (RSA)

And we're using `awk '{print $2}' to select just the 2nd column, which contains the fingerprint, i.e.:

8a:6a:5a:44:20:c8:3a:da:ab:dd:1c:12:2c:e4:20:0c

References

3

I know this is an old question but I needed the answer today, and this was the right question. But maybe due to old key format - ssh-keygen answer variations wouldn't function for my case. Here's a variation using just the output from "ssh-add -l", which just lists out all managed keys. This will be checking if my path-to-my-key is a substring within that result. If so, all's good, otherwise add the key.

PATH_TO_MY_KEY="/path/to/special_key"
if [[ "$(ssh-add -l)" == *"${PATH_TO_MY_KEY}"* ]]; then 
        echo "Key is ready managed in ssh-agent "
else  
        echo "adding key for ${PATH_TO_MY_KEY} "
        ssh-add ${PATH_TO_MY_KEY} 
fi
1

Try this oneliner to only ask for the passphrase and add the key to the ssh if the key is not yet added:

# for a private key located at "/path/to/special_key" (your specific question):
( KEY="/path/to/special_key" && ( ssh-add -T "${KEY}.pub" 2>/dev/null || ssh-add -q "$KEY" ) )

# for a private key located at ~/.ssh/id_rsa (generic/typical name):
( KEY="${HOME}/.ssh/id_rsa" && ( ssh-add -T "${KEY}.pub" 2>/dev/null || ssh-add -q "$KEY" ) )

Explanation:

  • everything is wrapped in parantheses to not leak the custom KEY variable into the environment
  • ... ssh-add -T "${KEY}.pub" 2>/dev/null ...: The -T allows to test a specified public key (here: ${KEY}.pub) against compatibility with any private key currently managed by the running (used/identified) ssh-agent (the 2>/dev/null redirect is there for making the command quiet in the failure case).
    • if there is no match, the command will return a nonzero exit status, and continue with ssh-add -q "$KEY".
    • if there is a match, the command will return a zero exit status, and early-exit the oneliner.
  • if ... ssh-add -q "$KEY" is reached, that means the running ssh-agent does not manage this private key yet. Therefore this command is executed to ask for the passphrase and add the key to the agent.
0

ssh-add --apple-use-keychain FILE worked fine for me on Mac.
It still shows "Identity added: " lines but doesn't ask for passphrase.

From man page:

--apple-use-keychain When adding identities, each passphrase will also be stored in the user's keychain. When removing identities with -d, each passphrase will be removed from it.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .