How to sftp using Paramiko Transport class using key? - python

With other partners we have had no trouble getting a password to connect with. This is the code we use presently to connect via proxy partner's SFTP server using a password:
import paramiko
proxy_command = '/usr/bin/ssh ' + proxy_address + ' -p 22 /usr/bin/nc ' + host_address + ' ' + str(host_port)
proxy = paramiko.ProxyCommand(proxy_command)
transport = paramiko.transport.Transport(proxy)
transport.connect(username=username, password=password)
sftp = paramiko.sftp_client.SFTPClient.from_transport(transport)
Our newest partner will not share a password with us--the connection should rely solely on keys. How can we modify the above to implement the keys on the proxy and not be reliant on using a password to connect to the host?

If you are asking for to authenticate using a key with the Paramiko low-level Transport class, just use the pkey parameter of the Transport.connect method:
pkey = paramiko.RSAKey.from_private_key_file(filename)
transport.connect(username=username, pkey=pkey)
Though in general, you should use the high-level SSHClient class instead:
ssh = paramiko.SSHClient()
pkey = paramiko.RSAKey.from_private_key_file('id_rsa')
ssh.connect(hostname=host_address, sock=sock, username=username, pkey=key)
sftp = ssh.open_sftp()
Though it turned out, you want to authenticate using a key stored on the proxy/jump server. You cannot use a key stored on the proxy server from a Paramiko code running on a local server. You would have to connect from the proxy server. Or download the key to the local machine. Or just read the key on run time from the server to local memory (what is a form of a download). See also Executing command from remote server into another remote server using Paramiko.

Related

Verify host key with pysftp against known_hosts file with custom port

I'm trying to login in an SFTP server using pysftp.
This is the code I'm testing:
import pysftp
cnopts = pysftp.CnOpts()
# cnopts.hostkeys = None
host = 'data-nz.metservice.com'
username = 'my_user'
password = 'my_passwd'
ciphers = ['aes128-cbc', '3des-cbc', 'blowfish-cbc', 'aes192-cbc', 'aes256-cbc']
with pysftp.Connection(host, username=username, password=password,
port=9022, ciphers=ciphers, cnopts=cnopts) as sftp:
sftp.listdir()
Note that:
The server uses a non-standard port
The server only uses the five listed ciphers to negotiate the connection, therefore this option is mandatory
This code fails because he host key cannot be found:
SSHException: No hostkey for host data-nz.metservice.com found.
I have read this question, and I have successfully used the workaroud of setting cnopts.hostkeys=None (see commented out line in my code). But obviously I'd like to remove this security flaw. However I don't know how to cope this exception. I have logged in using plain sftp to make sure that the required line is added to my known_hosts. This action actually added two lines (whose content is not fully clear to me, as there is not explicit reference to the the URL, but anyway...), and now sftp does not complain:
|1|l+HfDGPUhea+8cUzCS+jq2HGcBg=|XMWhbkgujRtW1lJ4E93sTidUiCs= ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC8N65MCdnbHjaEDxkZPPq1QO0RLwP3cdm9Gb9BAMS0mFH39d7/yHIerA6yFZRW27u3NClI7V1F3hDuheoCUomeF9Q9ioaeQ2dlX27hmGf611RpSfI/vGgnmipHYzzHsCIJi0LxuowCouKNw8g1v1e2VzsVWFPaq+cDeuUpDwpBKWnxQUWN7U9mzN1k0sDALimWOzhfQmXtCzPkHqERUcPpdU7/zWP8Xk9H7FQxgiPFa+EC5xuCzn01CcJppQ8VBqL9R6SNNP/d9ymQWh3cotXe6sj5gt2MdfbAUfxddQITW1rU+LSOkG21QPMq0VBDJwWf9RpqhnqcvusZIFVGyOsn
|1|uILdQCq4UAlxnruPlWnb7vwpWbc=|AOjbzHHXJ44ibhLVJJSGk++ep+U= ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC8N65MCdnbHjaEDxkZPPq1QO0RLwP3cdm9Gb9BAMS0mFH39d7/yHIerA6yFZRW27u3NClI7V1F3hDuheoCUomeF9Q9ioaeQ2dlX27hmGf611RpSfI/vGgnmipHYzzHsCIJi0LxuowCouKNw8g1v1e2VzsVWFPaq+cDeuUpDwpBKWnxQUWN7U9mzN1k0sDALimWOzhfQmXtCzPkHqERUcPpdU7/zWP8Xk9H7FQxgiPFa+EC5xuCzn01CcJppQ8VBqL9R6SNNP/d9ymQWh3cotXe6sj5gt2MdfbAUfxddQITW1rU+LSOkG21QPMq0VBDJwWf9RpqhnqcvusZIFVGyOsn
But still the host key seems not to be acknowledged from Python. Any idea what is wrong with my program?
I guess the problem is that pysftp do not support custom ports when looking up the host key in the known_hosts file.
Add an entry like this:
data-nz.metservice.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC8N65MCdnbHjaEDxkZPPq1QO0RLwP3cdm9Gb9BAMS0mFH39d7/yHIerA6yFZRW27u3NClI7V1F3hDuheoCUomeF9Q9ioaeQ2dlX27hmGf611RpSfI/vGgnmipHYzzHsCIJi0LxuowCouKNw8g1v1e2VzsVWFPaq+cDeuUpDwpBKWnxQUWN7U9mzN1k0sDALimWOzhfQmXtCzPkHqERUcPpdU7/zWP8Xk9H7FQxgiPFa+EC5xuCzn01CcJppQ8VBqL9R6SNNP/d9ymQWh3cotXe6sj5gt2MdfbAUfxddQITW1rU+LSOkG21QPMq0VBDJwWf9RpqhnqcvusZIFVGyOsn
Or use Paramiko directly (pysftp is a wrapper around Paramiko), as Paramiko implements the host key lookup with custom port correctly.
Some background: The codes at the beginning of your original known_hosts are hashed host[:port] identifiers. Pysftp does not use port when looking up the entry, so it does not find the correct one. If you add fake (hashed or not) entry without the custom port, pysftp will be able to find it.

Translate Oracle SQL Developer SSH Host w/ Local Port Forward Connection to Python

I'm trying to create a Python connection to a remote server through an SSH Jump Host (one I've successfully created in Oracle SQL Developer) but can't replicate in Python. Can connect to SSH Host successfully but fail to forward the port to the remote server due to timeout or error opening tunnels. Safe to assume my code is incorrect rather than server issues. Also need a solution that doesn't use the "with SSHTunnelForwarder() as server:" approach because I need a continuous session similar to OSD/cx_Oracle session rather than a batch processing function.
Similar examples provided here (and elsewhere) using paramiko, sshtunnel, and cx_Oracle haven't worked for me. Many other examples don't require (or at least clearly specify) separate login credentials for the remote server. I expect the critical unclear piece is which local host + port to use, which my SQL Developer connection doesn't require explicitly (although I've tried using the ports OSD chooses, not at the same time).
Closest match I think was best answer from paramiko-port-forwarding-around-a-nat-router
OSD Inputs
SSH Host
- host = proxy_hostname
- port = proxy_port = 22
- username = proxy_username
- password = proxy_password
Local Port Forward
- host = remote_hostname
- port = remote_port = 1521
- automatically assign local port = True
Connection
- username = remote_username
- password = remote_password
- connection type = SSH
- SID = remote_server_sid
Python Code
i.e., analogous code from paramiko-port-forwarding-around-a-nat-router
import paramiko
from paramiko import SSHClient
# Instantiate a client and connect to the proxy server
proxy_client = SSHClient()
proxy_client.connect(
proxy_hostname,
port=proxy_port,
username=proxy_username,
password=proxy_password)
# Get the client's transport and open a `direct-tcpip` channel passing
# the destination hostname:port and the local hostname:port
transport = proxy_client.get_transport()
dest_addr = (remote_hostname,remote_port)
local_addr = ('localhost',55587)
channel = transport.open_channel("direct-tcpip", dest_addr, local_addr)
# Create a NEW client and pass this channel to it as the `sock` (along
# with whatever credentials you need to auth into your REMOTE box
remote_client = SSHClient()
remote_client.connect(
'localhost',
port=55587,
username=remote_username,
password=remote_password,
sock=channel)
Rather than a connection to the remote server I get
transport.py in start_client()
SSHException: Error reading SSH protocol banner
Solution
Finally figured out a solution! Analogous to OSD's automatic local port assignment and doesn't require SSHTunnelForwarder's with statement. Hope it can help someone else- use the question's OSD input variables with...
from sshtunnel import SSHTunnelForwarder
import cx_Oracle
server=SSHTunnelForwarder(
(proxy_hostname,proxy_port),
ssh_username=proxy_username,
ssh_password=proxy_password,
remote_bind_address=(remote_hostname,remote_port))
server.start()
db=cx_Oracle.connect('%s/%s#%s:%s/%s'%(remote_username,remote_password,'localhost',server.local_bind_port,remote_server_sid))
# do something with db
server.close()

How to access to a remote server using Paramiko with a public key-file

I need to connect to a remote server without the use of a password but using a public keyfile using the Python module Paramiko.
How can I do this?
Use key_filename argument of SSHClient.connect:
import paramiko
ssh = paramiko.SSHClient()
ssh.connect("example.com", username="user", key_filename="mykeyfile")
Though you need private key file for that. You cannot authenticate with public key file.
You will also need to verify the host key:
Paramiko "Unknown Server"

Getting "socket.error: [Errno 61] Connection refused" python paramiko

Getting error connection refused error when trying to connect to the host to copy a local file to the host server. Don't have any issue connecting to the server remotely though.
host = "9.29.22.222"
username = "XXX"
password = "XXX"
local_path = "/Users/samuelhii/Desktop/file.txt"
remote_path = "C:\Program Files (x86)\file.txt"
s = paramiko.SSHClient()
s.set_missing_host_key_policy(paramiko.AutoAddPolicy())
s.connect(host,22,username,password)
sftp = s.open_sftp()
sftp.put(local_path,remote_path)
The connection was refused by the server. This can be caused by several reasons not related to Python programming:
a firewall
the SSH service is configure not to take requests from your IP
bad host ip
… (many more)
Check if you can use the normal SSH client to connect with this host/user/password combination.

Authentication Type error in Paramiko using SFTP

I am using paramiko to establish an SFTP connection with a public/private key exchange. They key is an SSH2 RSA key. When I try to connect I'm receiving the error BadAuthenticationType: Bad authentication type (allowed_types=['']). Does anyone have an idea what might be causing this?
key = paramiko.RSAKey.from_private_key_file(key, password=passphrase)
transport = paramiko.Transport((host, port))
transport.start_client()
transport.auth_publickey(username, key)
sftp = paramiko.SFTPClient.from_transport(transport)
According to the documentation for Paramiko, the server you're trying to connect to isn't configured properly (it doesn't allow public-key authentication for the user you're using to connect). Here is a link to the portion of the documentation that I referenced, hopefully it will be of use. http://www.lag.net/paramiko/docs/paramiko.Transport-class.html#auth_publickey
I recommend that you check your server config and make sure everything is set up properly.

Categories

Resources