Connecting to SFTP client using proxy command in Python - python

I need to connect to SFTP server using proxy command.
I know how to connect to SFTP server directly:
paramiko's sshclient with sftp
I can open an SSH connection via proxy command using this code:
import paramiko
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
target_host = 'sftp.XXXXX.co'
target_port = 22
proxy = paramiko.proxy.ProxyCommand('/usr/bin/nc --proxy proxy_host:8080 %s %d' % (target_host, target_port) )
client.connect(hostname=target_host,username='username', port=target_port, password='XXXXXXXX', sock=proxy)
But I need to create SFTPClient, not SSHClient. But I do not know how to pass the ProxyCommand to the SFTPClient.

To connect to SFTP server using a "custom socket", do:
proxy = paramiko.proxy.ProxyCommand(...)
transport = paramiko.Transport(proxy)
transport.connect(username = username, password = password)
sftp = paramiko.SFTPClient.from_transport(transport)

Related

Attempting to do remote login over SSH connection using python script

I am trying to log in to a remote server after setting up an SSH connection. I can get the SSH Tunnel to work, but from there I'm stumped on how to log in.
I am currently using Python's sshtunnel extension, which successfully connects me to the place I need. Now I need to be able to log in which I would usually do through a terminal with the command "ssh remotepc-ssh" (I have all the information stored in a /.ssh/config file)
I have already tried paramiko but it continuously gives me errors or won't load in the end. I also tried pysftp which is what I show in the code below but when I try to get the my known_hosts it tells me that it isn't finding any known ones, and when I try to set hosts to None, the system won't connect.
from sshtunnel import SSHTunnelForwarder
#import paramiko
import pprint
import pysftp
# create SSH tunnel
SERVER_HOST = "hostname"
SERVER_PASS = "********"
LOGIN_HOST = "loginUsername"
LOGIN_PASS = "*********"
server = SSHTunnelForwarder(
SERVER_HOST,
ssh_password = SERVER_PASS,
remote_bind_address=('127.0.0.1', 8080)
)
try:
server.start()
print("Connected to SSH Tunnel with local bind port %s" %server.local_bind_port)
###################################
# BROKEN PART BELOW
# establish remote connection
try:
print("\nEstablishing connection to %s" %LOGIN_HOST)
cnopts = pysftp.CnOpts()
cnopts.hostkeys.load = ("known_hosts")
with pysftp.Connection(LOGIN_HOST, password = LOGIN_PASS, cnopts = cnopts) as sftp:
print("CONNECTED")
except:
print("Unable to connect")
pass
##################################
server.stop()
print("\nServer stopped. Goodbye")
except:
print("Could not connect")
pass
I've just came by and solved the same issue, so let me share my working example:
with SSHTunnelForwarder(
("SSH_HOST",22),
ssh_username="SSH_USERNAME",
ssh_pkey="SSH_KEY",
remote_bind_address=("SFTP_HOST", 22),
) as tunnel:
# do some operations with client session
with pysftp.Connection(host='127.0.0.1', port=server.local_bind_port, username="SFTP_USERNAME",
private_key="SFTP_KEY", cnopts=cnopts) as sftp:
print("Connection succesfully stablished ... ")
print(sftp.listdir('public'))
print('FINISH!')

Paramiko SSHClient.connect fails while SSH works

in the terminal, the following works just fine:
> ssh me#host -p 22
but the following python code gives me a TimeoutError:
from paramiko import SSHClient
client = SSHClient()
client.connect(hostname='host', port=22, username='me', look_for_keys=True)
Any idea why that would be the case? The connection uses RSA keys for authentication, and I'm over a VPN. Seems like I'm missing some context I need to tell paramiko about, but I can't figure out what it is.
I usually connect to a remote server by adding an explicit link to my private key:
HOST = 'hostname'
USER = 'username'
PKEY = '/path/to/rsa_private_key'
PKEY_PASS = 'xxx'
k = paramiko.RSAKey.from_private_key_file(PKEY, PKEY_PASS)
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
print "connecting"
ssh.connect(HOST, username=USER, pkey=k)
connect_status = 'connected' if ssh else 'failed to connect'
print connect_status

Paramiko SFTPClient - Setting missing host key policy?

I know with Paramiko's SSHClient class, you can set a relaxed missing host key policy like so:
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
However, I'm opening a file stream via SFTP (not SSHClient), like so:
t = paramiko.Transport((process['hostname'], 22))
keyfile = paramiko.DSSKey.from_private_key_file('./id_dsa')
t.connect(username = 'user', pkey = keyfile)
sftp = paramiko.SFTPClient.from_transport(t)
I couldn't locate anything in the docs for setting a missing host key policy via Transport, or SFTPClient.
Is there any way to achieve the same thing using SFTPClient?
Cheers,
Victor
One can get SFTP client from SSH client by using open_sftp().
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
sftp = ssh.open_sftp()
sftp.get('remotefile', 'localfile')
Though I haven't tested this.

paramiko can't open SFTP connection

I'm having some trouble opening an SFTP connection with paramiko. My current code is:
client = SSHClient()
client.set_missing_host_key_policy(AutoAddPolicy())
client.load_system_host_keys()
client.connect('some.example.com', username="myuser", password="mypassword")
sftp_client = client.open_sftp()
sftp_client.put(my_local_file)
But at the point where I hit client.open_sftp(), I get an exception of "Unable to open channel."
Any idea what might cause this? I've been able to open the connection to the server with a command-line sftp client.
I'm guessing about my invocation here, if anyone can point me to an example, that would be great.
You need to first create and connect to a transport:
transport = Transport((host, port))
transport.connect(username = username, pkey = mykey) # or password = mypassword
Now to can start the SFTP client:
sftp_client = SFTPClient.from_transport(transport)
Then you can
sftp_client.put(my_local_file)
and when you're done
sftp_client.close()
transport.close()

Paramiko's SSHClient with SFTP

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?
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()
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"
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
...
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='.')
For those anyone need to integrate with an ssh/sftp server that requires a private key and want to perform host key verification for the known host by using a specific public key, here is a snippet code with paramiko:
import paramiko
sftp_hostname = "target.hostname.com"
sftp_username = "tartgetHostUsername"
sftp_private_key = "/path/to/private_key_file.pvt"
sftp_private_key_password = "private_key_file_passphrase_if_it_encrypted"
sftp_public_key = "/path/to/public_certified_file.pub"
sftp_port = 22
remote_path = "."
target_local_path = "/path/to/target/folder"
ssh = paramiko.SSHClient()
# Load target host public cert for host key verification
ssh.load_host_keys(sftp_public_key)
# Load encrypted private key and ssh connect
key = paramiko.RSAKey.from_private_key_file(sftp_private_key, sftp_private_key_password)
ssh.connect(host=sftp_hostname, port=sftp_port, username=sftp_username, pkey=key)
# Get the sftp connection
sftp_connection = ssh.open_sftp()
directory_list = sftp_connection.listdir(remote_path)
# ...
if sftp_connection: sftp_connection.close()
if ssh: ssh.close()
Notice that only certificates in classic Openssh format are supported, otherwise needs to be converted with the following commands (also for the latest Openssh formats):
$chmod 400 /path/to/private_key_file.pvt
$ssh-keygen -p -f /path/to/private_key_file.pvt -m pem -P <currentPassphrase> -N <newPassphrase>
In order to avoid man in the middle attack, it is important to do not use paramiko.AutoAddPolicy() and load the public host key programmatically as above or load it from ~/.ssh/known_hosts
The file must be in the format "<host_name> ssh-rsa AAAAB3NzaC1yc2EAAAA..."
In case you don't have the public key and you trust the target host (take care to mitm), you can download it using $ssh-keyscan target.hostname.com command.
The above code is the only way I found to avoid the following error during connection:
paramiko.ssh_exception.SSHException: Server 'x.y.z' not found in known_hosts
This error was prompted also with the following way to load the public certificates:
key = paramiko.RSAKey(data=decodebytes(sftp_public_key))
ssh_client.get_host_keys().add(sftp_hostname, 'ssh-rsa', key)
Also the following code was not able for me to load the certificate (tried also by encoding the certificate in base64):
ssh_client=paramiko.SSHClient()
rsa_key = paramiko.RSAKey.from_private_key_file(sftp_private_key, sftp_private_key_password)
rsa_key.load_certificate(sftp_public_key)
It always ends with:
File "/usr/local/lib/python3.9/site-packages/paramiko/pkey.py", line 720, in from_string
key_blob = decodebytes(b(fields[1]))
File "/usr/lib64/python3.9/base64.py", line 538, in decodebytes
return binascii.a2b_base64(s)
binascii.Error: Incorrect padding
The above code above worked for the SFTP integration with GoAnywhere.
I hope this is helpful, I've not found any working example and spent many hours in searches and tests.
The implementations using pysftp wrapper it is now to be considered as discontinued from 2016.

Categories