Paramiko and corporate proxies

16/10/2014 Bertrand Chenal How to Brian Cantoni

Since November 2012 and the release 1.9, the Paramiko API allows to use a proxy command when the ssh connection is created. For example:

client = paramiko.SSHClient()
sock = paramiko.ProxyCommand(proxy_command)
client.connect(
        hostname=host,
        port=port,
        username=username,
        password=password,
        sock=sock,
        )

where proxy_command contains a string with a command line that will be launched as subprocess.

This mimick the ProxyCommand option of OpenSSH and offer a lot of flexibility, but this may not be interesting if you want your code to run reliably across different OSes and configurations. Actually, the OpenSSH ProxyCommand option is often configured to launch another ssh instance and daisy-chain connections, which is probably something that we can't or don't want to do.

The sock argument of the connect method support a socket-like object and so will happily use a real socket if you take care to create one. So let's use it to connect to our proxy, which is quite easy thanks to the httplib and urlparse modules:

host = "mysshsever.com"
port = 22

proxy_uri = "http://login:passwd@proxy.example.com:8080"
url = urlparse.urlparse(proxy_uri)
http_con = httplib.HTTPConnection(url.hostname, url.port)

headers = {}
if url.username and url.password:
auth = '%s:%s' % (url.username, url.password)
headers['Proxy-Authorization'] = 'Basic ' + base64.b64encode(auth)

http_con.set_tunnel(host, port, headers)
http_con.connect()
sock = http_con.sock

We can then pass this socket to the connect method :

client = paramiko.SSHClient()
client.connect(
        hostname=host,
        port=port,
        username=username,
        password=password,
        sock=sock,
        )

References:

Bertrand Chenal

Bertrand is a software engineer with a passion for underground culture and technology.