SSH and SFTP with Paramiko & Python

Paramiko is a Python implementation of SSH with a whole range of supported features. To start, let’s look at the most simple example – connecting to a remote SSH server and gathering the output of ls /tmp/

import paramiko

ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
try:
        ssh.connect('localhost', username='testuser', password='t3st@#test123')
except paramiko.SSHException:
        print "Connection Failed"
        quit()

stdin,stdout,stderr = ssh.exec_command("ls /etc/")

for line in stdout.readlines():
        print line.strip()
ssh.close()

After importing paramiko, we create a new variable ‘ssh’ to hold our SSHClient. ssh.set_missing_host_key_policy automatically adds our server’s host key without prompting. For security, this is not a good idea in production, and host keys should be added manually. Should a host key change unexpectedly, it could indicate that the connection has been compromised and is being diverted elsewhere.

Next, we create 3 variables, stdin, stdout and stderr allowing us to access the respective streams when calling ls /etc/

Finally, for each “\n” terminated line on stdout, we print the line, stripping the trailing “\n” (as print adds one). Finally we close the SSH connection.

Let’s look at another example, where we communicate with stdin.

cat in its simplest form will print what it receives on stdin to stdout. This can be shown as follows:

root@w:~# echo "test" | cat
test

Simply, we can use:

stdin,stdout,stderr = ssh.exec_command("cat")
stdin.write("test")

To allow us to communicate with stdin. Wait! Now, the program hangs indefinitely. cat is waiting for an EOF to be received. To do so, we must close the channel:

stdin.channel.shutdown_write()

Now, let’s extend the example to read a colon separated username and password from a file:

import paramiko
import sys

ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

if len(sys.argv) != 2:
	print "Usage %s <filename>" % sys.argv[0]
	quit()

try:
	fd = open(sys.argv[1], "r")
except IOError:
	print "Couldn't open %s" % sys.argv[1]
	quit()

username,passwd = fd.readline().strip().split(":") #TODO: add error checking!

try:
	ssh.connect('localhost', username=username, password=passwd)
	stdin,stdout,stderr = ssh.exec_command("ls /tmp")
	for line in stdout.readlines():
		print line.strip()
	ssh.close()
except paramiko.AuthenticationException:
	print "Authentication Failed"
	quit()
except:
	print "Unknown error"
	quit()


Lastly, let’s look at reading a remote directory over SFTP:

import paramiko

ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
try:
	ssh.connect('localhost', username='testuser', password='t3st@#test123')
except paramiko.SSHException:
	print "Connection Error"
sftp = ssh.open_sftp()
sftp.chdir("/tmp/")
print sftp.listdir()
ssh.close()

Paramiko supports far more SFTP options, including of course the upload and download of files.

Tags: , , , , , , ,

6 Responses to “SSH and SFTP with Paramiko & Python”

  1. A K says:

    Please use except paramiko.SSHException, an unqualified except is not a good example to show in code that people might end copy & pasting.

  2. abc says:

    Are there any existing interesting server side usages for Paramiko? For example server that lets users access their files but only see their own files with shared bin binaries etc.

    • Adam Palmer says:

      Paramiko is a Python based SSH client. Anything that can be achieved with any other SSH client such as PuTTY – i.e. anything that the remote server supports can be called and utilized via Paramiko.

  3. I would recommend taking a look at fabric, it take most of the boilerplate away. (At long you don’t need to interact with processes at the “other” side, for interacting I would recommend https://github.com/fgimian/paramiko-expect it give expect api ontop of Paramiko)

Leave a Reply