79

How I can make SFTP transport through SSHClient on the remote server? I have a local host and two remote hosts. Remote hosts are backup server and web server. I need to find on backup server necessary backup file and put it on web server over SFTP. How can I make Paramiko's SFTP transport work with Paramiko's SSHClient?

Martin Prikryl
  • 167,268
  • 50
  • 405
  • 846
Denis
  • 6,591
  • 6
  • 36
  • 57

4 Answers4

196

paramiko.SFTPClient

Sample Usage:

import paramiko
paramiko.util.log_to_file("paramiko.log")

# Open a transport
host,port = "example.com",22
transport = paramiko.Transport((host,port))

# Auth    
username,password = "bar","foo"
transport.connect(None,username,password)

# Go!    
sftp = paramiko.SFTPClient.from_transport(transport)

# Download
filepath = "/etc/passwd"
localpath = "/home/remotepasswd"
sftp.get(filepath,localpath)

# Upload
filepath = "/home/foo.jpg"
localpath = "/home/pony.jpg"
sftp.put(localpath,filepath)

# Close
if sftp: sftp.close()
if transport: transport.close()
evandrix
  • 5,889
  • 4
  • 26
  • 35
leoluk
  • 11,759
  • 6
  • 41
  • 49
  • 2
    Great answer. I'd add however that both `Transport` and `SFTPClient` implement the `__enter__`/`__exit__` interface thus can be used within a context manager e.g. `with Transport((host, port)) as transport:` – ayorgo Mar 12 '19 at 18:18
  • This implementation works however it does not cleanup processes. sftp-server process is forked with it and if you run it multiple times you can see there are a lot of processes exists after the completion of code. – Saurabh Nemade Jun 16 '20 at 11:27
  • 2
    While this *works*, with its use of the low-level `Transport` class, it bypasses a host key verification, what is a security flaw, as it makes the code susceptible to [Man-in-the-middle attacks](https://en.wikipedia.org/wiki/Man-in-the-middle_attack). Better is to use the right Paramiko SSH API, the `SSHClient`. See [my answer](https://stackoverflow.com/q/3635131/850848#66724076). – Martin Prikryl Mar 20 '21 at 16:44
18

The accepted answer "works". But with its use of the low-level Transport class, it bypasses a host key verification, what is a security flaw, as it makes the code susceptible to Man-in-the-middle attacks.

Better is to use the right Paramiko SSH API, the SSHClient, which does verify the host key:

import paramiko
paramiko.util.log_to_file("paramiko.log")

ssh = paramiko.SSHClient()
ssh.connect(host, username='user', password='password')
# or 
# key = paramiko.RSAKey.from_private_key_file('id_rsa')
# ssh.connect(host, username='user', pkey=key)

sftp = ssh.open_sftp()

sftp.get(remotepath, localpath)
# or
sftp.put(localpath, remotepath)

For details about verifying the host key, see:
Paramiko "Unknown Server"

Martin Prikryl
  • 167,268
  • 50
  • 405
  • 846
8

If you have a SSHClient, you can also use open_sftp():

import paramiko


# lets say you have SSH client...
client = paramiko.SSHClient()

sftp = client.open_sftp()

# then you can use upload & download as shown above
...
Alon Gouldman
  • 2,393
  • 20
  • 24
  • 2
    First, this is not a standalone answer, but mere comment to @leoluk's answer. Second, if you have `SSHClient`, you can simply do `sftp = client.open_sftp()`. – Martin Prikryl Sep 22 '19 at 15:00
1

In addition to the first answer which is great but depends on username/password, the following shows how to use an ssh key:

from paramiko import Transport, SFTPClient, RSAKey
key = RSAKey(filename='path_to_my_rsakey')
con = Transport('remote_host_name_or_ip', 22)
con.connect(None,username='my_username', pkey=key)
sftp = SFTPClient.from_transport(con)
sftp.listdir(path='.')
David W.
  • 165
  • 2
  • 5