Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to pass commands to an SSH from subprocess in Python

I have used the subprocess module in Python 2.7.6 to establish an SSH. I realise that this is not recommended, but I am unable to install other Python SSH libraries such as paramiko and fabric.

I was just wondering if someone wouldn't mind just telling me how I'd now go about

sshProcess = subprocess.call(['ssh', '-t', '<REMOTE>', 'ssh', '<REMOTE>']) 

I want to carry out commands in REMOTE with the subprocess approach. Is there any way to do this? Unfortunately, REMOTE is protected by a password which the user manually enters. If it helps, I'm running the Windows 10 Bash shell.

Any help is appreciated.

like image 432
entity without identity Avatar asked Oct 30 '22 10:10

entity without identity


1 Answers

Running a remote command is as simple as putting it on the command line. (This is distinguishable to the SSH server at a protocol level from feeding it on stdin, but the protocol in question is built for programmatic use, vs built for human use -- as the latter was the design intent behind the interactive-shell model).

By the way, if you want to run multiple commands via distinct SSH invocations over a single connection after authenticating only once, I'd strongly suggest using Paramiko for this, but you can do it with OpenSSH command-line tools by using SSH multiplexing support.


Let's say you have an array representing your remote command:

myCommand = [ 'ls', '-l', '/tmp/my directory name with spaces' ]

To get that into a string (in a way that honors the spaces and can't let a maliciously-selected name run arbitrary commands on the remote server), you'd use:

myCommandStr = ' '.join(pipes.quote(n) for n in myCommand)

Now, you have something you can pass as a command line argument to ssh:

subprocess.call(['ssh', '-t', hostname, myCommandStr])

However, let's say you want to nest this. You can just repeat the process:

myCommand = [ 'ssh', '-t', hostname1, myCommandStr ]
myCommandStr = ' '.join(pipes.quote(n) for n in myCommand)
subprocess.call(['ssh', '-t', hostname2, myCommandStr])

Because we aren't redirecting stdin or stdout, they should still be pointed at the terminal from which your Python program was started, so SSH should be able to execute its password prompts directly.


That said, specifically for ssh'ing through an interim system, you don't need to go through this much trouble: You can tell ssh to do that work for you with the ProxyJump option:

myCommand = [ 'ls', '-l', '/tmp/my directory name with spaces' ]
myCommandStr = ' '.join(pipes.quote(n) for n in myCommand)
subprocess.call(['ssh', '-o', 'ProxyJump=%s' % hostname1, hostname2, myCommandStr])
like image 71
Charles Duffy Avatar answered Nov 09 '22 10:11

Charles Duffy