From b9918386b03646abe21676825c9344188c64dfe4 Mon Sep 17 00:00:00 2001 From: Feilong Wang Date: Fri, 27 Jul 2018 12:27:30 +1200 Subject: [PATCH] Using simple public/private key for k8s service account keys Due to a change in Go 1.10.3[1], which k8s v1.11.1 is based on, now magnum is failing to create a working k8s cluster with version 1.11.1. This patch is changing removing the extention usage for server auth for ca cert and using simple public/private keys for k8s service account keys. [1] https://go.googlesource.com/go/+/09fa131c99da0ef9f78c9f4f6cd955237ccc01cd Task: 23210 Story: 2003103 Change-Id: Ieba8f55d55db2afda6888d4bc6c2caa87370d13d --- magnum/common/x509/operations.py | 20 +++++++++++-------- .../drivers/heat/k8s_fedora_template_def.py | 13 ++++-------- .../tests/unit/common/x509/test_operations.py | 6 ++++-- .../handlers/test_k8s_cluster_conductor.py | 20 +++++++++++-------- .../unit/drivers/test_template_definition.py | 10 ++++++---- 5 files changed, 38 insertions(+), 31 deletions(-) diff --git a/magnum/common/x509/operations.py b/magnum/common/x509/operations.py index 4cd21c116e..fa82f6aa4d 100644 --- a/magnum/common/x509/operations.py +++ b/magnum/common/x509/operations.py @@ -87,14 +87,12 @@ def _build_ca_extentions(): key_usage = x509.KeyUsage(False, False, False, False, False, True, False, False, False) key_usage = x509.Extension(key_usage.oid, True, key_usage) - extended_key_usage = x509.ExtendedKeyUsage([x509.OID_SERVER_AUTH]) - extended_key_usage = x509.Extension(extended_key_usage.oid, False, - extended_key_usage) + basic_constraints = x509.BasicConstraints(ca=True, path_length=0) basic_constraints = x509.Extension(basic_constraints.oid, True, basic_constraints) - return [basic_constraints, key_usage, extended_key_usage] + return [basic_constraints, key_usage] def _generate_self_signed_certificate(subject_name, extensions, @@ -235,23 +233,29 @@ def sign(csr, issuer_name, ca_key, ca_key_password=None, def generate_csr_and_key(common_name): - """Return a dict with a new csr and key.""" - key = rsa.generate_private_key( + """Return a dict with a new csr, public key and private key.""" + private_key = rsa.generate_private_key( public_exponent=65537, key_size=2048, backend=default_backend()) + public_key = private_key.public_key() + csr = x509.CertificateSigningRequestBuilder().subject_name(x509.Name([ x509.NameAttribute(x509.oid.NameOID.COMMON_NAME, common_name), - ])).sign(key, hashes.SHA256(), default_backend()) + ])).sign(private_key, hashes.SHA256(), default_backend()) result = { 'csr': csr.public_bytes( encoding=serialization.Encoding.PEM).decode("utf-8"), - 'key': key.private_bytes( + 'private_key': private_key.private_bytes( encoding=serialization.Encoding.PEM, format=serialization.PrivateFormat.TraditionalOpenSSL, encryption_algorithm=serialization.NoEncryption()).decode("utf-8"), + 'public_key': public_key.public_bytes( + encoding=serialization.Encoding.PEM, + format=serialization.PublicFormat.SubjectPublicKeyInfo).decode( + "utf-8"), } return result diff --git a/magnum/drivers/heat/k8s_fedora_template_def.py b/magnum/drivers/heat/k8s_fedora_template_def.py index 0fd8cfa97b..51145c01bc 100644 --- a/magnum/drivers/heat/k8s_fedora_template_def.py +++ b/magnum/drivers/heat/k8s_fedora_template_def.py @@ -116,17 +116,12 @@ class K8sFedoraTemplateDefinition(k8s_template_def.K8sTemplateDefinition): if label_value: extra_params[label] = label_value - # NOTE(flwang): We're generating a signed cert and private key - # based on the cluster CA as the service account signing keys for - # k8s cluster, though a general public/private keypair works as well. - csr_key = x509.generate_csr_and_key(u"Kubernetes Service Account") - signed_cert = cert_manager.sign_node_certificate(cluster, - csr_key["csr"], - context=context) + csr_keys = x509.generate_csr_and_key(u"Kubernetes Service Account") + extra_params['kube_service_account_key'] = \ - signed_cert.replace("\n", "\\n") + csr_keys["public_key"].replace("\n", "\\n") extra_params['kube_service_account_private_key'] = \ - csr_key["key"].replace("\n", "\\n") + csr_keys["private_key"].replace("\n", "\\n") cert_manager_api = cluster.labels.get('cert_manager_api') if strutils.bool_from_string(cert_manager_api): diff --git a/magnum/tests/unit/common/x509/test_operations.py b/magnum/tests/unit/common/x509/test_operations.py index eec60a3175..32bedfacd2 100644 --- a/magnum/tests/unit/common/x509/test_operations.py +++ b/magnum/tests/unit/common/x509/test_operations.py @@ -50,5 +50,7 @@ class TestX509Operations(base.BaseTestCase): def test_generate_csr_and_key(self, mock_generate_private_key, mock_default_backend): mock_generate_private_key.return_value = mock.MagicMock() - csr_key = operations.generate_csr_and_key(u"Test") - self.assertIsNotNone(csr_key) + csr_keys = operations.generate_csr_and_key(u"Test") + self.assertIsNotNone(csr_keys) + self.assertTrue("public_key" in csr_keys) + self.assertTrue("private_key" in csr_keys) diff --git a/magnum/tests/unit/conductor/handlers/test_k8s_cluster_conductor.py b/magnum/tests/unit/conductor/handlers/test_k8s_cluster_conductor.py index 38affc9b7e..099e33ba70 100644 --- a/magnum/tests/unit/conductor/handlers/test_k8s_cluster_conductor.py +++ b/magnum/tests/unit/conductor/handlers/test_k8s_cluster_conductor.py @@ -164,7 +164,8 @@ class TestClusterConductorWithK8s(base.TestCase): cluster_template = objects.ClusterTemplate( self.context, **self.cluster_template_dict) mock_generate_csr_and_key.return_value = {'csr': 'csr', - 'key': 'private_key'} + 'private_key': 'private_key', + 'public_key': 'public_key'} mock_sign_node_certificate.return_value = 'signed_cert' mock_objects_cluster_template_get_by_uuid.return_value = \ cluster_template @@ -283,7 +284,7 @@ class TestClusterConductorWithK8s(base.TestCase): 'kubescheduler_options': '--kubescheduler', 'kubeproxy_options': '--kubeproxy', 'octavia_enabled': False, - 'kube_service_account_key': 'signed_cert', + 'kube_service_account_key': 'public_key', 'kube_service_account_private_key': 'private_key', } if missing_attr is not None: @@ -316,7 +317,8 @@ class TestClusterConductorWithK8s(base.TestCase): cluster_template = objects.ClusterTemplate( self.context, **self.cluster_template_dict) mock_generate_csr_and_key.return_value = {'csr': 'csr', - 'key': 'private_key'} + 'private_key': 'private_key', + 'public_key': 'public_key'} mock_sign_node_certificate.return_value = 'signed_cert' mock_objects_cluster_template_get_by_uuid.return_value = \ cluster_template @@ -401,7 +403,7 @@ class TestClusterConductorWithK8s(base.TestCase): 'kubescheduler_options': '--kubescheduler', 'kubeproxy_options': '--kubeproxy', 'octavia_enabled': False, - 'kube_service_account_key': 'signed_cert', + 'kube_service_account_key': 'public_key', 'kube_service_account_private_key': 'private_key', } @@ -441,7 +443,8 @@ class TestClusterConductorWithK8s(base.TestCase): cluster_template = objects.ClusterTemplate( self.context, **self.cluster_template_dict) mock_generate_csr_and_key.return_value = {'csr': 'csr', - 'key': 'private_key'} + 'private_key': 'private_key', + 'public_key': 'public_key'} mock_sign_node_certificate.return_value = 'signed_cert' mock_objects_cluster_template_get_by_uuid.return_value = \ cluster_template @@ -506,7 +509,7 @@ class TestClusterConductorWithK8s(base.TestCase): 'kubescheduler_options': '--kubescheduler', 'kubeproxy_options': '--kubeproxy', 'octavia_enabled': False, - 'kube_service_account_key': 'signed_cert', + 'kube_service_account_key': 'public_key', 'kube_service_account_private_key': 'private_key', } self.assertEqual(expected, definition) @@ -837,7 +840,8 @@ class TestClusterConductorWithK8s(base.TestCase): cluster_template = objects.ClusterTemplate( self.context, **self.cluster_template_dict) mock_generate_csr_and_key.return_value = {'csr': 'csr', - 'key': 'private_key'} + 'private_key': 'private_key', + 'public_key': 'public_key'} mock_sign_node_certificate.return_value = 'signed_cert' mock_objects_cluster_template_get_by_uuid.return_value = \ cluster_template @@ -916,7 +920,7 @@ class TestClusterConductorWithK8s(base.TestCase): 'kubescheduler_options': '--kubescheduler', 'kubeproxy_options': '--kubeproxy', 'octavia_enabled': False, - 'kube_service_account_key': 'signed_cert', + 'kube_service_account_key': 'public_key', 'kube_service_account_private_key': 'private_key', } self.assertEqual(expected, definition) diff --git a/magnum/tests/unit/drivers/test_template_definition.py b/magnum/tests/unit/drivers/test_template_definition.py index 67f7dc6141..04e509e94e 100644 --- a/magnum/tests/unit/drivers/test_template_definition.py +++ b/magnum/tests/unit/drivers/test_template_definition.py @@ -285,7 +285,8 @@ class AtomicK8sTemplateDefinitionTestCase(BaseK8sTemplateDefinitionTestCase): mock_get_discovery_url, mock_osc_class, mock_enable_octavia): mock_generate_csr_and_key.return_value = {'csr': 'csr', - 'key': 'private_key'} + 'private_key': 'private_key', + 'public_key': 'public_key'} mock_sign_node_certificate.return_value = 'signed_cert' mock_enable_octavia.return_value = False mock_context = mock.MagicMock() @@ -417,7 +418,7 @@ class AtomicK8sTemplateDefinitionTestCase(BaseK8sTemplateDefinitionTestCase): 'ingress_controller': ingress_controller, 'ingress_controller_role': ingress_controller_role, 'octavia_enabled': False, - 'kube_service_account_key': 'signed_cert', + 'kube_service_account_key': 'public_key', 'kube_service_account_private_key': 'private_key', }} mock_get_params.assert_called_once_with(mock_context, @@ -454,7 +455,8 @@ class AtomicK8sTemplateDefinitionTestCase(BaseK8sTemplateDefinitionTestCase): mock_get_discovery_url, mock_osc_class, mock_enable_octavia): mock_generate_csr_and_key.return_value = {'csr': 'csr', - 'key': 'private_key'} + 'private_key': 'private_key', + 'public_key': 'public_key'} mock_sign_node_certificate.return_value = 'signed_cert' mock_enable_octavia.return_value = False mock_context = mock.MagicMock() @@ -588,7 +590,7 @@ class AtomicK8sTemplateDefinitionTestCase(BaseK8sTemplateDefinitionTestCase): 'ingress_controller': ingress_controller, 'ingress_controller_role': ingress_controller_role, 'octavia_enabled': False, - 'kube_service_account_key': 'signed_cert', + 'kube_service_account_key': 'public_key', 'kube_service_account_private_key': 'private_key', }} mock_get_params.assert_called_once_with(mock_context,