]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
mgr/dashboard: Disable TLS 1.0 and 1.1 38286/head
authorVolker Theile <vtheile@suse.com>
Wed, 25 Nov 2020 16:57:13 +0000 (17:57 +0100)
committerVolker Theile <vtheile@suse.com>
Thu, 26 Nov 2020 14:40:15 +0000 (15:40 +0100)
Disable these TLS versions because of security issues.

Fixes: https://tracker.ceph.com/issues/48360
Signed-off-by: Volker Theile <vtheile@suse.com>
qa/tasks/mgr/test_dashboard.py
src/pybind/mgr/dashboard/module.py

index 5e9b3829b2a6e7b8ee6489663601dc2e70726321..9f904a6e0c0e0d081ab55d1fbba596fd0a55ed65 100644 (file)
@@ -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)
index 238b99f226d610869274ed8280d7bd69e8004146..e3f69664764447eb4167338ffaef3dc3528dfca3 100644 (file)
@@ -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 <ip>"'
                 .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