14

I am using this code for executing command on remote server.

import subprocess import sys COMMAND="ls" ssh = subprocess.Popen(["ssh", "%s" % HOST, COMMAND], shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE) result = ssh.stdout.readlines() if result == []: error = ssh.stderr.readlines() print >>sys.stderr, "ERROR: %s" % error else: print result 

When I try to execute this script, I get prompt for password. Is there any way I could avoid it, for example, can I enter password in script somehow? Also, password should be encrypted somehow so that people who have access to the script cannot see it.

1
  • 2
    Have you thought about using an authentication scheme other than password entry? Commented Jul 17, 2015 at 13:51

7 Answers 7

5

Why make it so complicated? Here's what I suggest:

1) Create a ssh config section in your ~/.ssh/config file:

Host myserver HostName 50.50.50.12 (fill in with your server's ip) Port xxxx (optional) User me (your username for server) 

2) If you have generated your ssh keypair do it now (with ssh-keygen). Then upload with:

$ ssh-copy-id myserver 

3) Now you can use subprocess with ssh. For example, to capture output, I call:

result = subprocess.check_output(['ssh', 'myserver', 'cat', 'somefile']) 

Simple, robust, and the only time a password is needed is when you copy the public key to the server.

BTW, you code will probably work just fine as well using these steps.

Sign up to request clarification or add additional context in comments.

Comments

4

One way is to create a public key, put it on the server, and do ssh -i /path/to/pub/key user@host or use paramiko like this:

import paramiko import getpass ssh = paramiko.SSHClient() ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) p = getpass.getpass() ssh.connect('hostname', username='user', password=p) stdin, stdout, stderr = ssh.exec_command('ls') print stdout.readlines() ssh.close() 

Comments

3

You should use pexpect or paramiko to connect to remote machine,then spawn a child ,and then run subprocess to achieve what you want.

Comments

2

Here's what I did when encountering this issue before:

  1. Set up your ssh keys for access to the server.
  2. Set up an alias for the server you're accessing. Below I'll call it remote_server.
  3. Put the following two lines at the end of ~/.bash_profile.

    eval $(ssh-agent -s) ssh-add 

Now every time you start your shell, you will be prompted for a passphrase. By entering it, you will authenticate your ssh keys and put them 'in hand' at the start of your bash session. For the remainder of your session you will be able to run commands like

 ssh remote_server ls 

without being prompted for a passphrase. Here ls will run on the remote server and return the results to you. Likewise your python script should run without password prompt interruption if you execute it from the shell.

You'll also be able to ssh to the server just by typing ssh remote_server without having to enter your username or password every time.

The upside to doing it this way is that you should be doing this anyway to avoid password annoyances and remembering funky server names :) Also you don't have to worry about having passwords saved anywhere in your script. The only potential downside is that if you want to share the python script with others, they'll have to do this configuring as well (which they should anyway).

Comments

1

You don't really need something like pexpect to handle this. SSH keys already provide a very good and secure solution to this sort of issue.

The simplest way to get the results you want would probably be to generate an ssh key and place it in the .ssh folder of your device. I believe github has a pretty good guide to doing that, if you look into it. Once you set up the keys correctly on both systems, you won't actually have to add a single line to your code. When you don't specify a password it will automatically use the key to authenticate you.

Comments

0

While subprocess.Popen might work for wrapping ssh access, this is not the preferred way to do so.

I recommend using paramiko.

import paramiko ssh_client = paramiko.SSHClient() ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) ssh_client.connect(server, username=user,password=password) ... ssh_client.close() 

And If you want to simulate a terminal, as if a user was typing:

chan=ssh_client.invoke_shell() def exec_cmd(cmd): """Gets ssh command(s), execute them, and returns the output""" prompt='bash $' # the command line prompt in the ssh terminal buff='' chan.send(str(cmd)+'\n') while not chan.recv_ready(): time.sleep(1) while not buff.endswith(prompt): buff+=ssh_client.chan.recv(1024) return buff[:len(prompt)] 

Example usage: exec_cmd('pwd')

If you don't know the prompt in advance, you can set it with:

chan.send('PS1="python-ssh:"\n') 

2 Comments

paramiko is probably too low-level to run a command via ssh. It is easier to use fabric or pexpect here. The right solution would use ssh keys anyway.
Yeah, ssh keys for sure unless that's not desired for some reason.
0

You could use following.

import subprocess import sys COMMAND="ls" ssh = subprocess.Popen("powershell putty.exe user@HOST -pw "password", stdout=PIPE, stdin=PIPE, stderr=STDOUT) result = ssh.stdout.readlines() if result == []: error = ssh.stderr.readlines() print >>sys.stderr, "ERROR: %s" % error else: print result 

1 Comment

Can you please show how your snippet attempts to answer the question? Also, please follow StackOverflow's guidelines on how to answer a question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.