October 22, 2018

Scripting SSH and SFTP Made Easy With Python

Secure, Automated SSH and SFTP Sessions

  • December 16, 2008
  • By Jeremy M. Jones

SSH is an indispensable tool that I use every day for file transfers, remote execution of tasks, setting up network port redirection between systems (tunneling), and securely driving a shell on a remote system. While the SSH commandline client on UNIX and Linux systems is how I interact most often with SSH servers on the remote end, there are times when it is helpful to script some action or series of actions rather than performing them interactively.

This is where Python and paramiko come in. paramiko is a library for Python that provides a programmatic interface to SSH. This combination of Python and SSH allows you to drive SSH tasks you would normally perform manually.

Installation of paramiko is pretty simple. If you're using Ubuntu or Debian, installation is a simple "sudo apt-get install python-paramiko" command in a terminal. If you aren't using Ubuntu or Debian, you can check to see if your system provides a package for paramiko. If it doesn't, then you can always use easy_install: "sudo easy_install paramiko".

After installing, the next step is to create an SSHClient object and connect it to an SSH server. I've created a module named "ssh_common.py" that contains a function to connect to a specific server on my network and then return an "ssh" object.

#!/usr/bin/env pythonimport paramiko
from contextlib import contextmanagerhost = ''
username = 'slacker'
password = 'insecure'@contextmanager
def create_ssh(host=host, username=username, password=password):
��� ssh = paramiko.SSHClient()
��� ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) try:
������ print "creating connection"
������ ssh.connect(host, username=username, password=password)
������ print "connected"
������ yield ssh
��� finally:
������ print "closing connection"
������ ssh.close()
������ print "closed"

The first couple of lines are imports: one for "paramiko" and another for "contextlib". "paramiko" contains all of the SSH code that we'll use. "contextlib" contains code that helps setup a context manager in a very simple way. Context managers are a fairly new feature to Python. I won't go into great detail in describing them here, but the gist of a context manager is that it allows you to create some resource that you can use in a "with" code block. It performs some initialization code before the "with" block is entered and then runs some finalization code after the "with" block is completed. I am using a context manager with an SSH connection because I know that before I use the connection, I need it to login to the server and after I get done with it, I want it to close.

Related Articles

Have a Bash With This Linux Shell
Scripting Best Practices
OpenSSH Speed Tips and Tricks

After the imports, I set "host", "username", and "password" variables that the "create_ssh()" function will pick up by default. While this function will pick these values up by default, you can certainly override one or all of them if you import the module and call the function yourself.

Next, I define the function "create_ssh()" that I just mentioned. I set a "contextmanager" decorator on "create_ssh()" so that it can be used as a context manager. Inside "create_ssh()", I create an "SSHClient" object and refer to it as "ssh". I then set a host key policy to automatically accept host keys from any host it connects to. If you are concerned with security, you'll want to change this behavior so that it is not quite so permissive.

Next, I create a try/finally block. In the try/finally block, I connect to the specified server and then login. After connecting, I "yield" the "ssh" object. A context manager executes the code up to the point of "yield" before anything else in the "with" block. (I'll get to an example of the "with" block in the next code example.)

In the "finally" block, I simply "close()" the connection. A context manager executes the code after the "yield" after everything else in the "with" block has run. In this case, it will execute the "finally" block even if an exception is raised when the "ssh" object is used. Note that before and after creating the connection and closing it, I have placed "print" statements to detail what is going on in the code.

Here is a very simple example that creates a "with" block and uses the "ssh" object:

#!/usr/bin/env pythonfrom __future__ import with_statement
import ssh_commonwith ssh_common.create_ssh() as ssh:
��� print ssh

All that I do in this example is to get an "ssh" object from the "create_ssh()" function in the "with" statement and then print the "ssh" object.

Here is the output from running this simple code:

jmjones: python_ssh$ python simple_connect.py
creating connection

closing connection closed

You can see that the pre- and post- "yield" statements ran before and after the print statement that displayed the "ssh" object. This means that the "ssh" object was initialized before any code ran in the "with" block and it was finalized after the code ran inside the "with" block.

Most Popular LinuxPlanet Stories