Ssh-Add from Bash Script and Automate Passphrase Entry

How to make ssh-add read passphrase from a file?

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

ssh-add from bash script and automate passphrase entry

Personally, I find the use of expect a bit cumbersome. The following approach found how to make ssh-add read passphrase from a file rather informative.

So if your version of ssh-add allows the -p argument and you are not worried about security then this should work:

#!/bin/bash
# store a file somewheres with your passphrase. For example's sake
# I'll just use $HOME/.myscrt

<$HOME/.myscrt ssh-add -p ~/.ssh/id_rsa

Now if -p is not an option for you, I found the second method mildly ingenious:

#!/bin/bash
# Same passfile and some minor enhancements from the OP of the linked
# solution
PASS="$(<$HOME/.myscrt)"

# the following is just a one-liner method of making an executable
# one-line script echoing the password to STDOUT
install -vm700 <(echo "echo $PASS") "$PWD/ps.sh"

# then the magic happens. NOTE: your DISPLAY variable should be set
# for this method to work (see ssh-add(1))
[[ -z "$DISPLAY" ]] && export DISPLAY=:0
< id_rsa SSH_ASKPASS="$PWD/ps.sh" ssh-add - && shred -n3 -uz $PWD/ps.sh

When I tested the script I called "j", see below:

$ cd /tmp
$ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/home/me/.ssh/id_rsa): /tmp/id_rsa
Enter passphrase (empty for no passphrase): asdfasdf
Enter same passphrase again: asdfasdf
Your identification has been saved in /tmp/id_rsa.
Your public key has been saved in /tmp/id_rsa.pub.
The key fingerprint is:
ed:1a:ae:c7:ac:47:5e:31:98:8e:18:8f:1c:67:94:6d jimconn@redapt-240
The key's randomart image is:
+--[ RSA 2048]----+
| o |
| o E |
| . . o |
| o o o.o |
| . O oS .o |
| + o o.. |
| =... |
| .*o |
| o=o |
+-----------------+
$ echo 'asdfasdf' > ~/.myscrt
$ chmod 0600 ~/.myscrt
$ ls -altr ~/.myscrt
-rw------- 1 me me 9 Feb 16 19:00 /home/me/.myscrt
$ cat ~/.myscrt
asdfasdf
$ ls -ltr
total 12
-rw-r--r-- 1 me me 400 Feb 16 18:59 id_rsa.pub
-rw------- 1 me me 1766 Feb 16 18:59 id_rsa
-rwx------ 1 me me 151 Feb 16 19:04 j
$ cat j
#!/bin/bash
PASS="$(<$HOME/.myscrt)"
install -vm700 <(echo "echo $PASS") "$PWD/ps.sh"
cat id_rsa | SSH_ASKPASS="$PWD/ps.sh" ssh-add - && shred -n3 -uz $PWD/ps.sh
$ ./j
‘/dev/fd/63’ -> ‘/tmp/so/ps.sh’
Identity added: (stdin) ((stdin))
$ ls
id_rsa id_rsa.pub j

So, one thing to quickly note about this method is that listing the identities loaded into ssh-agent will only show that stdin was loaded:

$ ssh-add -D
All identities removed.
$ ssh-add -l
2048 ed:1a:ae:c7:ac:47:5e:31:98:8e:18:8f:1c:67:94:6d (stdin) (RSA)
$ ./j
‘/dev/fd/63’ -> ‘/tmp/so/ps.sh’
Identity added: (stdin) ((stdin))
$ ssh-add -l
2048 ed:1a:ae:c7:ac:47:5e:31:98:8e:18:8f:1c:67:94:6d (stdin) (RSA)

Script that executes ssh-add and feeds the passphrase automatically

If you're going to do that you'd be better off just not using a passphrase on the key. In which case you wouldn't even need to use ssh-agent. You can change or remove a passphrase from an existing key with ssh-keygen -p.

Automating ssh-add private keys with a common password

If you have same password for all the keys then you can pass multiple keys to ssh-add and it prompts for password only once and adds all those keys to the ssh-agent.

eg:

$> arr=("id_ecdsa" "new_test_key")
$> ssh-add ${arr[@]}
Enter passphrase for id_ecdsa:
Identity added: id_ecdsa (test_user@host_test)
Identity added: new_test_key (test_user@host_test)

$> ssh-add -l
256 SHA256:urYhdMK9UZyLl+p8cC7ehdImYfvsmtJFtQmESWoczmM test_user@host_test (ECDSA)
256 SHA256:53obuQkRzLGW5iUJdmFPNvSK1quUSlCi4gbQkKsJinY test_user@host_test (ECDSA)

expect script with optional ssh-agent passphrase prompt?

Yeah, that's a funny one. Since you're using ssh -N, you don't launch any process on the remote host, and the ssh session just sits there. You would just have to sleep for a couple of seconds and hope the tunnel gets established.

set timeout 2
spawn ssh -M -S /var/run/examplecom-mysql-socket -fnNT -L 3307:localhost:3306 someuser@example.com

expect {
# conditional prompt appears in case ssh-agent is not active
"*.ssh/id_rsa':*" { send -- "$SSH_PASSPHRASE\r" }
# wait until the timeout, then carry on with the rest of the script
timeout
}

set timeout -1
# ...

Or, remove -N, then you can expect to see the prompt on the remote host.

spawn ssh -M -S /var/run/examplecom-mysql-socket -fnT -L 3307:localhost:3306 someuser@example.com
# ..........................................^^^^

expect {
# conditional prompt appears in case ssh-agent is not active
"*.ssh/id_rsa':*" { send -- "$SSH_PASSPHRASE\r" }
# I assume your prompt ends with a dollar sign and a space
-re {\$ $}
}

Now you can spawn the mysql command and interact with that.

How to pass an ssh key passphrase via environment variable

So there are actually a few things that is important for what you are trying to do:

  1. DISPLAY must be set
  2. it must not have a terminal associated with it
  3. on some machines it may be necessary to redirect the input from /dev/null (mine is one of them).
  4. SSH_ASKPASS must contain an executable which outputs the passphrase on stdout.

So for an example of getting it to work (for me, should work on other linux also I guess):

Create dummy key:

ssh-keygen -t rsa -C se-so-38354773 -f /tmp/se-so-38354773.key -N 'se-so-38354773-pp'

Create askpass script to echo password files:

cat > /tmp/se-so-38354773-askpass <<EOF
#!/usr/bin/env bash
echo "${0}:${@} : this is for debugging to see if the echo script runs" 1>&2
echo "se-so-38354773-pp"
EOF
chmod +x /tmp/se-so-38354773-askpass

I placed this file in /tmp/ - but this is not a good for security unless you also change permissions on the file before writing to it to ensure that nobody else can read it (or set umask).

Then you can do ssh-add as follow:

DISPLAY=":0.0" SSH_ASKPASS="/tmp/se-so-38354773-askpass" setsid ssh-add /tmp/se-so-38354773.key </dev/null

The setsid dissociates it from your terminal if there is one - This is not needed on my computer though - but yeah - I think it may be needed in some other contexts.

And when you are done testing do clean up:

ssh-add -d /tmp/se-so-38354773.key
rm /tmp/se-so-38354773*

Example output on my computer:

iwana@iwana-nb.concurrent.co.za:~/projects/gitlab.com/aucampia/stackexchange/stackoverflow/38354773
$ ssh-keygen -t rsa -C se-so-38354773 -f /tmp/se-so-38354773.key -N 'se-so-38354773-pp'
Generating public/private rsa key pair.
Your identification has been saved in /tmp/se-so-38354773.key.
Your public key has been saved in /tmp/se-so-38354773.key.pub.
The key fingerprint is:
SHA256:s+jVUPEyb2DzRM5y+Hm3XDzVRREKn5yU2d0hk61hIQ0 se-so-38354773
The key's randomart image is:
+---[RSA 2048]----+
| .E+=B=O|
| B*B*o=|
| X B*o o|
| o % o ..|
| S * ..+|
| . = . ...+|
| . o . o |
| . . |
| . |
+----[SHA256]-----+
iwana@iwana-nb.concurrent.co.za:~/projects/gitlab.com/aucampia/stackexchange/stackoverflow/38354773
$
iwana@iwana-nb.concurrent.co.za:~/projects/gitlab.com/aucampia/stackexchange/stackoverflow/38354773
$ cat > /tmp/se-so-38354773-askpass <<EOF
> #!/usr/bin/env bash
> echo "${0}:${@} : this is for debugging to see if the echo script runs" 1>&2
> echo "se-so-38354773-pp"
> EOF
iwana@iwana-nb.concurrent.co.za:~/projects/gitlab.com/aucampia/stackexchange/stackoverflow/38354773
$ chmod +x /tmp/se-so-38354773-askpass
iwana@iwana-nb.concurrent.co.za:~/projects/gitlab.com/aucampia/stackexchange/stackoverflow/38354773
$
iwana@iwana-nb.concurrent.co.za:~/projects/gitlab.com/aucampia/stackexchange/stackoverflow/38354773
$ DISPLAY=":0.0" SSH_ASKPASS="/tmp/se-so-38354773-askpass" setsid ssh-add /tmp/se-so-38354773.key </dev/null
iwana@iwana-nb.concurrent.co.za:~/projects/gitlab.com/aucampia/stackexchange/stackoverflow/38354773
$
bash: : this is for debugging to see if the echo script runs
Identity added: /tmp/se-so-38354773.key (/tmp/se-so-38354773.key)
iwana@iwana-nb.concurrent.co.za:~/projects/gitlab.com/aucampia/stackexchange/stackoverflow/38354773
$ ssh-add -d /tmp/se-so-38354773.key
Identity removed: /tmp/se-so-38354773.key (se-so-38354773)
iwana@iwana-nb.concurrent.co.za:~/projects/gitlab.com/aucampia/stackexchange/stackoverflow/38354773
$ rm /tmp/se-so-38354773*


Related Topics



Leave a reply



Submit