-
Notifications
You must be signed in to change notification settings - Fork 27
[DPE-8320] Fix backups with internal certificates #1162
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -32,6 +32,8 @@ | |
| from charms.operator_libs_linux.v2 import snap | ||
| from charms.rolling_ops.v0.rollingops import RollingOpsManager, RunWithLock | ||
| from charms.tempo_coordinator_k8s.v0.charm_tracing import trace_charm | ||
| from cryptography.x509 import load_pem_x509_certificate | ||
| from cryptography.x509.oid import NameOID | ||
| from ops import ( | ||
| ActionEvent, | ||
| ActiveStatus, | ||
|
|
@@ -378,6 +380,17 @@ def _post_snap_refresh(self, refresh: charm_refresh.Machines): | |
|
|
||
| Called after snap refresh | ||
| """ | ||
| try: | ||
| if raw_cert := self.get_secret(UNIT_SCOPE, "internal-cert"): | ||
| cert = load_pem_x509_certificate(raw_cert.encode()) | ||
| if ( | ||
| cert.subject.get_attributes_for_oid(NameOID.COMMON_NAME)[0].value | ||
| != self._unit_ip | ||
| ): | ||
| self.tls.generate_internal_peer_cert() | ||
| except Exception: | ||
| logger.exception("Unable to check or update internal cert") | ||
|
Comment on lines
+383
to
+392
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Regenerate the cert if the common name is not the IP before the upgrade. |
||
|
|
||
| if not self._patroni.start_patroni(): | ||
| self.set_unit_status(ops.BlockedStatus("Failed to start PostgreSQL"), refresh=refresh) | ||
| return | ||
|
|
@@ -1403,7 +1416,6 @@ def _on_leader_elected(self, event: LeaderElectedEvent) -> None: # noqa: C901 | |
|
|
||
| if not self.get_secret(APP_SCOPE, "internal-ca"): | ||
| self.tls.generate_internal_peer_ca() | ||
| self.tls.generate_internal_peer_cert() | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If the internal cert generates before the IP is set to the peer data, the hostname will be used as common name. It also causes issues on Juju 4. |
||
| self.update_config() | ||
|
|
||
| # Don't update connection endpoints in the first time this event run for | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -71,21 +71,22 @@ def _get_peer_addrs(self) -> set[str]: | |
| peer_addrs.add(addr) | ||
| return peer_addrs | ||
|
|
||
| def _get_common_name(self): | ||
| def _get_common_name(self) -> str: | ||
| return self.charm.unit_peer_data.get("database-address") or self.host | ||
|
|
||
| def _get_peer_common_name(self) -> str: | ||
| return self.charm.unit_peer_data.get("database-peers-address") or self.host | ||
|
Comment on lines
+77
to
+78
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we should use the peers address here, in case it's different from the relation address.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Makes sense, as we might have different Juju spaces and for the purpose of using the certificates for backup on replicas, what makes sense is the peer address. |
||
|
|
||
| def __init__(self, charm: "PostgresqlOperatorCharm", peer_relation: str): | ||
| super().__init__(charm, "client-relations") | ||
| self.charm = charm | ||
| self.peer_relation = peer_relation | ||
| unit_id = self.charm.unit.name.split("/")[1] | ||
| self.host = f"{self.charm.app.name}-{unit_id}" | ||
| if self.charm.unit_peer_data: | ||
| common_name = self._get_common_name() | ||
| client_addresses = self._get_client_addrs() | ||
| peer_addresses = self._get_peer_addrs() | ||
| else: | ||
| common_name = self.host | ||
| client_addresses = set() | ||
| peer_addresses = set() | ||
| self.common_hosts = {self.host} | ||
|
|
@@ -97,7 +98,7 @@ def __init__(self, charm: "PostgresqlOperatorCharm", peer_relation: str): | |
| TLS_CLIENT_RELATION, | ||
| certificate_requests=[ | ||
| CertificateRequestAttributes( | ||
| common_name=common_name, | ||
| common_name=self._get_common_name(), | ||
| sans_ip=frozenset(client_addresses), | ||
| sans_dns=frozenset({ | ||
| *self.common_hosts, | ||
|
|
@@ -114,7 +115,7 @@ def __init__(self, charm: "PostgresqlOperatorCharm", peer_relation: str): | |
| TLS_PEER_RELATION, | ||
| certificate_requests=[ | ||
| CertificateRequestAttributes( | ||
| common_name=common_name, | ||
| common_name=self._get_peer_common_name(), | ||
| sans_ip=frozenset(self._get_peer_addrs()), | ||
| sans_dns=frozenset({ | ||
| *self.common_hosts, | ||
|
|
@@ -239,7 +240,7 @@ def generate_internal_peer_cert(self) -> None: | |
| private_key = generate_private_key() | ||
| csr = generate_csr( | ||
| private_key, | ||
| common_name=self._get_common_name(), | ||
| common_name=self._get_peer_common_name(), | ||
| sans_ip=frozenset(self._get_peer_addrs()), | ||
| sans_dns=frozenset({ | ||
| *self.common_hosts, | ||
|
|
@@ -252,3 +253,6 @@ def generate_internal_peer_cert(self) -> None: | |
| self.charm.set_secret(UNIT_SCOPE, "internal-key", str(private_key)) | ||
| self.charm.set_secret(UNIT_SCOPE, "internal-cert", str(cert)) | ||
| self.charm.push_tls_files_to_workload() | ||
| logger.info( | ||
| "Internal peer certificate generated. Please use a proper TLS operator if possible." | ||
| ) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -16,9 +16,6 @@ | |
| logger = logging.getLogger(__name__) | ||
|
|
||
| S3_INTEGRATOR_APP_NAME = "s3-integrator" | ||
| tls_certificates_app_name = "self-signed-certificates" | ||
| tls_channel = "latest/stable" | ||
| tls_config = {"ca-common-name": "Test CA"} | ||
|
|
||
| backup_id, value_before_backup, value_after_backup = "", None, None | ||
|
|
||
|
|
@@ -167,9 +164,9 @@ async def test_backup_ceph(ops_test: OpsTest, cloud_configs, cloud_credentials, | |
| await backup_operations( | ||
| ops_test, | ||
| S3_INTEGRATOR_APP_NAME, | ||
| tls_certificates_app_name, | ||
| tls_config, | ||
| tls_channel, | ||
| None, | ||
| None, | ||
| None, | ||
|
Comment on lines
+167
to
+169
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Test on microceph with the internal certs, without using a TLS operator. |
||
| cloud_credentials, | ||
| "ceph", | ||
| cloud_configs, | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add INFO-like message to log to see when cert is regenerated (to simplify production troubleshooting). Warning is also fine.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added info log inside generate_internal_peer_cert().