Getting error
paramiko.ssh_exception.SSHException: No hostkey for host target.org found.
when using pysftp
(for a connection that requires a specific port), even though I am providing the same known_hosts file that was initially used to connect to that location (following the post here). Ie. did...
[airflow@airflowetl reporting]$ sftp -oPort=15259 [email protected]
The authenticity of host '[target.org]:15259 ([205.172.2.88]:15259)' can't be established.
RSA key fingerprint is SHA256:UM6OflG0rkcYohes7qOlYoJZ4TIqVd0JQSh7HXYZQVA.
RSA key fingerprint is MD5:33:c2:30:22:57:5b:57:98:2f:11:07:4d:a3:4a:10:0f.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '[target.org]:15259,[205.172.2.88]:15259' (RSA) to the list of known hosts.
password
Enter password for my_user
Password:
Connected to target.org.
sftp> ls
csv_drop test_results
sftp> exit
and then copied the /home/me/.ssh/known_hosts
to another location
[airflow@airflowetl .ssh]$ ls -lha
total 8.0K
drwx------ 2 airflow airflows 25 Oct 19 17:31 .
drwx------. 32 airflow airflows 4.0K Oct 19 17:31 ..
-rw-r--r-- 1 airflow airflows 777 Oct 19 17:32 known_hosts
[airflow@airflowetl .ssh]$ ls -lha /home/airflow/projects/backups/reporting/configs/known_hosts
-rw-r--r-- 1 airflow airflows 777 Oct 19 17:34 /home/airflow/projects/backups/reporting/configs/known_hosts
(noting that the permissions are the name for the original and copy) that gets used like...
# connect to ftp location
assert os.path.isfile(os.path.join(PROJECT_HOME, "configs", "known_hosts"))
cnopts = pysftp.CnOpts(knownhosts=os.path.join(PROJECT_HOME, "configs", "known_hosts"))
#cnopts = pysftp.CnOpts(knownhosts="/home/airflow/.ssh/known_hosts")
HOSTNAME = "target.org"
PORT = 15259
sftp = pysftp.Connection(HOSTNAME,
port=PORT,
username=CREDS["sink"]["ftp_creds"]["username"],
password=CREDS["sink"]["ftp_creds"]["password"],
cnopts=cnopts)
print(sftp.pwd())
print(sftp.listdir())
sftp.cwd(CONF["reporting_configs"]["to"]["share_folder_path"])
print(sftp.pwd())
print(sftp.listdir())
Yet, when running the script I get the error saying it could not find the hostkey (Note that even using the original known_hosts file path throws the same error (and happens whether using hostname or the IP)). What could be causing this? Any more debugging steps I could try to get more info? Don't have much experience with this kind of thing.
Looking in the debugger while running, I see that the cnopts hostkeys entries does seem to contain the right hostkey...
<HostKeyEntry ['[target.org]:15259', '[205.172.2.88]:15259']: <paramiko.rsakey.RSAKey object at 0x7f8d752d4208>>
Note that the hostkey entry is '[target.org]:15259' (ie. it is combining the specified port), even though the name provided as the service name to the connection function is just 'target.org'
The full traceback looks like...
Traceback (most recent call last):
File "./source/local2ftp.2.py", line 52, in <module>
cnopts=cnopts)
File "/home/airflow/projects/backups/reporting/venv/lib/python3.6/site-packages/pysftp/__init__.py", line 132, in __init__
self._tconnect['hostkey'] = self._cnopts.get_hostkey(host)
File "/home/airflow/projects/backups/reporting/venv/lib/python3.6/site-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 target.org found.
Exception ignored in: <bound method Connection.__del__ of <pysftp.Connection object at 0x7f1a61df6f98>>
Traceback (most recent call last):
File "/home/airflow/projects/backups/reporting/venv/lib/python3.6/site-packages/pysftp/__init__.py", line 1013, in __del__
self.close()
File "/home/airflow/projects/backups/reporting/venv/lib/python3.6/site-packages/pysftp/__init__.py", line 784, in close
if self._sftp_live:
AttributeError: 'Connection' object has no attribute '_sftp_live'
Note that the user I used to initially connect via sftp
in the command line and am using in the pysftp
script is not the user running the script (the user I used to connect to the sftp server is a special set of credentials for connecting). I don't know if this is relevant.
TLDR: The code expects the
pystfp.Connection
hostname to match that in the hostkey file (eg.~/.ssh/known_hosts
), but if the rsa entry in the hostkey file entry was created with a connection that specified the port and thus caused the rsa entry in known_hosts to be formatted in a way thatpysftp
could not understand / handle,like...
The rsa entry that gets created looks like...
so when you use this hostkey file for the
knownhosts
in...the code ends up checking the hostkey file for an entry that looks like
(what you entered as the
hostname
) but only finds(the entry in the hostkey / known_hosts file formatted for the specific port you connected on) so throws an error.
Note also that you can't just use "[target.org]:15259" as the
hostname
for thepysftp.Connection()
function either just to get it to match when thepysftp
code does this internal check because it will say that it does not recognize the service name since (apparently) that's not a valid servicename representation (ie. it won't just know to separate that string into thehostname
andport
components).What I had to do was...
Specifically in the code, the
pysftp.Connection()
function...Paraminko
module to try to find the hostkey entry from theknownhosts
file given in thecnopt
arghostname
that you entered as thepysftp.Connection
arg (which, if you connected to using a specific port, created an rsa entry that when taken as a literal is not formatted the way you likely are passing in thehostname
arg and is not even a valid host name), thus confusing the matching logic and causing it to not find any matchespysftp
code