Sunday 17 May 2015

[Bash / ssh] How to invoke command remotely without password / private key prompts ?

Sometimes you may want to invoke command on remote machine via ssh. You can obviously pass a command in double quotes:
ssh root@somehost.com "echo \$HOME"
This example prints to the console a value of env variable HOME (note that the dollar sign has to be escaped otherwise HOME variable will be resolved on your local machine). Let's say I want to fetch a value of some env variable in my bash script which will be started by Jenkins. There are actually two problems:
  • ssh will prompt for password,
  • if you haven't already accepted host's key there will be another prompt.
If you don't have proper entry in ~/.ssh/known_hosts you will see:
gt ~ ssh root@somehost.com "echo \$HOME"
                                                        
The authenticity of host 'somehost.com (10.92.30.38)' can't be established.
RSA key fingerprint is b0:c6:ad:6b:06:73:a3:de:31:8c:f8:4d:07:4e:2c:e6.
Are you sure you want to continue connecting (yes/no)? 

so you need to type "yes" in order to invoke the command.
In case you've already accepted the key you will see only:
gt ~ ssh root@somehost.com "echo \$HOME"                                                                                                           
root@somehost.com's password: 
Ssh doesn't have any flag for password (security) so you cannot do something like:
ssh root@somehost.com -p mySecretPassword
Solution for that is sshpass. I'm sure it's available in your linux distribution's repository. On Fedora install it using:
sudo yum install sshpass
So now you can pass the password easily:
gt ~ sshpass -p mySecretPassword ssh root@somehost.com "echo \$HOME"                                    
/root
In case you need to accept host's key you can use ssh -oStrictHostKeyChecking=no. Example:
gt ~ ssh root@somehost.com "echo \$HOME"                                                                          
The authenticity of host 'somehost.com (10.92.30.38)' can't be established.
RSA key fingerprint is b0:c6:ad:6b:06:73:a3:de:31:8c:f8:4d:07:4e:2c:e6.
Are you sure you want to continue connecting (yes/no)? ^C
zsh: interrupt  ssh root@somehost.com "echo \$HOME"
gt ~ sshpass -p mySecretPassword ssh -oStrictHostKeyChecking=no root@somehost.com "echo \$HOME"                             
Warning: Permanently added 'somehost.com,10.92.30.38' (RSA) to the list of known hosts.
/root
There is sctually another way of importing keys - ssh-keyscan command which output has to be appended to ~/.ssh/known_hosts file.
ssh-keyscan -H somehost.com >> ~/.ssh/known_hosts
Example:
gt ~ ssh root@somehost.com          
The authenticity of host 'somehost.com (10.92.30.39)' can't be established.
RSA key fingerprint is 3d:7d:a0:82:d7:3b:60:bc:58:ce:14:d2:bf:1e:d5:89.
Are you sure you want to continue connecting (yes/no)? ^C
zsh: interrupt  ssh root@somehost.com
gt ~ ssh-keyscan -H somehost.com >> ~/.ssh/known_hosts  
# somehost.com SSH-2.0-OpenSSH_5.3
# somehost.com SSH-2.0-OpenSSH_5.3
no hostkey alg
gt ~ ssh root@somehost.com 
Warning: Permanently added the RSA host key for IP address '10.92.30.39' to the list of known hosts.
root@somehost.com's password: 
Last login: Thu May 14 15:24:06 2015 from 10.154.8.71
[root@somehost ~]#
Value returned by the command invoked on remote host can obviously be assigned to some variable in bash script:
gt ~ cat script.sh
#!/bin/bash
REMOTE_HOME=$(sshpass -p arthur ssh -oStrictHostKeyChecking=no root@somehost.com "echo \$HOME")
echo "remote home = ${REMOTE_HOME}"
gt ~ ./script.sh
remote home = /root
As you can see both problems can be solved quite easily but you should realize that this kind of hacks (sshpass) shouldn't be used in production environment. Actually I use this kind of scripts which pass password in plain text only in test environments which aren't directly connected to the internet. Generally such machines are used only for snapshots' testing and don't store any crucial data. You should definitely read this part of sshpass man page:
SECURITY CONSIDERATIONS

First and foremost, users of sshpass should realize that ssh's insistance on only getting the password interactively is not without reason. 
It is close to impossible to securely store the password, and users of sshpass should consider whether ssh's public key authentication provides the same end-user experience, while involving less hassle and being more secure.

The -p option should be considered the least secure of all of sshpass's options. 
All system users can see the password in the command line with a simple "ps" command. Sshpass makes a minimal attempt to hide the password, but such attempts are doomed to create race conditions without actually solving the problem. 
Users of sshpass are encouraged to use one of the other password passing techniques, which are all more secure.

In particular, people writing programs that are meant to communicate the password programatically are encouraged 
to use an anonymous pipe and pass the pipe's reading end to sshpass using the -d option. 

No comments:

Post a Comment