From fae0c9c6482a42a9f847a5954de5b22cd7d7f305 Mon Sep 17 00:00:00 2001 From: Liam Young Date: Mon, 30 Oct 2023 09:22:59 +0000 Subject: [PATCH] Support CA for ldaps Change-Id: I6489bd5f7975daf26f9669e17733071b6eaf4654 --- .../charms/keystone_k8s/v0/domain_config.py | 12 +++++-- charms/keystone-k8s/src/charm.py | 31 +++++++++++++++++-- 2 files changed, 38 insertions(+), 5 deletions(-) diff --git a/charms/keystone-k8s/lib/charms/keystone_k8s/v0/domain_config.py b/charms/keystone-k8s/lib/charms/keystone_k8s/v0/domain_config.py index f3fc84be..0d9858c9 100644 --- a/charms/keystone-k8s/lib/charms/keystone_k8s/v0/domain_config.py +++ b/charms/keystone-k8s/lib/charms/keystone_k8s/v0/domain_config.py @@ -63,7 +63,7 @@ class DomainConfigProvides(Object): self.on.remote_ready.emit(event.relation) def set_domain_info( - self, domain_name: str, config_contents: str + self, domain_name: str, config_contents: str, ca=None ) -> None: """Set ceilometer configuration on the relation.""" if not self.charm.unit.is_leader(): @@ -72,6 +72,8 @@ class DomainConfigProvides(Object): for relation in self.relations: relation.data[self.charm.app]["domain-name"] = domain_name relation.data[self.charm.app]["config-contents"] = base64.b64encode(config_contents.encode()).decode() + if ca: + relation.data[self.charm.app]["ca"] = base64.b64encode(ca.encode()).decode() @property def relations(self): @@ -142,9 +144,13 @@ class DomainConfigRequires(Object): raw_config_contents = relation.data[relation.app].get("config-contents") if not all([domain_name, raw_config_contents]): continue - configs.append({ + raw_ca = relation.data[relation.app].get("ca") + config = { "domain-name": domain_name, - "config-contents": base64.b64decode(raw_config_contents).decode()}) + "config-contents": base64.b64decode(raw_config_contents).decode()} + if raw_ca: + config["ca"] = base64.b64decode(raw_ca).decode() + configs.append(config) return configs @property diff --git a/charms/keystone-k8s/src/charm.py b/charms/keystone-k8s/src/charm.py index 1c639207..2f0d0628 100755 --- a/charms/keystone-k8s/src/charm.py +++ b/charms/keystone-k8s/src/charm.py @@ -136,6 +136,7 @@ class KeystoneConfigAdapter(sunbeam_contexts.ConfigContext): "public_endpoint": self.charm.public_endpoint, "admin_endpoint": self.charm.admin_endpoint, "domain_config_dir": self.charm.domain_config_dir, + "domain_ca_dir": self.charm.domain_ca_dir, "log_config": "/etc/keystone/logging.conf.j2", "paste_config_file": "/etc/keystone/keystone-paste.ini", } @@ -316,6 +317,7 @@ class KeystoneOperatorCharm(sunbeam_charm.OSBaseOperatorAPICharm): wsgi_admin_script = "/usr/bin/keystone-wsgi-admin" wsgi_public_script = "/usr/bin/keystone-wsgi-public" domain_config_dir = Path("/etc/keystone/domains") + domain_ca_dir = Path("/usr/local/share/ca-certificates") service_port = 5000 mandatory_relations = {"database", "ingress-public"} db_sync_cmds = [ @@ -904,6 +906,12 @@ export OS_AUTH_VERSION=3 else: container.remove_path(domain_file.path) removed_domains.append(domain_on_disk) + for domain_file in container.list_files(self.domain_ca_dir): + domain_on_disk = domain_file.name.split(".")[1] + if domain_on_disk in active_domains: + logger.debug("Keeping CA {}".format(domain_file.name)) + else: + container.remove_path(domain_file.path) return removed_domains def update_domain_config( @@ -921,6 +929,7 @@ export OS_AUTH_VERSION=3 domain_config_file = ( self.domain_config_dir / f"keystone.{domain_name}.conf" ) + domain_ca_file = self.domain_ca_dir / f"keystone.{domain_name}.crt" try: original_contents = container.pull(domain_config_file).read() except (ops.pebble.PathError, FileNotFoundError): @@ -936,6 +945,23 @@ export OS_AUTH_VERSION=3 }, ) updated_domains.append(domain_name) + if domain_config.get("ca"): + try: + original_contents = container.pull(domain_ca_file).read() + except (ops.pebble.PathError, FileNotFoundError): + original_contents = None + if original_contents != domain_config["ca"]: + container.push( + domain_ca_file, + domain_config["ca"], + **{ + "user": "keystone", + "group": "keystone", + "permissions": 0o644, + }, + ) + updated_domains.append(domain_name) + return updated_domains def configure_domains(self, event: ops.framework.EventBase = None) -> None: @@ -945,8 +971,9 @@ export OS_AUTH_VERSION=3 else: exclude = [] container = self.unit.get_container(KEYSTONE_CONTAINER) - if not container.isdir(self.domain_config_dir): - container.make_dir(self.domain_config_dir, make_parents=True) + for d in [self.domain_config_dir, self.domain_ca_dir]: + if not container.isdir(d): + container.make_dir(d, make_parents=True) domain_configs = self.dc.get_domain_configs(exclude=exclude) removed_domains = self.remove_old_domains(domain_configs, container) updated_domains = self.update_domain_config(domain_configs, container)