From 13c856a5c393d6c510d29628c27c6987f9e6d867 Mon Sep 17 00:00:00 2001 From: Malte Swart Date: Mon, 10 Feb 2025 14:33:09 +0100 Subject: [PATCH] patch: Add option to disable ssl.VERIFY_X509_STRICT Since Python 3.13, ssl.VERIFY_X509_STRICT is enabled by default. Old Kubernetes clusters might have certificates that do not (yet) comply with that. Add a (custom) configuration option to disable this flag. --- kubernetes_asyncio/client/configuration.py | 8 ++++++++ kubernetes_asyncio/client/rest.py | 2 ++ kubernetes_asyncio/client/test_rest.py | 8 ++++++++ ...disable_ssl_strict_verification_patch.diff | 19 +++++++++++++++++++ ...disable_ssl_strict_verification_patch.diff | 13 +++++++++++++ scripts/update-client.sh | 3 +++ 6 files changed, 53 insertions(+) create mode 100644 scripts/client_configuration_disable_ssl_strict_verification_patch.diff create mode 100644 scripts/rest_client_disable_ssl_strict_verification_patch.diff diff --git a/kubernetes_asyncio/client/configuration.py b/kubernetes_asyncio/client/configuration.py index d0dd9f9e..facc9173 100644 --- a/kubernetes_asyncio/client/configuration.py +++ b/kubernetes_asyncio/client/configuration.py @@ -177,6 +177,14 @@ def __init__(self, host=None, Set this to false to skip verifying SSL certificate when calling API from https server. """ + self.disable_strict_ssl_verification = False + """Set to true, to accept certificates violate X509 strict certificate + verification requirements, like missing the following extensions: + - X509v3 Subject Key Identifier + - X509v3 Authority Key Identifier + - X509v3 Subject Alternative Name + (It is implemented by removing ssl.VERIFY_X509_STRICT from SSLContext.verify_flags) + """ self.ssl_ca_cert = ssl_ca_cert """Set this to customize the certificate file to verify the peer. """ diff --git a/kubernetes_asyncio/client/rest.py b/kubernetes_asyncio/client/rest.py index eca41107..ee30e26a 100644 --- a/kubernetes_asyncio/client/rest.py +++ b/kubernetes_asyncio/client/rest.py @@ -61,6 +61,8 @@ def __init__(self, configuration, pools_size=4, maxsize=None): if not configuration.verify_ssl: ssl_context.check_hostname = False ssl_context.verify_mode = ssl.CERT_NONE + if configuration.disable_strict_ssl_verification: + ssl_context.verify_flags &= ~ssl.VERIFY_X509_STRICT connector = aiohttp.TCPConnector( limit=maxsize, diff --git a/kubernetes_asyncio/client/test_rest.py b/kubernetes_asyncio/client/test_rest.py index f379637f..b40e8248 100644 --- a/kubernetes_asyncio/client/test_rest.py +++ b/kubernetes_asyncio/client/test_rest.py @@ -1,4 +1,5 @@ import asyncio +import ssl import unittest from unittest.mock import AsyncMock import aiohttp @@ -30,3 +31,10 @@ async def test_rest_request_timeout(self): timeout=expected_timeout_arg, headers={"Content-Type": "application/json"} ) + + async def test_disable_ssl_verification(self): + configuration = Configuration() + configuration.disable_strict_ssl_verification = True + rest_api = RESTClientObject(configuration=configuration) + ssl_context = rest_api.pool_manager._connector._ssl + self.assertEqual(ssl_context.verify_flags & ssl.VERIFY_X509_STRICT, 0) diff --git a/scripts/client_configuration_disable_ssl_strict_verification_patch.diff b/scripts/client_configuration_disable_ssl_strict_verification_patch.diff new file mode 100644 index 00000000..203673d7 --- /dev/null +++ b/scripts/client_configuration_disable_ssl_strict_verification_patch.diff @@ -0,0 +1,19 @@ +diff --git a/kubernetes_asyncio/client/configuration.py b/kubernetes_asyncio/client/configuration.py +index d0dd9f9e..facc9173 100644 +--- a/kubernetes_asyncio/client/configuration.py ++++ b/kubernetes_asyncio/client/configuration.py +@@ -177,6 +177,14 @@ conf = client.Configuration( + Set this to false to skip verifying SSL certificate when calling API + from https server. + """ ++ self.disable_strict_ssl_verification = False ++ """Set to true, to accept certificates violate X509 strict certificate ++ verification requirements, like missing the following extensions: ++ - X509v3 Subject Key Identifier ++ - X509v3 Authority Key Identifier ++ - X509v3 Subject Alternative Name ++ (It is implemented by removing ssl.VERIFY_X509_STRICT from SSLContext.verify_flags) ++ """ + self.ssl_ca_cert = ssl_ca_cert + """Set this to customize the certificate file to verify the peer. + """ diff --git a/scripts/rest_client_disable_ssl_strict_verification_patch.diff b/scripts/rest_client_disable_ssl_strict_verification_patch.diff new file mode 100644 index 00000000..95d8182e --- /dev/null +++ b/scripts/rest_client_disable_ssl_strict_verification_patch.diff @@ -0,0 +1,13 @@ +diff --git a/kubernetes_asyncio/client/rest.py b/kubernetes_asyncio/client/rest.py +index eca41107..ee30e26a 100644 +--- a/kubernetes_asyncio/client/rest.py ++++ b/kubernetes_asyncio/client/rest.py +@@ -61,6 +61,8 @@ class RESTClientObject(object): + if not configuration.verify_ssl: + ssl_context.check_hostname = False + ssl_context.verify_mode = ssl.CERT_NONE ++ if configuration.disable_strict_ssl_verification: ++ ssl_context.verify_flags &= ~ssl.VERIFY_X509_STRICT + + connector = aiohttp.TCPConnector( + limit=maxsize, diff --git a/scripts/update-client.sh b/scripts/update-client.sh index a9e68d48..1db50ed7 100755 --- a/scripts/update-client.sh +++ b/scripts/update-client.sh @@ -73,6 +73,9 @@ patch "${CLIENT_ROOT}/client/rest.py" "${SCRIPT_ROOT}/rest_client_patch_read_buf echo ">>> fix generated rest client and configuration to support customer server hostname TLS verification..." patch "${CLIENT_ROOT}/client/rest.py" "${SCRIPT_ROOT}/rest_client_server_hostname_patch.diff" patch "${CLIENT_ROOT}/client/configuration.py" "${SCRIPT_ROOT}/client_configuration_tls_server_name_patch.diff" +echo ">>> fix generated rest client and configuration to support disabling strict TLS verification..." +patch "${CLIENT_ROOT}/client/rest.py" "${SCRIPT_ROOT}/rest_client_disable_ssl_strict_verification_patch.diff" +patch "${CLIENT_ROOT}/client/configuration.py" "${SCRIPT_ROOT}/client_configuration_disable_ssl_strict_verification_patch.diff" echo ">>> fix generated rest client by handling timeout correctly..." patch -R "${CLIENT_ROOT}/client/rest.py" "${SCRIPT_ROOT}/rest_client_timeout.diff"