4

Background

To SFTP across to another server I use the following command in the UNIX command line:

sftp -i /some_dir/another_dir/key -oPort=12345 user@12.123.456.789

What I want to achieve

I want to convert this to command to be used with PySFTP.

What I have tried

import pysftp
cnopts = pysftp.CnOpts()
cnopts.hostkeys = None

# source: https://pysftp.readthedocs.io/en/release_0.2.7/pysftp.html
srv = pysftp.Connection("user@12.123.456.789", port="12345",  
                         private_key_pass="/some_dir/another_dir/key")

Errors encountered

File "./aws_sql_dumper.py", line 14, in <module>
    srv = pysftp.Connection("user@12.123.456.789", port="12345",  private_key_pass="/some_dir/another_dir/key")
  File "/usr/local/lib/python3.4/dist-packages/pysftp/__init__.py", line 132, in __init__
    self._tconnect['hostkey'] = self._cnopts.get_hostkey(host)
  File "/usr/local/lib/python3.4/dist-packages/pysftp/__init__.py", line 71, in get_hostkey
    raise SSHException("No hostkey for host %s found." % host)
paramiko.ssh_exception.SSHException: No hostkey for host user@12.123.456.789 found.
Exception ignored in: <bound method Connection.__del__ of <pysftp.Connection object at 0x7f6067c7ea20>>
Traceback (most recent call last):
  File "/usr/local/lib/python3.4/dist-packages/pysftp/__init__.py", line 1013, in __del__
    self.close()
  File "/usr/local/lib/python3.4/dist-packages/pysftp/__init__.py", line 784, in close
    if self._sftp_live:
AttributeError: 'Connection' object has no attribute '_sftp_live'

Research done

I've read up on the following:

Question

I think I am doing something fundamental wrong. How can I adopt the SFTP command used in UNIX command line to be accepted/interpretted by pysftp?


Changes

I changed a few things around

import pysftp
cnopts = pysftp.CnOpts()
cnopts.hostkeys.load('/home/some_dir/.ssh/known_hosts')

# source: https://pysftp.readthedocs.io/en/release_0.2.7/pysftp.html
srv = pysftp.Connection("user@12.123.456.789", port="12345",  
                         private_key="/some_dir/another_dir/key", cnopts=cnopts)

Output after change

Traceback (most recent call last):
  File "./aws_sql_dumper.py", line 17, in <module>
    srv = pysftp.Connection("user@12.123.456.789", port="12345",  private_key="/some_dir/another_dir/key", cnopts=cnopts)
  File "/usr/local/lib/python3.4/dist-packages/pysftp/__init__.py", line 132, in __init__
    self._tconnect['hostkey'] = self._cnopts.get_hostkey(host)
  File "/usr/local/lib/python3.4/dist-packages/pysftp/__init__.py", line 71, in get_hostkey
    raise SSHException("No hostkey for host %s found." % host)
paramiko.ssh_exception.SSHException: No hostkey for host user@12.123.456.789" found.
Exception ignored in: <bound method Connection.__del__ of <pysftp.Connection object at 0x7f8120dc6438>>
Traceback (most recent call last):
  File "/usr/local/lib/python3.4/dist-packages/pysftp/__init__.py", line 1013, in __del__
    self.close()
  File "/usr/local/lib/python3.4/dist-packages/pysftp/__init__.py", line 784, in close
    if self._sftp_live:
AttributeError: 'Connection' object has no attribute '_sftp_live
3kstc
  • 1,871
  • 3
  • 29
  • 53

3 Answers3

0

You never use the cnopts variable. You need to pass it to cnopts parameter of Connection class.

Once you resolve this, you will have a problem with the private key, as you pass it to private_key_pass parameter ("private key passphrase") instead of to private_key.

srv = pysftp.Connection("user@12.123.456.789", port="12345",  
                         private_key="/some_dir/another_dir/key", cnopts=cnopts)

Though you should not do cnopts.hostkeys = None, as you lose security by doing so. The right solution is to verify the host key. Check my answer to the same question for correct solutions.

Martin Prikryl
  • 188,800
  • 56
  • 490
  • 992
  • I'm still having some difficulty (I've updated the question) I read your answer and did so, but still to no avail. What else should I be doing? Or is there an alternative simpler library you could recommend? – 3kstc Mar 15 '19 at 00:39
  • So what did you do exactly? How did you update the `known_hosts`? What does the `known_hosts` contains? Show us. – Martin Prikryl Mar 15 '19 at 05:57
  • Is there a way I can bypass `known_hosts` (I've become so confused with the known hosts - the more I read the more confused I've become) and just use the key (`/some_dir/another_dir/key`) and the user alongside the IP address `user` [`@`] `12.123.456.789` – 3kstc Mar 18 '19 at 01:21
  • @3kstc What is `/some_dir/another_dir/key`? Actually your are probably confused :) As I assume that `key` is your key for authentication, what has nothing to do with host keys/known hosts. Read my article [Understanding SSH key pairs](https://winscp.net/eng/docs/ssh_keys) - So if you actually put your *authentication key* to `known_hosts`, then it's clear why it does not match the *host key*. – Martin Prikryl Mar 18 '19 at 06:22
0

After much trial and error, converting the following SFTP command put into the terminal:

sftp -i /some_dir/another_dir/key -oPort=12345 user@12.123.456.789

can be translated* into:

paramiko.SSHClient().connect(hostname='12.123.456.789', username='user', port=12345,
                             key_filename='/some_dir/another_dir/key')

The whole condensed code is:

#!/usr/bin/python3

import paramiko

try:
    client = paramiko.SSHClient()
    client.load_system_host_keys()
    client.set_missing_host_key_policy(paramiko.WarningPolicy)
    client.connect(hostname='12.123.456.789', username='user', port=12345, 
                   key_filename='/some_dir/another_dir/key')

    # -------------------------- [ just for testing ] --------------------------
    stdin, stdout, stderr = client.exec_command('ls -la')   # THIS IS FOR TESTING
    print(stdout.read())                                    # AND PRINTING OUT

finally:
    client.close()
3kstc
  • 1,871
  • 3
  • 29
  • 53
0

I was facing the similar issue (Host key issue) and found a good solution. In am trying to connect from a windows box(source) to Linux box(Destination). In my windows machine we have already installed CYGWIN where i logged in and did the below

1. Logged in using my ID
2. Ran the command ssh-keygen -b 2048 -t rsa
3. under my cygwin home dir (~/.ssh) folder was created with pub and private key.
4. Physically this folder would be in c:\cygwin\home\/.ssh
5. Copy this folder and paste in the c:\user\\.ssh (windows home dir)
6. also open the pub key in the folder and paste that in the destination server ~\.ssh\authroized_keys. This is for password less login.

After this pysftp was able to connect without password less. Host key would be detected without any issues

-Prasanna.K
Prasanna K
  • 23
  • 4