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?
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?
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
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.
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.
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.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.
With this minimal changes worked for me this bash script of @enrico.basis
#!/bin/bash
if [ $# -ne 2 ] ; then
echo "Usage: ssh-add-pass passfile keyfile"
exit 1
fi
eval 'ssh-agent -s'
passwordToFileSSH=$1
pathFileSSH=$2
expect << EOF
spawn ssh-add $pathFileSSH
expect "Enter passphrase"
send "$passwordToFileSSH\r"
expect eof
EOF
Came here looking for a specific solution, to load ssh-add from pass
the unix password manager. Thanks to the great answers here, I put together a script that does this for me:
#!/usr/bin/env bash
# Get password from pass
set -euo pipefail
keyfile=$(echo "$1" | /usr/bin/env sed -n 's/Enter passphrase for \(.*\):\s*$/\1/p');
echo "Extracted key filename $keyfile" >&2
[[ -z "${keyfile}" ]] && exit 1
comment=$(/usr/bin/env ssh-keygen -l -f "$keyfile" | /usr/bin/env awk '{print $3}')
echo "Comment from keyfile $keyfile is $comment" >&2
[[ -z "${comment}" ]] && exit 1
passphrase=$(/usr/bin/env pass show "ssh/$comment")
[[ -z "${passphrase}" ]] && exit 1
echo "got passphrase for comment $comment: XXX" >&2
echo "$passphrase"
Invoked with this:
env SSH_ASKPASS=/usr/local/bin/pass-ssh-askpass.sh SSH_ASKPASS_REQUIRE=force ssh-add
This wouldn't be possible without the answers here, so thanks for that, making this as community wiki for the greater good.
Once my ssh-add
supports the -p
option, I'll look into a different solution, but until then this will have to do.
Shameless plug: https://github.com/YarekTyshchenko/pass-ssh-askpass
The best way is to generate a key without a passphrase