33

I am trying to add a key to ssh-agent and want ssh-add to read the password from the key file I'm using. How is this possible?

How do I automate this process from the shell script?

icc97
  • 8,746
  • 6
  • 60
  • 75
Satish
  • 13,709
  • 26
  • 80
  • 130
  • 1
    Why not just store a copy of the key without any password applied in the same place with the same permissions as you would store the password? – Charles Duffy Oct 19 '15 at 18:50
  • See https://unix.stackexchange.com/questions/90853/how-can-i-run-ssh-add-automatically-without-a-password-prompt and https://stackoverflow.com/questions/18880024/start-ssh-agent-on-login – icc97 Jan 14 '21 at 11:46

4 Answers4

38

Depending on your distribution and on the version of ssh-add you may be able or not to use the -p option of ssh-add that reads the passphrase from stdin in this way:

cat passfile | ssh-add -p keyfile

If this is not working you can use Expect, a Unix tool to make interactive applications non-interactive. You'll have to install it from your package manager.

I have written a tool for you in expect. Just copy the content in a file named ssh-add-pass and set executable permissions on it (chmod +x ssh-add-pass). You can also copy it to /usr/bin or /usr/local/bin to be accessible from the $PATH search.

#!/bin/bash

if [ $# -ne 2 ] ; then
  echo "Usage: ssh-add-pass keyfile passfile"
  exit 1
fi

eval $(ssh-agent)
pass=$(cat $2)

expect << EOF
  spawn ssh-add $1
  expect "Enter passphrase"
  send "$pass\r"
  expect eof
EOF

The usage is simply: ssh-add-pass keyfile passfile

Ed Neville
  • 155
  • 10
enrico.bacis
  • 27,413
  • 7
  • 76
  • 108
  • 3
    there is no -[Pp] option in ssh-add - error ssh-add: illegal option -- P – Satish Oct 23 '12 at 16:06
  • 1
    It used to have in some distributions. Which distribution are you using? I'll let the answer so people with a compatible distribution may find it useful. – enrico.bacis Oct 23 '12 at 16:12
  • 1
    They closed the question, but I still wanted to help. Try the new way I posted and let me know! – enrico.bacis Oct 23 '12 at 17:17
  • I have a one more issue related above script how do i add "ssh-agent bash" command in it. problem is it spawn a new shell and it failed. – Satish Oct 23 '12 at 18:34
  • What do you want to do with ssh-agent? – enrico.bacis Oct 23 '12 at 18:37
  • without ssh-agent you can't run ssh-add command. check out https://spaces.seas.harvard.edu/display/USERDOCS/Storing+Your+Keys+-+SSH-Agent,+Agent+Forwarding,+and+Keychain – Satish Oct 23 '12 at 18:46
  • No, its not working. you have to run "ssh-agent bash" option it won't work without bash argument? – Satish Oct 24 '12 at 13:52
  • 1
    Try to change the `eval $(ssh-agent)` with `ssh-agent bash` or with `eval \`ssh-agent -s\`` – enrico.bacis Oct 24 '12 at 14:24
  • I have tried `eval` ```ssh-agent -s``` and it ran all commands but after that script return back to original bash and it lost that key. Its all depend on spawning bash and use same bash to run ssh-add – Satish Oct 24 '12 at 14:31
  • I suggest you to start another question because now the question is not how to pass a passphrase to ssh-add (which you know now and is the question asked here), but is how to script ssh-agent + ssh-add. I suggest you to add also your distribution version in the new question. Hope it helps :) – enrico.bacis Oct 24 '12 at 14:52
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/18528/discussion-between-enrico-bacis-and-satish) – enrico.bacis Oct 24 '12 at 16:57
10

Similar to the answer by kenorb, but doesn't save the secret in a file:

$ SSH_ASKPASS=/path/to/ssh_give_pass.sh ssh-add $KEYFILE <<< "$KEYPASS"

where ssh_give_pass.sh is:

#!/bin/bash
# Parameter $1 passed to the script is the prompt text
# READ Secret from STDIN and echo it
read SECRET
echo $SECRET

If you have you secret in a $KEYPASSFILE, read it into a variable first with

KEYPASS=`cat $KEYPASSFILE`

Also make sure that ssh_give_pass.sh is not editable by unauthorized users - it will be easy to log all secrets passed through the script.

Ray Shannon
  • 109
  • 1
  • 3
  • Very nice! I think this could be improved even more- since the questioner wants this as part of a script, you can go: SSH_ASKPASS="$0", and then have – cmc Feb 12 '19 at 15:26
  • 2
    This is by far the most elegant- no saving passwords anywhere. Tiny shortening, replace read SECRET ; echo $SECRET with cat Also, since this is for use in a script, the script itself can double as askpass using SSH_ASKPASS=$0, then check $1 to see if is being called normally or as askpass – cmc Feb 12 '19 at 16:17
  • 2
    if DISPLAY isn't set, ssh-add won't respect the SSH_ASKPASS variable. So in case the above solution isn't working, check this one first. – petkov.np Jul 31 '19 at 18:33
  • @petkov.np `DISPLAY=:0 SSH_ASKPASS=/path/to/ssh_give_pass.sh ssh-add $KEYFILE <<< "$KEYPASS"` – aff Oct 09 '20 at 08:30
  • @petkov.np If we're using bash, it would be `${DISPLAY:=0}` – Jon Feb 15 '21 at 21:05
9

Here is some workaround for systems not supporting -p:

$ PASS="my_passphrase"
$ install -vm700 <(echo "echo $PASS") "$PWD/ps.sh"
$ cat id_rsa | SSH_ASKPASS="$PWD/ps.sh" ssh-add - && rm -v "$PWD/ps.sh"

where ps.sh is basically your script printing your passphrase. See: man ssh-add.

To make it more secure (to not keep it in the same file), use mktemp to generate a random private file, make it executable (chmod) and make sure it prints the passphrase to standard output once executed.

kenorb
  • 118,428
  • 63
  • 588
  • 624
  • 1
    Very creative way to fake-out interactive input in this special case where `ssh-add` allows you to swap-out the `SSH_ASKPASS` binary per-call like that. – Mike Atlas Dec 19 '15 at 02:51
  • 1
    Correct, but `ps.sh` is a security risk, and a rm is a quite weak way to hide it, you should at least do a `shred -u`, but even shred is inefficient on modern fs like ext4 and a lot more on btrfs. So create your file in shared memory `/dev/shm` or `/run/user/`, and shred it after use. An other option is to put `ps.sh` on an encrypted filesystem. – marcz Apr 15 '16 at 09:35
  • This solution works great for me, but only if I set `DISPLAY=:0` as the man page for ssh-add suggests (Ubuntu 16.04) – Antoine Cotten May 23 '16 at 14:03
  • On my Bionic, I had to redirect ssh-add's stdin from /dev/null, as the man page suggested. – Egor Tensin May 20 '18 at 15:41
1

On my Ubuntu system, none of the answers worked:

  • ssh-add did not support the -p option.
  • ssh-add ignored SSH_ASKPASS, insisting on prompting for the passphrase on the controlling terminal.
  • I wanted to avoid installing additional packages, especially expect.

What worked in my case was:

password_source | SSH_ASKPASS=/bin/cat setsid -w ssh-add keyfile

password_source isn't really a program: it just represents whatever feeds the passphrase to ssh-add. In my case, it is a program that executes setsid and writes the passphrase to its stdin. If you keep your passphrase in a file, you are responsible for making the simple modifications: I will not enable you to hurt yourself.

setsid was already installed, and detaches the controlling terminal so that ssh-add will not try to use it to prompt for the passphrase. -w causes setsid to wait for ssh-add to exit and make its return code available. /bin/cat has the same effect as the script Ray Shannon provided, but uses a standard tool instead of replicating its functionality with a script.

Steven Crain
  • 71
  • 1
  • 2