40

I'm trying to get started with the Paramiko library, but the library is throwing an exception as soon as I try to connect with the following simple program:

import paramiko
ssh = paramiko.SSHClient()
ssh.connect('127.0.0.1', username='boatzart', password='mypassword')

The error I get is:

Traceback (most recent call last):
File "test.py", line 6, in <module>
ssh.connect('127.0.0.1')
File "build/bdist.macosx-10.7-intel/egg/paramiko/client.py", line 316, in connect
File "build/bdist.macosx-10.7-intel/egg/paramiko/client.py", line 85, in missing_host_key
paramiko.SSHException: Unknown server 127.0.0.1

This occurs no matter which server I try.

Martin Prikryl
  • 188,800
  • 56
  • 490
  • 992
rcv
  • 6,078
  • 9
  • 43
  • 63

6 Answers6

76

I experienced the same issue and here's the solution that worked out for me:

import paramiko

client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect('127.0.0.1', username=username, password=password)
stdin, stdout, stderr = client.exec_command('ls -l')

This is to set the policy to use when connecting to a server that doesn't have a host key in either the system or local HostKeys objects. The default policy is to reject all unknown servers (using RejectPolicy). You may substitute AutoAddPolicy or write your own policy class.

More details at paramiko api doc. Hope this helps.

After that you can save into an other keyfile file for next usage as follows.

ssh.get_host_keys().save('/some/file/path')

You can always load from a file as follows.

ssh.load_host_keys('/some/file/path')
MUY Belgium
  • 2,330
  • 4
  • 30
  • 46
user1224821
  • 885
  • 1
  • 7
  • 9
  • 8
    It works, and I do that too, but worth mentioning you are auto-trusting the target machine and technically exposed to man in the middle attacks. Just to mention the caveat! – F1Rumors Jun 15 '16 at 18:18
  • 1
    Does `AutoAddPolicy()` add the host_key to the known_hosts. So the next time this is run can I remove the `set_missing_host_key_policy()` and just use `load_system_host_keys()`? – nidHi Sep 16 '16 at 04:46
  • 1
    @nidHi Only if you tell it, where to load the keys from in advance, by calling the `SSHClient.load_host_keys`. See [my answer](http://stackoverflow.com/a/43093883/850848) – Martin Prikryl Mar 29 '17 at 12:45
34

The correct way is either:

  • Call the HostKeys.add on the instance returned by SSHClient.get_host_keys before calling the connect, passing it the trusted key.

    from base64 import decodebytes
    # ...
    
    keydata = b"""AAAAB3NzaC1yc2EAAAADAQAB..."""
    key = paramiko.RSAKey(data=decodebytes(keydata))
    client.get_host_keys().add('example.com', 'ssh-rsa', key) 
    

    Depending on the actual key type, you might need to use ECDSAKey or Ed25519Key instead of RSAKey.

    To see how to obtain the key for use in the code, see my answer to:
    Verify host key with pysftp.

    If you know a fingerprint only, see:
    Python - pysftp / paramiko - Verify host key using its fingerprint

  • Or load the already cached hostkey (e.g. by the OpenSSH command-line ssh) using client.load_system_host_keys().

  • Or you can at least cache the hostkey from the first attempt to make sure it does not change in the future.

    For that use SSHClient.load_host_keys before connect. It makes Paramiko automatically add the new host key to the file (when combined with AutoAddPolicy).

Martin Prikryl
  • 188,800
  • 56
  • 490
  • 992
  • 1
    This should be higher up! Especially the last note about caching the hostkey from the first attempt: call `client.load_host_keys(os.path.expanduser('~/.ssh/known_hosts'))` and `client.set_missing_host_key_policy(paramiko.AutoAddPolicy())`, then `connect` to the server to save the key. Subsequent connections can then load the host key with `client.load_system_host_keys()`. – karan.dodia Mar 11 '20 at 19:35
  • While this is sound and important security advice, the more important advice is probably "don't use passwords". With public key client authentication, [this doesn't matter so much](https://security.stackexchange.com/a/75753/221359). – Caesar Sep 01 '23 at 10:34
32

The exception was raised because you are missing a host key, the rather cryptic "Unknown server" is the clue - since the exception was raised from missing_host_key

Try this instead:

import paramiko

paramiko.util.log_to_file('ssh.log') # sets up logging

client = paramiko.SSHClient()
client.load_system_host_keys()
client.connect('127.0.0.1', username=username, password=password)
stdin, stdout, stderr = client.exec_command('ls -l')
Tanveer Alam
  • 5,185
  • 4
  • 22
  • 43
Burhan Khalid
  • 169,990
  • 18
  • 245
  • 284
7

I encountered this issue and wanted to post a workaround here. The issue was indeed the ssh server sending ecdsa keys, which are not supported (yet) with paramiko. On my debian Wheezy system I disabled ecdsa by commenting out a single line in /etc/ssh/sshd_config:

# HostKey /etc/ssh/ssh_host_ecdsa_key

Restarted sshd, and it was back to using RSA. There were some ecdsa keys in my known_hosts file so I just deleted it to reset, and logged in manually to recreate the keys. From there, paramiko worked perfectly as expected, with RSA host key checking.

zeugmatis
  • 81
  • 1
  • 2
6

I had this error: I can connect from the shell, but paramiko says "Unknown server workdevel114".

There were two similar entries in known_hosts:

user@host> grep workdevel114 ~/.ssh/known_hosts
workdevel114 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQC8qGbuI1BaBodi7sKWLfV8Eh+De80Th7HFLD4WiJWo57THl0Q+QcopUaU3pF....
user@host> grep I1BaBodi7sKWLfV8Eh+De80Th7HFLD4WiJWo57THl0Q+QcopUaU3pF ~/.ssh/known_hosts
workdevel114 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQC8qGbuI1BaBodi7sK...
|1|f/auQ9nY5dFbVtOdY3ocjtVO9dM=|esvazUDTT3VIcLk9DxmPI6FZt1s= ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQC8qGbuI1BaBodi7sKWLfV8Eh+De80Th7HFLD4...

The seconds entry (|1|....) seems to confuse paramiko. I guess it is related to this ticket: https://github.com/paramiko/paramiko/issues/67

I solved it by adding this line:

client.set_missing_host_key_policy(paramiko.AutoAddPolicy())

But this disables host-checking of the ssh protocol in this case: Paramiko thinks the host key is unknown, but it is known. The known Key gets ignored. I don't care because man-in-the-middle attacks are very unlikely in my environment.

paraiko-version: 1.7.7.1-1ubuntu1

guettli
  • 25,042
  • 81
  • 346
  • 663
  • I know this is an old thread but adding "set_missing_host_key_policy" solved my problem, as using "load_system_host_keys" wasn't enough – ton Oct 10 '14 at 04:31
0

I tried to incorporate part of Martin Prikryl's response into a single class using a context manager.

Or you can at least cache the hostkey from the first attempt to make sure it does not change in the future. For that use SSHClient.load_host_keys before connect. It makes Paramiko automatically add the new host key to the file (when combined with AutoAddPolicy).


import paramiko
from paramiko import client, sftp_client


class SFTP:
    sftp: sftp_client.SFTPClient
    ssh: client.SSHClient
    host: str
    user: str
    password: str

    def __init__(self, host: str, user: str, password: str):
        self.host = host
        self.user = user
        self.password = password

    def __enter__(self) -> sftp_client.SFTPClient:
        ssh = paramiko.SSHClient()
        ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        ssh.load_system_host_keys()
        ssh.connect(self.host, username=self.user, password=self.password)
        self.ssh = ssh

        sftp = ssh.open_sftp()
        self.sftp = sftp
        return sftp

    def __exit__(self, exc, _, __) -> bool:
        if exc is None:
            self.sftp.close()
            self.ssh.close()
            return True

        raise exc

Example:


with SFTP('host', 'user', 'password') as sftp:
    ...