Sunday, September 12, 2010

Automating ssh public key authentication with keys that have passphrases

This subject has burnt a day of my time this week... upon re-reviewing man ssh-add I should of got to solution much quicker. At first I was annoyed and the lack of documentation... perhaps now I'm just annoyed at how its written... because I failed to read it thoroughly enough the first time!

Enough rambling.

A large amount of my automation with bash involves remote host execution... most scripts I deal with require humans to do something like:

$ eval $(ssh-agent); ssh-add ~/.ssh/some-key
... enter some password if the key has one
$ ./some_script $servers $work

Where $servers is a file or list of hosts to be affected and $work gives the script an indication or direct instruction on what to perform on the remote hosts. a simple example of ./some_script:

#!/bin/bash
servers=$1;work=$2
for $server in $servers; do
ssh $user@$server "$work"
done

For some scripts, the time had come to make them part of a workflow and automate them further... the the scripts had to run completely autonomously and return the result of their execution to the workflow.

So, due to a number of factors, time being a big one, I decided to look at how to input a password to authenticate the remote access. I know this has security implications but it is what it is for now... to be improved in time.

I wanted to avoid having to use the expect command and I wanted to keep the existing authentication keys. So I set about the manuals for ssh, ssh-agent and ssh-add.

Up popped $SSH_ASKPASS... The primary mistake I made which burnt most of my time researching this... was not realising $SSH_ASKPASS ONLY applies to passphrases from public key authentication. It does not apply to interactive password authentication.
In layman's terms $SSH_ASKPASS provides the path to the executable that will output the passphrase for the given key.

So with that cleared up, my solution looks like this:

# setup env
$ export DISPLAY=none SSH_ASKPASS=/home/$user/output_phasephrase.sh;
# create authenticated session
$ eval $(ssh-agent); ssh-add /home/$user/.ssh/some-key < /dev/null

First set up the env for ssh-add and secondly add the key. After the key is added successfully, the shell/script session is fully authenticated for any remote hosts that recognise the key.

The output_passphrase.sh can be as simple or as complicated as you'd like. For example:

#!/bin/bash
echo 'some-passphrase'

Would work but has security implications! Something like this would be better:

#!/bin/bash
sudo gpg -d /home/$user/key-passphrase.txt.gpg 2> /dev/null

No comments: