Skip to content

Commit

Permalink
chore: update charm libraries (#288)
Browse files Browse the repository at this point in the history
  • Loading branch information
observability-noctua-bot authored Sep 5, 2024
1 parent 0f0df54 commit 14281e5
Showing 1 changed file with 39 additions and 3 deletions.
42 changes: 39 additions & 3 deletions lib/charms/observability_libs/v1/cert_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
self.framework.observe(self.cert_handler.on.cert_changed, self._on_server_cert_changed)
container.push(keypath, self.cert_handler.private_key)
container.push(certpath, self.cert_handler.servert_cert)
container.push(certpath, self.cert_handler.server_cert)
```
Since this library uses [Juju Secrets](https://juju.is/docs/juju/secret) it requires Juju >= 3.0.3.
Expand Down Expand Up @@ -59,15 +59,15 @@
import logging

from ops.charm import CharmBase
from ops.framework import EventBase, EventSource, Object, ObjectEvents
from ops.framework import BoundEvent, EventBase, EventSource, Object, ObjectEvents, StoredState
from ops.jujuversion import JujuVersion
from ops.model import Relation, Secret, SecretNotFoundError

logger = logging.getLogger(__name__)

LIBID = "b5cd5cd580f3428fa5f59a8876dcbe6a"
LIBAPI = 1
LIBPATCH = 11
LIBPATCH = 12

VAULT_SECRET_LABEL = "cert-handler-private-vault"

Expand Down Expand Up @@ -273,6 +273,7 @@ class CertHandler(Object):
"""A wrapper for the requirer side of the TLS Certificates charm library."""

on = CertHandlerEvents() # pyright: ignore
_stored = StoredState()

def __init__(
self,
Expand All @@ -283,6 +284,7 @@ def __init__(
peer_relation_name: str = "peers",
cert_subject: Optional[str] = None,
sans: Optional[List[str]] = None,
refresh_events: Optional[List[BoundEvent]] = None,
):
"""CertHandler is used to wrap TLS Certificates management operations for charms.
Expand All @@ -299,8 +301,17 @@ def __init__(
Must match metadata.yaml.
cert_subject: Custom subject. Name collisions are under the caller's responsibility.
sans: DNS names. If none are given, use FQDN.
refresh_events: an optional list of bound events which
will be observed to replace the current CSR with a new one
if there are changes in the CSR's DNS SANs or IP SANs.
Then, subsequently, replace its corresponding certificate with a new one.
"""
super().__init__(charm, key)
# use StoredState to store the hash of the CSR
# to potentially trigger a CSR renewal on `refresh_events`
self._stored.set_default(
csr_hash=None,
)
self.charm = charm

# We need to sanitize the unit name, otherwise route53 complains:
Expand Down Expand Up @@ -355,6 +366,15 @@ def __init__(
self._on_upgrade_charm,
)

if refresh_events:
for ev in refresh_events:
self.framework.observe(ev, self._on_refresh_event)

def _on_refresh_event(self, _):
"""Replace the latest current CSR with a new one if there are any SANs changes."""
if self._stored.csr_hash != self._csr_hash:
self._generate_csr(renew=True)

def _on_upgrade_charm(self, _):
has_privkey = self.vault.get_value("private-key")

Expand Down Expand Up @@ -419,6 +439,20 @@ def enabled(self) -> bool:

return True

@property
def _csr_hash(self) -> int:
"""A hash of the config that constructs the CSR.
Only include here the config options that, should they change, should trigger a renewal of
the CSR.
"""
return hash(
(
tuple(self.sans_dns),
tuple(self.sans_ip),
)
)

@property
def available(self) -> bool:
"""Return True if all certs are available in relation data; False otherwise."""
Expand Down Expand Up @@ -484,6 +518,8 @@ def _generate_csr(
)
self.certificates.request_certificate_creation(certificate_signing_request=csr)

self._stored.csr_hash = self._csr_hash

if clear_cert:
self.vault.clear()

Expand Down

0 comments on commit 14281e5

Please sign in to comment.