Use Paramiko AutoAddPolicy with pysftp
Asked Answered
S

2

9

This code is not working:

def sftp_connection(self):
    import pysftp
    connection = pysftp.Connection(self.host, username=self.system_name,
                  private_key=os.path.join(HOME, '.ssh', 'id_rsa'))

    # in the next lines I try to use AutoAddPolicy
    client = connection.sftp_client()
    client.load_host_keys(os.path.expanduser('~/.ssh/known_hosts'))
    client.set_missing_host_key_policy(paramiko.client.AutoAddPolicy)
    return connection

This is the exception:

Traceback (most recent call last):
  File "/home/u/src/myapp-glo/myapp_doxis_archiv/tests/test_doxis_archiv.py", line 85, in test_beleg_to_archiv__ftpservercontext
    info_dict = beleg_to_archiv(beleg, self.archiv_belegart)
  File "/home/u/src/myapp-glo/myapp_doxis_archiv/beleg_to_archiv.py", line 28, in beleg_to_archiv
    transfer_log=send_data_via_ftp(temp_directory, archiv_belegart.doxis_archiv)
  File "/home/u/src/myapp-glo/myapp_doxis_archiv/beleg_to_archiv.py", line 71, in send_data_via_ftp
    with doxis_archiv.sftp_connection() as sftp:
  File "/home/u/src/myapp-glo/myapp_doxis_archiv/models.py", line 43, in sftp_connection
    private_key=os.path.join(HOME, '.ssh', 'id_rsa'))
  File "/home/u/local/lib/python2.7/site-packages/pysftp/__init__.py", line 132, in __init__
    self._tconnect['hostkey'] = self._cnopts.get_hostkey(host)
  File "/home/u/local/lib/python2.7/site-packages/pysftp/__init__.py", line 71, in get_hostkey
    raise SSHException("No hostkey for host %s found." % host)
SSHException: No hostkey for host localhost found.

I get the exception before I try to set the host_key_policy.

I could not find a different way to access the client instance via pysftp.

Is there a way to set AutoAddPolicy before I get the exception?

There is a related question. My question is about how to apply one of the several solutions which are provided in the old question.

Stria answered 7/12, 2018 at 8:52 Comment(0)
C
23

pysftp does not use Paramiko SSHClient class at all, it uses more low-level Transport class. So it does not have the MissingHostKeyPolicy functionality of SSHClient.

You would have to implement it on your own.

One possible implementation can be:

host = 'example.com'

# Loads .ssh/known_hosts    
cnopts = CnOpts()

hostkeys = None

if cnopts.hostkeys.lookup(host) == None:
    print("New host - will accept any host key")
    # Backup loaded .ssh/known_hosts file
    hostkeys = cnopts.hostkeys
    # And do not verify host key of the new host
    cnopts.hostkeys = None

with Connection(host, username=user, private_key=pkey, cnopts=cnopts) as sftp:
    if hostkeys != None:
        print("Connected to new host, caching its hostkey")
        hostkeys.add(
            host, sftp.remote_server_key.get_name(), sftp.remote_server_key)
        hostkeys.save(pysftp.helpers.known_hosts())

Though, due to a bug in pysftp, this still might not work satisfactory. I suggest you switch to Paramiko altogether. See pysftp vs. Paramiko.

Crimpy answered 7/12, 2018 at 12:31 Comment(1)
cnopts = pysftp.CnOpts() will fail on the first run if ~/.ssh/known_hosts file is empty.Devin
D
2

I've implemented auto_add_key in my pysftp github fork.

auto_add_key will add the key to known_hosts if auto_add_key=True
Once a key is present for a host in known_hosts this key will be checked.

Please reffer Martin Prikryl -> answer about security concerns.

Though for an absolute security, you should not retrieve the host key remotely, as you cannot be sure, if you are not being attacked already.

import pysftp as sftp

def push_file_to_server():
    s = sftp.Connection(host='138.99.99.129', username='root', password='pass', auto_add_key=True)
    local_path = "testme.txt"
    remote_path = "/home/testme.txt"

    s.put(local_path, remote_path)
    s.close()

push_file_to_server()
Dyna answered 28/8, 2019 at 11:26 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.