Automatic loading of SSH keys from scripts

a keyWhen using SSH with public-key authentication, ‘ssh-agent‘ is a useful compromise between storing the SSH private key un-encrypted to disk and having to type the key`s passphrase every time you need to make an SSH connection.

When using SSH from scripts, things are further complicated, because no one is around to type in the passphrase. From this reason, SSH keys that are used by servers are, more often then not, stored with no encryption, thereby becoming a lucrative target for hackers.

With some clever manipulation, a script can be written in such a way where it can make use of the ‘ssh-agent‘ to load and use an encrypted private key.

The first thing a script needs to do is load up an instance of the SSH agent. The agent itself is very helpful here and could be loaded like this:

eval "$(ssh-agent)" > /dev/null
trap 'ssh-agent -k > /dev/null' EXIT

The output of the agent is a shell script defining the environment variables needed to use it. The redirection to ‘/dev/null‘ is needed because the agent generates some ‘echo‘ commands. The ‘trap‘ command is used to make sure the agent is shut down when the script exits.

Once the agent is up we can try to load a private key by using the following command (Assuming the path to the key file is stored in the ‘KEY_FILE‘ variable:

ssh-add "$KEY_FILE"

This will not work. Placing this in a script will cause it to stop and wait for the user to enter the passphrase for the private key. We can try to work around this the following way (Assuming the passphrase is stored in the ‘PASS‘ variable:

echo "$PASS" | ssh-add "$KEY_FILE"

But this is also doomed to fail. ‘ssh-add‘ actually makes an effort to ensure the password is entered manually by a user from a TTY. When run like this (With the standard input not attached to a TTY), ‘ssh-add‘ will actually (by default) try to invoke a graphical program to ask for a password. This behavior can be very useful for desktop scripts, but harmful when automating a server.

One way to work around this, is to use tools like ‘expect‘ to simulate user input. But there is another way that doesn’t necessitate having more tools. When ‘ssh-add‘ asks of a password and doesn’t have a direct access to a terminal, it will invoke the program specified by the ‘SSH_ASKPASS‘ environment variable. We can use that to make it more friendly towards our script. First, we would need a little helper script like the following:

exec cat

Once the helper is in place (lets call it ‘‘ for now), we can use it like this:

echo "$PASS"| SSH_ASKPASS=./ ssh-add "$KEY_FILE" 2> /dev/null

We need the helper (Instead of running ‘cat‘ directly) in order to do away with the parameters that ‘ssh-add‘ tries to pass to the ‘askpass‘ program. Otherwise, ‘cat‘ will try to interpret them as file names an fail.

We redirect the standard error channel because ‘ssh-add‘ is chatty and reports loading of the keys.

And there you have it. Now you can use the ‘ssh-agent‘ in your scripts to load and use keys that are protected by a passphrase. That is, provided that you have means of making the passphrase known to the script. Storing it in a clear-text file, is, of course, not a good idea, but that is a problem for another day.

5 thoughts on “Automatic loading of SSH keys from scripts

    • Hi ,

      Above solution is working locally but not using remotely.

      I have copied all the command in a script and executing, It’s working locally.

      But When I connected to the machine using ssh and trying to execute the same script is asking password to enter.

      I am wondering how come its working locally but not remotely?

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s