From 5cf222b6d2a5cdc7ff23357b12878d34a4e68801 Mon Sep 17 00:00:00 2001 From: Volker Theile Date: Wed, 25 Nov 2020 17:57:13 +0100 Subject: [PATCH] mgr/dashboard: Disable TLS 1.0 and 1.1 Disable these TLS versions because of security issues. Fixes: https://tracker.ceph.com/issues/48360 Signed-off-by: Volker Theile --- qa/tasks/mgr/test_dashboard.py | 33 +++++++++++++++++++++++++++++- src/pybind/mgr/dashboard/module.py | 21 ++++++++++++++----- 2 files changed, 48 insertions(+), 6 deletions(-) diff --git a/qa/tasks/mgr/test_dashboard.py b/qa/tasks/mgr/test_dashboard.py index 5e9b3829b2a6e..9f904a6e0c0e0 100644 --- a/qa/tasks/mgr/test_dashboard.py +++ b/qa/tasks/mgr/test_dashboard.py @@ -1,9 +1,11 @@ import logging +import ssl + import requests +from requests.adapters import HTTPAdapter from .mgr_test_case import MgrTestCase - log = logging.getLogger(__name__) @@ -122,3 +124,32 @@ class TestDashboard(MgrTestCase): )) self.assertListEqual(failures, []) + + def test_tls(self): + class CustomHTTPAdapter(HTTPAdapter): + def __init__(self, ssl_version): + self.ssl_version = ssl_version + super().__init__() + + def init_poolmanager(self, *args, **kwargs): + kwargs['ssl_version'] = self.ssl_version + return super().init_poolmanager(*args, **kwargs) + + uri = self._get_uri("dashboard") + + # TLSv1 + with self.assertRaises(requests.exceptions.SSLError): + session = requests.Session() + session.mount(uri, CustomHTTPAdapter(ssl.PROTOCOL_TLSv1)) + session.get(uri, allow_redirects=False, verify=False) + + # TLSv1.1 + with self.assertRaises(requests.exceptions.SSLError): + session = requests.Session() + session.mount(uri, CustomHTTPAdapter(ssl.PROTOCOL_TLSv1_1)) + session.get(uri, allow_redirects=False, verify=False) + + session = requests.Session() + session.mount(uri, CustomHTTPAdapter(ssl.PROTOCOL_TLS)) + r = session.get(uri, allow_redirects=False, verify=False) + self.assertEqual(r.status_code, 200) diff --git a/src/pybind/mgr/dashboard/module.py b/src/pybind/mgr/dashboard/module.py index 238b99f226d61..e3f6966476444 100644 --- a/src/pybind/mgr/dashboard/module.py +++ b/src/pybind/mgr/dashboard/module.py @@ -9,6 +9,8 @@ import errno import logging import os import socket +import ssl +import sys import tempfile import threading import time @@ -93,8 +95,8 @@ class CherryPyConfig(object): """ server_addr = self.get_localized_module_option( # type: ignore 'server_addr', get_default_addr()) - ssl = self.get_localized_module_option('ssl', True) # type: ignore - if not ssl: + use_ssl = self.get_localized_module_option('ssl', True) # type: ignore + if not use_ssl: server_port = self.get_localized_module_option('server_port', 8080) # type: ignore else: server_port = self.get_localized_module_option('ssl_server_port', 8443) # type: ignore @@ -104,7 +106,7 @@ class CherryPyConfig(object): 'no server_addr configured; ' 'try "ceph config set mgr mgr/{}/{}/server_addr "' .format(self.module_name, self.get_mgr_id())) # type: ignore - self.log.info('server: ssl=%s host=%s port=%d', 'yes' if ssl else 'no', # type: ignore + self.log.info('server: ssl=%s host=%s port=%d', 'yes' if use_ssl else 'no', # type: ignore server_addr, server_port) # Initialize custom handlers. @@ -141,7 +143,7 @@ class CherryPyConfig(object): 'tools.plugin_hooks_filter_request.on': True, } - if ssl: + if use_ssl: # SSL initialization cert = self.get_store("crt") # type: ignore if cert is not None: @@ -163,9 +165,18 @@ class CherryPyConfig(object): verify_tls_files(cert_fname, pkey_fname) + # Create custom SSL context to disable TLS 1.0 and 1.1. + context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH) + context.load_cert_chain(cert_fname, pkey_fname) + if sys.version_info >= (3, 7): + context.minimum_version = ssl.TLSVersion.TLSv1_2 + else: + context.options |= ssl.OP_NO_TLSv1 | ssl.OP_NO_TLSv1_1 + config['server.ssl_module'] = 'builtin' config['server.ssl_certificate'] = cert_fname config['server.ssl_private_key'] = pkey_fname + config['server.ssl_context'] = context self.update_cherrypy_config(config) @@ -173,7 +184,7 @@ class CherryPyConfig(object): 'url_prefix', default='')) uri = "{0}://{1}:{2}{3}/".format( - 'https' if ssl else 'http', + 'https' if use_ssl else 'http', socket.getfqdn(server_addr if server_addr != '::' else ''), server_port, self.url_prefix -- 2.47.3