'Can you pass a file like object as a parameter to pysftp.CnOpts in Python [duplicate]

I have a Python script that uses pysftp to create an SFTP connection to a remote host as shown:

 cnopts = pysftp.CnOpts(knownhosts='known_hosts') # REFERENCE A STATIC FILE
 sftp = pysftp.Connection(host=parm0, username=parm1, password=parm2, cnopts=cnopts)

The file "known_hosts" lives in the same directory where the Python script lives. I would like to eliminate the static know_hosts file and pass a file like object to pysftp.CnOpts() like this:

 remote_public_key = subprocess.getoutput('ssh-keyscan myRemoteSFTPServer.com')
 key_buffer.write(remote_public_key)
 key_buffer.seek(0)
 cnopts = pysftp.CnOpts(knownhosts=key_buffer.read()) # REFERENCE A FILE LIKE OBJECT
 sftp = pysftp.Connection(host=parm0, username=parm1, password=parm2, cnopts=cnopts)     
 

However, this fails. Is it possible to pass a file like object as a parameter to pysftp.CnOpts, and if so, how do I do it?



Solution 1:[1]

Did you try

cnopts = pysftp.CnOpts(knownhosts=key_buffer)

to just pass in the file-like object? If you do key_buffer.read(), that'd be equivalent to

cnopts = pysftp.CnOpts(knownhosts="# 127.0.0.1:22 SSH-2.0-OpenSSH_8.1...")

or whatever is in the buffer, and pysftp would likely try to interpret that as a filename.

Failing that,

with tempfile.NamedTemporaryFile("wb") as key_buffer:
    remote_public_key = subprocess.getoutput('ssh-keyscan myRemoteSFTPServer.com')
    key_buffer.write(remote_public_key)
    key_buffer.seek(0)
    cnopts = pysftp.CnOpts(knownhosts=key_buffer.name)
    sftp = pysftp.Connection(host=parm0, username=parm1, password=parm2, cnopts=cnopts)     

(NamedTemporaryFiles are automagically deleted at the end of the with block.)

Solution 2:[2]

Thanks @AKX. I ended up rewriting my Python script to use Paramiko instead of pysftp and have a working solution. First I created a function called get_remote Server_key to generate an SSH key. Then I called the add_server_key(pkey) method of the Paramiko Transport object. This way I don't have to pass a file like object.

def get_remote_server_key(ip: str, port: int=22) -> paramiko.pkey.PKey:
    # Returns PKey for given server
    # :param ip: IP or Hostname
    # :param port: Port
    # :return: Returns PKey
    my_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    my_socket.settimeout(10)
    my_socket.connect((ip, port))
    my_transport = paramiko.Transport(my_socket)
    my_transport.start_client()
    ssh_key = my_transport.get_remote_server_key()
    my_transport.close()
    my_socket.close()
    return ssh_key 

def getSFTPConnection(server, port, uid, pw):
    client = paramiko.SSHClient()
    **pkey = get_remote_server_key(server,port)**
    trans = paramiko.Transport((server, port))
    **trans.add_server_key(pkey)**
    trans.connect(username=uid, password=pw)
    sftp = paramiko.SFTPClient.from_transport(trans)
    return sftp

sftp=getSFTPConnection(server, port, uid, password)

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 AKX
Solution 2 CentennialJim