From 903e1a710c935a2e598d68c33a966258ac7382a3 Mon Sep 17 00:00:00 2001 From: Lucian Petrut Date: Thu, 5 Dec 2024 07:22:30 +0200 Subject: [PATCH] Add kube-apiserver-extra-sans option (#201) We're adding a config option that allows specifying additional kube-apiserver Subject Alternative Names. Co-authored-by: Adam Dyess --- charms/worker/k8s/charmcraft.yaml | 11 ++++++++++ charms/worker/k8s/src/charm.py | 11 ++++++++-- charms/worker/k8s/tests/unit/test_base.py | 25 +++++++++++++++++++++++ 3 files changed, 45 insertions(+), 2 deletions(-) diff --git a/charms/worker/k8s/charmcraft.yaml b/charms/worker/k8s/charmcraft.yaml index 12ee9051..cf24b0bb 100644 --- a/charms/worker/k8s/charmcraft.yaml +++ b/charms/worker/k8s/charmcraft.yaml @@ -224,6 +224,17 @@ config: runtime-config=batch/v2alpha1=true profiling=true will result in kube-apiserver being run with the following options: --runtime-config=batch/v2alpha1=true --profiling=true + kube-apiserver-extra-sans: + type: string + default: "" + description: | + Space separated list of extra Subject Alternative Names for the kube-apiserver + self-signed certificates. + + Examples: + - "kubernetes" + - "kubernetes.default.svc" + - "kubernetes.default.svc.cluster.local" kube-controller-manager-extra-args: type: string default: "" diff --git a/charms/worker/k8s/src/charm.py b/charms/worker/k8s/src/charm.py index a3d5206a..1a2af243 100755 --- a/charms/worker/k8s/src/charm.py +++ b/charms/worker/k8s/src/charm.py @@ -350,6 +350,13 @@ def _check_k8sd_ready(self): status.add(ops.MaintenanceStatus("Ensuring snap readiness")) self.api_manager.check_k8sd_ready() + def _get_extra_sans(self): + """Retrieve the certificate extra SANs.""" + extra_sans_str = str(self.config.get("kube-apiserver-extra-sans") or "") + configured_sans = {san for san in extra_sans_str.strip().split() if san} + all_sans = configured_sans | set([_get_public_address()]) + return sorted(all_sans) + def _assemble_bootstrap_config(self): """Assemble the bootstrap configuration for the Kubernetes cluster. @@ -362,7 +369,7 @@ def _assemble_bootstrap_config(self): bootstrap_config.service_cidr = str(self.config["bootstrap-service-cidr"]) bootstrap_config.pod_cidr = str(self.config["bootstrap-pod-cidr"]) bootstrap_config.control_plane_taints = str(self.config["bootstrap-node-taints"]).split() - bootstrap_config.extra_sans = [_get_public_address()] + bootstrap_config.extra_sans = self._get_extra_sans() cluster_name = self.get_cluster_name() config.extra_args.craft(self.config, bootstrap_config, cluster_name) return bootstrap_config @@ -795,7 +802,7 @@ def _join_with_token(self, relation: ops.Relation, token: str, cluster_name: str request = JoinClusterRequest(name=node_name, address=cluster_addr, token=token) if self.is_control_plane: request.config = ControlPlaneNodeJoinConfig() - request.config.extra_sans = [_get_public_address()] + request.config.extra_sans = self._get_extra_sans() config.extra_args.craft(self.config, request.config, cluster_name) else: request.config = NodeJoinConfig() diff --git a/charms/worker/k8s/tests/unit/test_base.py b/charms/worker/k8s/tests/unit/test_base.py index 6a3f419a..a0ee2daa 100644 --- a/charms/worker/k8s/tests/unit/test_base.py +++ b/charms/worker/k8s/tests/unit/test_base.py @@ -195,3 +195,28 @@ def test_configure_datastore_runtime_config_etcd(harness): assert uccr_config.datastore.client_key == "" assert uccr_config.datastore.servers == ["foo:1234", "bar:1234"] assert uccr_config.datastore.type == "external" + + +def test_configure_boostrap_extra_sans(harness): + """Test configuring kube-apiserver-extra-sans on bootstrap. + + Args: + harness: the harness under test + """ + if harness.charm.is_worker: + pytest.skip("Not applicable on workers") + + cfg_extra_sans = ["mykubernetes", "mykubernetes.local"] + public_addr = "11.12.13.14" + harness.update_config({"kube-apiserver-extra-sans": " ".join(cfg_extra_sans)}) + + with mock.patch("charm._get_public_address") as mock_get_public_addr: + mock_get_public_addr.return_value = public_addr + + bs_config = harness.charm._assemble_bootstrap_config() + + # We expect the resulting SANs to include the configured addresses as well + # as the unit address. + exp_extra_sans = cfg_extra_sans + [public_addr] + for san in exp_extra_sans: + assert san in bs_config.extra_sans