From 661a9abbd21310ef7803ea0286fcb818cb93dfa9 Mon Sep 17 00:00:00 2001 From: Amador Pahim Date: Tue, 19 Apr 2016 10:20:38 -0300 Subject: [PATCH] avocado.core.remoter option to reject remote unknown hosts When Avocado runs tests on remote machines it always accepts the host SSH key fingerprint. This could allow credentials to be stolen if the remote host name or address is spoofed. This patch adds to Avocado the configuration option to enable/disable the reject_unknown_hosts option, so user can choose between safe or flexible. Notice there is an issue in Paramiko where it does not recognizes ecdsa keys in known_hosts file. So for reject_unknown_hosts to work, we currently have to accept the remote host key fingerprint in RSA format. To do so, the SSH command shouled be like below: $ ssh -oHostKeyAlgorithms='ssh-rsa' Reference: https://trello.com/c/oqyAvZBq Signed-off-by: Amador Pahim --- avocado/core/remoter.py | 13 +++++++- etc/avocado/avocado.conf | 13 ++++++++ selftests/functional/test_thirdparty_bugs.py | 32 ++++++++++++++++++++ 3 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 selftests/functional/test_thirdparty_bugs.py diff --git a/avocado/core/remoter.py b/avocado/core/remoter.py index 432085b2..ecd21c82 100644 --- a/avocado/core/remoter.py +++ b/avocado/core/remoter.py @@ -20,6 +20,7 @@ import getpass import logging import time +from .settings import settings from ..utils import process LOG = logging.getLogger('avocado.test') @@ -70,6 +71,14 @@ class Remote(object): self.password = password self.port = port self.quiet = quiet + reject_unknown_hosts = settings.get_value('remoter.behavior', + 'reject_unknown_hosts', + key_type=bool, + default=True) + disable_known_hosts = settings.get_value('remoter.behavior', + 'disable_known_hosts', + key_type=bool, + default=False) self._setup_environment(host_string=hostname, user=username, password=password, @@ -78,7 +87,9 @@ class Remote(object): connection_attempts=attempts, linewise=True, abort_on_prompts=True, - abort_exception=ConnectionError) + abort_exception=ConnectionError, + reject_unknown_hosts=reject_unknown_hosts, + disable_known_hosts=disable_known_hosts) @staticmethod def _setup_environment(**kwargs): diff --git a/etc/avocado/avocado.conf b/etc/avocado/avocado.conf index f3c2f131..af26b5dc 100644 --- a/etc/avocado/avocado.conf +++ b/etc/avocado/avocado.conf @@ -38,6 +38,19 @@ utf8 = # Keep job temporary files after jobs (useful for avocado debugging) keep_tmp_files = False +[remoter.behavior] +# __Insecure__, reject unknown SSH host keys. +# 'False' will leave you wide open to man-in-the-middle attacks! +# 'True' will only work with RSA keys (due to a bug in Paramiko). +# If using 'True', accept the remote host key fingerprint by using: +# $ ssh -oHostKeyAlgorithms='ssh-rsa' +reject_unknown_hosts = False +# __Insecure__, SSH layer to skip loading the user’s known-hosts +# file. Useful for avoiding exceptions in situations where a +# 'known host' changing its host key is actually valid (e.g. cloud +# servers such as EC2.) +disable_known_hosts = False + [job.output] # Base log level for --show-job-log. # Allowed levels: debug, info, warning, error, critical diff --git a/selftests/functional/test_thirdparty_bugs.py b/selftests/functional/test_thirdparty_bugs.py new file mode 100644 index 00000000..eb08b2f8 --- /dev/null +++ b/selftests/functional/test_thirdparty_bugs.py @@ -0,0 +1,32 @@ +import json +import sys +from avocado.utils import download + +if sys.version_info[:2] == (2, 6): + import unittest2 as unittest +else: + import unittest + + +class TestThirdPartyBugs(unittest.TestCase): + """ + Class created to verify third-party known issues + """ + + def test_paramiko_ecsda_bug(self): + # https://github.com/paramiko/paramiko/issues/243 + # Problems with using ECDSA known_hosts keys when negotiation also + # accepts RSA or DSS keys + try: + issue_url = 'https://api.github.com/repos/paramiko/paramiko/issues/243' + issue = json.load(download.url_open(issue_url)) + self.assertEqual(issue['state'], 'open', 'The issue %s is not open ' + 'anymore. Please double check and, if already fixed, ' + 'change the avocado.conf option ' + '"reject_unknown_hosts" defaults to True.' % + 'https://github.com/paramiko/paramiko/issues/243') + except download.urllib2.URLError as details: + raise unittest.SkipTest(details) + +if __name__ == '__main__': + unittest.main() -- GitLab