How to pass an ssh key passphrase via environment variable

11,005

Solution 1

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:

[email protected]:~/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]-----+
[email protected]:~/projects/gitlab.com/aucampia/stackexchange/stackoverflow/38354773
$ 
[email protected]:~/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
[email protected]:~/projects/gitlab.com/aucampia/stackexchange/stackoverflow/38354773
$ chmod +x /tmp/se-so-38354773-askpass
[email protected]:~/projects/gitlab.com/aucampia/stackexchange/stackoverflow/38354773
$ 
[email protected]:~/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
[email protected]:~/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)
[email protected]:~/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)
[email protected]:~/projects/gitlab.com/aucampia/stackexchange/stackoverflow/38354773
$ rm /tmp/se-so-38354773*

Solution 2

Edit: I am adding more details to this answer. If you have a PEM encoded private key with a password you can use openssl to decrypt the key first, as openssl will accept a passphrase on stdin.

To generate a new key that will work with this use this command:

ssh-keygen -t rsa -m pem -b 4096

It cannot be an 'OPENSSH' key. The start of an existing key that looks like this should work.

-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-128-CBC,8032BCA01FB25FCCD89AFDED8DB52079

Then, you can use openssl to decrypt the key before sending it to ssh-add. Openssl accepts the passphrase on stdin with the -passin stdin option and will by default output to stdout, then ssh-add can accept the unencrypted key on stdin by adding a - as the first argument.

echo "$MY_PASSPHRASE" | openssl rsa -in my_encrypted_key -passin stdin | ssh-add -
Share:
11,005
Sergei Voitovich
Author by

Sergei Voitovich

I like programming languages, functional programming, algorithms, TDD and quality. I have a knack for UX design and passion for modelling complex domains. I studied mathematics and computer science, worked at JetBrains for 4 years and have been working at Apple since 2019.

Updated on June 04, 2022

Comments

  • Sergei Voitovich
    Sergei Voitovich about 2 years

    I run shell script with ssh command inside my application. Used private key is encrypted by passphrase and the problem is - I cannot interactively pass it when asked.Key is not added in ssh-agent. I cannot execute ssh-add my_key because the passphrase is suppose to be passed interactively. It's good for terminal communication, but not so good to use inside application.

    The man page says:

    DISPLAY and SSH_ASKPASS

    If ssh-add needs a passphrase, it will read the passphrase from the current terminal if it was run from a terminal. If ssh-add does not have a terminal associated with it but DISPLAY and SSH_ASKPASS are set, it will execute the program specified by SSH_ASKPASS and open an X11 window to read the passphrase. This is particularly useful when calling ssh-add from a .xsession or related script. (Note that on some machines it may be necessary to redirect the input from /dev/null to make this work.)

    When I execute SSH_ASKPASS=file_with_passphrase ssh-add my_key I still asked to type a passphrase, looks like env var is just ignored in that case. I tryed to execute ssh -o BatchMode=yes and server just rejected encoded key because no one was able to decoded it.

    I definitely can decode ssh key manually before using it in ssh-agent but it looks like I'm about to get what I need from SSH_ASKPASS variable, but I don't know how to make it work. Happy to get community help.

  • Sergei Voitovich
    Sergei Voitovich almost 8 years
    user@imnc:~/Code/Sandbox$ chmod +x passphrase.sh user@imnc:~/Code/Sandbox$ DISPLAY=":0.0" SSH_ASKPASS=./passphrase.sh setsid ssh-add encrypted_key Enter passphrase for encrypted_key: No idea why but I still getting asked to enter a passphrase. Didn't work either
  • Sergei Voitovich
    Sergei Voitovich almost 8 years
    Oh, sorry again, missed dev/null redirection, it is working actually. Thanks a lot
  • Sergei Voitovich
    Sergei Voitovich almost 8 years
    It seems too tricky to achieve so simple requirement and also unsecure as hell. Wonder how people solve such problem.
  • Iwan Aucamp
    Iwan Aucamp almost 8 years
    @SergeyVoitovich Can you maybe elaborate on your use case a bit ? I only had to use this once ever and that was actually not for adding a key but for passing a password to ssh since the endpoint was running some custom ssh solution with no support for key based auth available to me. If you have automated use cases the right approach in most cases is to not use a passphrase and just restrict access to keys and also restrict access in authorized keys file. See serverfault.com/questions/142959 for some discussion.
  • Sergei Voitovich
    Sergei Voitovich almost 8 years
    sure: distributed java web application, one instance fetches repo from another one using git via ssh. Generally ssh key is not known for ssh agent``. Inside I call native git and pass key with GIT_SSH` environment variable. GIT_SSH is set to bash script, which calls native ssh. In order to support windows I can't use something except git bash supports (sadly, I don't know a lot about it). The key may be encrypted and my app asked to provide a pasphrase and I was in a search to satisfy this need:)
  • Abhishek Dutt
    Abhishek Dutt about 3 years
    Be more specific about the answer.
  • morrow
    morrow over 2 years
    set SSH_ASKPASS_REQUIRE=force instead of DISPLAY