From 89f185b1972db25c8af84c7ca50c5ffc2af65613 Mon Sep 17 00:00:00 2001 From: Jack Hodgkiss Date: Fri, 31 Jan 2025 10:55:02 +0000 Subject: [PATCH 1/3] certs: add subject key identifier extension Add the subject key identifier extension to the certificate generated by Magnum. Which should permit Kubernetes clusters to have certificates that include authority key identifier extension which appears to be a requirement in Python 3.13 and newer. Closes-Bug: #2097094 Change-Id: I13bbb97c8b17fbba2f5f1acfac9d597f12925818 --- magnum/common/x509/operations.py | 6 ++++++ magnum/tests/unit/common/x509/test_sign.py | 20 +++++++++++++++++++ ...ubject-key-identifer-ae5c6ebe86749239.yaml | 7 +++++++ 3 files changed, 33 insertions(+) create mode 100644 releasenotes/notes/add-subject-key-identifer-ae5c6ebe86749239.yaml diff --git a/magnum/common/x509/operations.py b/magnum/common/x509/operations.py index 7d8c5a8ebe..8e2c59a5f8 100644 --- a/magnum/common/x509/operations.py +++ b/magnum/common/x509/operations.py @@ -223,6 +223,12 @@ def sign(csr, issuer_name, ca_key, ca_key_password=None, builder = builder.add_extension(extention.value, critical=extention.critical) + subject_key_identifier = x509.SubjectKeyIdentifier.from_public_key( + csr.public_key()) + builder = builder.add_extension( + subject_key_identifier, critical=False + ) + certificate = builder.sign( private_key=ca_key, algorithm=hashes.SHA256(), ).public_bytes(serialization.Encoding.PEM).strip() diff --git a/magnum/tests/unit/common/x509/test_sign.py b/magnum/tests/unit/common/x509/test_sign.py index 42083ebfe0..e52a513bf7 100644 --- a/magnum/tests/unit/common/x509/test_sign.py +++ b/magnum/tests/unit/common/x509/test_sign.py @@ -233,6 +233,26 @@ def test_sign_empty_chars(self, mock_load_pem): self.assertEqual(certificate, certificate.strip()) + # If a subject key identifier is given in the CSR, ensure it is added + @mock.patch('cryptography.x509.load_pem_x509_csr') + def test_sign_subject_key_identifier(self, mock_load_pem): + ca_key = self._generate_private_key() + private_key = self._generate_private_key() + csr_obj = self._build_csr(private_key) + csr = csr_obj.public_bytes(serialization.Encoding.PEM) + csr = csr.decode('utf-8') + + mock_load_pem.return_value = csr_obj + certificate = operations.sign(csr, self.issuer_name, + ca_key, skip_validation=True) + + # Ensure the Subject Key Identifier extension is present + cert = c_x509.load_pem_x509_certificate(certificate) + ext_ski = [ext for ext in cert.extensions + if cert.extensions[0].oid == + c_x509.oid.ExtensionOID.SUBJECT_KEY_IDENTIFIER] + self.assertEqual(len(ext_ski), 1) + def test_sign_with_invalid_csr(self): ca_key = self._generate_private_key() csr = 'test' diff --git a/releasenotes/notes/add-subject-key-identifer-ae5c6ebe86749239.yaml b/releasenotes/notes/add-subject-key-identifer-ae5c6ebe86749239.yaml new file mode 100644 index 0000000000..570aa7423a --- /dev/null +++ b/releasenotes/notes/add-subject-key-identifer-ae5c6ebe86749239.yaml @@ -0,0 +1,7 @@ +--- +features: + - | + Add subject key identifier extension to x509 operations + signing function. Allows for magnum Kubernetes clusters + to generate certificates with authority key + identifier extension. From 3d7c57cbdc0f84c1c3bbb9b7a7d2ec054a2e8a79 Mon Sep 17 00:00:00 2001 From: Herby Hertilien Date: Thu, 3 Apr 2025 14:42:39 -0400 Subject: [PATCH 2/3] Add unit tests to improve code coverage Better coverage for HTTPNotAcceptableAPIVersion class. Controller._check_version is needed in some new tests, must be mocked in other tests. Enable the mock when needed. Co-Authored-By: Jayson Flores Change-Id: I723d8e3e4bddb4fa8e193f3f442376b9765d9c1b --- magnum/tests/unit/api/base.py | 7 ++++--- magnum/tests/unit/api/controllers/test_root.py | 3 +++ .../unit/api/controllers/v1/test_nodegroup.py | 18 ++++++++++++++++++ 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/magnum/tests/unit/api/base.py b/magnum/tests/unit/api/base.py index 233556dfd4..6edd895dfa 100644 --- a/magnum/tests/unit/api/base.py +++ b/magnum/tests/unit/api/base.py @@ -67,9 +67,10 @@ def reset_pecan(): self.addCleanup(reset_pecan) - p = mock.patch('magnum.api.controllers.v1.Controller._check_version') - self._check_version = p.start() - self.addCleanup(p.stop) + # Controller._check_version is needed in some tests, + # must be mocked in others. Enable the mock when needed. + self.patch_check_version = mock.patch( + 'magnum.api.controllers.v1.Controller._check_version') def _verify_attrs(self, attrs, response, positive=True): if positive is True: diff --git a/magnum/tests/unit/api/controllers/test_root.py b/magnum/tests/unit/api/controllers/test_root.py index 4c58f426de..97adeead73 100644 --- a/magnum/tests/unit/api/controllers/test_root.py +++ b/magnum/tests/unit/api/controllers/test_root.py @@ -222,9 +222,12 @@ def test_healthcheck_disable_file(self): class TestV1Routing(api_base.FunctionalTest): def test_route_checks_version(self): + # Temporarily instantiate mock for Controller._check_version + self._check_version = self.patch_check_version.start() self.get_json('/') self._check_version.assert_called_once_with(mock.ANY, mock.ANY) + self.patch_check_version.stop() class TestCheckVersions(test_base.TestCase): diff --git a/magnum/tests/unit/api/controllers/v1/test_nodegroup.py b/magnum/tests/unit/api/controllers/v1/test_nodegroup.py index 5e61bc16a6..a2b757c974 100644 --- a/magnum/tests/unit/api/controllers/v1/test_nodegroup.py +++ b/magnum/tests/unit/api/controllers/v1/test_nodegroup.py @@ -253,6 +253,24 @@ def test_get_all_wrong_microversion(self): response = self.get_json(url, headers=headers, expect_errors=True) self.assertEqual(406, response.status_code) + def test_get_all_api_minor_version_above_range(self): + headers = {"Openstack-Api-Version": "container-infra 1.999"} + url = '/clusters/%s/nodegroups/' % (self.cluster.uuid) + response = self.get_json(url, headers=headers, expect_errors=True) + self.assertEqual(406, response.status_code) + self.assertIsNotNone(response.json['errors']) + self.assertEqual('magnum.microversion-unsupported', + response.json['errors'][0]['code']) + + def test_get_all_api_major_version_above_range(self): + headers = {"Openstack-Api-Version": "container-infra 2.11"} + url = '/clusters/%s/nodegroups/' % (self.cluster.uuid) + response = self.get_json(url, headers=headers, expect_errors=True) + self.assertEqual(406, response.status_code) + self.assertIsNotNone(response.json['errors']) + self.assertEqual('magnum.microversion-unsupported', + response.json['errors'][0]['code']) + class TestPost(NodeGroupControllerTest): def setUp(self): From cbeb6a89aa4cc06548fe15b36a041200fd49821c Mon Sep 17 00:00:00 2001 From: Dmitriy Rabotyagov Date: Thu, 2 May 2024 16:08:22 +0200 Subject: [PATCH 3/3] Add insecure_registry parameter to templates API At the moment `insecure_registry` is an undocumented property that is accepted and respected for quite a while. Change-Id: Ibe5500bb46210c3f38ccdd2b81f9642597b873ea --- api-ref/source/clustertemplates.inc | 1 + api-ref/source/samples/clustertemplate-create-req.json | 1 + 2 files changed, 2 insertions(+) diff --git a/api-ref/source/clustertemplates.inc b/api-ref/source/clustertemplates.inc index 0c33a08d28..8353caa866 100644 --- a/api-ref/source/clustertemplates.inc +++ b/api-ref/source/clustertemplates.inc @@ -47,6 +47,7 @@ Request - image_id: image_id - volume_driver: volume_driver - registry_enabled: registry_enabled + - insecure_registry: insecure_registry - docker_storage_driver: docker_storage_driver - name: name - network_driver: network_driver diff --git a/api-ref/source/samples/clustertemplate-create-req.json b/api-ref/source/samples/clustertemplate-create-req.json index 38bb40c584..4e1f4f5b7a 100644 --- a/api-ref/source/samples/clustertemplate-create-req.json +++ b/api-ref/source/samples/clustertemplate-create-req.json @@ -16,6 +16,7 @@ "image_id":"fedora-atomic-latest", "volume_driver":"cinder", "registry_enabled":false, + "insecure_registry":null, "docker_storage_driver":"devicemapper", "name":"k8s-bm2", "network_driver":"flannel",