fix(ssh): verify the host key netOrk expects, report the one seen (NetOrk/netork#1167)
CI / test (3.10) (push) Successful in 27s
CI / test (3.11) (push) Successful in 30s
CI / test (3.12) (push) Successful in 37s
CI / test (3.10) (pull_request) Successful in 32s
CI / test (3.11) (pull_request) Successful in 34s
CI / test (3.12) (pull_request) Successful in 29s
CI / test (3.10) (push) Successful in 27s
CI / test (3.11) (push) Successful in 30s
CI / test (3.12) (push) Successful in 37s
CI / test (3.10) (pull_request) Successful in 32s
CI / test (3.11) (pull_request) Successful in 34s
CI / test (3.12) (pull_request) Successful in 29s
The driver accepted any SSH host key. It now verifies through napalm-device-types' HostKeyCheck (>= 4.19.0): with a known key in optional_args["ssh_host_keys"] any other key is refused before login, and every key seen is reported to optional_args["ssh_host_key_observer"]. Without either argument it connects as before (first use).
This commit is contained in:
1 parent
68dd818da6
commit
6179607137
4 files changed
+122
-6
No files matched your search
+8
-4
@@ -20,6 +20,7 @@ from napalm.base.exceptions import ConnectionClosedException, ConnectionExceptio
|
||||
from napalm_device_types import EnsurePackageMixin, OSDriver, SnmpAgentMixin
|
||||
from napalm_device_types.models import FixStepOutcomeDict, SnmpAgentSettingsDict
|
||||
from napalm_device_types.host_status import HostStatusMixin
|
||||
from napalm_device_types.ssh_host_keys import HostKeyCheck, SshHostKeyMismatch
|
||||
from napalm_device_types.channel import (
|
||||
ByteStream,
|
||||
CommandResult,
|
||||
@@ -124,6 +125,8 @@ class BsdDriver(SnmpAgentMixin, EnsurePackageMixin, HostStatusMixin, OSDriver):
|
||||
self._sudo_password: Optional[str] = args.get("sudo_password")
|
||||
self._allow_agent: bool = bool(args.get("allow_agent", False))
|
||||
self._look_for_keys: bool = bool(args.get("look_for_keys", False))
|
||||
# The host key to expect, and where the one seen is reported (netork#1167).
|
||||
self._host_key = HostKeyCheck(args, hostname, self.port)
|
||||
self._client: Optional[paramiko.SSHClient] = None
|
||||
self._root: Optional[bool] = None
|
||||
|
||||
@@ -131,11 +134,9 @@ class BsdDriver(SnmpAgentMixin, EnsurePackageMixin, HostStatusMixin, OSDriver):
|
||||
|
||||
def open(self) -> None:
|
||||
client = paramiko.SSHClient()
|
||||
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||
try:
|
||||
client.connect(
|
||||
self.hostname,
|
||||
port=self.port,
|
||||
self._host_key.connect(
|
||||
client,
|
||||
username=self.username,
|
||||
password=self.password or None,
|
||||
key_filename=self._key_file,
|
||||
@@ -143,6 +144,9 @@ class BsdDriver(SnmpAgentMixin, EnsurePackageMixin, HostStatusMixin, OSDriver):
|
||||
look_for_keys=self._look_for_keys,
|
||||
timeout=self.timeout,
|
||||
)
|
||||
except SshHostKeyMismatch:
|
||||
client.close() # refused before any login; nothing was sent
|
||||
raise
|
||||
except (paramiko.SSHException, socket.error) as exc:
|
||||
client.close()
|
||||
raise ConnectionException(f"SSH to {self.hostname} failed: {exc}") from exc
|
||||
|
||||
Reference in new issue
Block a user