compute_certificate
Compute TLS certificate lifecycle: CSR generation and Hub-issued cert renewal.
Once a compute has heartbeated with a private IP address, the hub registers a
"compute" record and returns a computeId/domain pair (see
BitfountHub.do_pod_heartbeat). This module builds a CSR for that domain,
submits it to BitfountHub.request_compute_certificate, polls
BitfountHub.get_compute_certificate until issued, persists the result, and later
detects when the issued certificate is two-thirds of the way through its
validity period so a renewal can be requested.
If the hub hands back a new computeId/domain pair; a persisted
certificate for the old domain is treated as absent (rather than just not-yet-
due-for-renewal) so a certificate for the new domain is requested straight
away instead of waiting out the old one's remaining validity.
Module
Functions
build_csr_pem
def build_csr_pem(private_key: RSAPrivateKey, domain: str) ‑> str:Builds a PEM-encoded certificate signing request for domain.
The hub requires the CSR's public key to be RSA, its subject common name
to equal domain exactly, and exactly one subject alternative name (a
DNS name equal to domain).
Arguments
private_key: The RSA private key to sign the CSR with. Its public key is embedded in the CSR.domain: The domain the certificate is being requested for (thedomainreturned alongsidecomputeIdfrom the heartbeat).
Returns The PEM-encoded CSR.
certificate_domain
def certificate_domain(certificate_pem: str) ‑> str | None:Returns the leaf certificate's subject common name, or None if absent.
build_csr_pem sets the CSR's common name to the domain it was issued
for, and the hub is required to preserve it, so this is what identifies
which domain a persisted certificate belongs to.
Arguments
certificate_pem: A PEM-encoded certificate (the leaf certificate is sufficient; any following CA bundle entries are ignored).
certificate_validity
def certificate_validity( certificate_pem: str,) ‑> tuple[datetime.datetime, datetime.datetime]:Returns the (not-valid-before, not-valid-after) UTC datetimes.
Arguments
certificate_pem: A PEM-encoded certificate (the leaf certificate is sufficient; any following CA bundle entries are ignored).
renewal_due_at
def renewal_due_at( not_before: datetime, not_after: datetime, fraction: float = 0.6666666666666666,) ‑> datetime.datetime:Returns the point at which a certificate should be renewed.
Defaults to two-thirds of the way through the certificate's validity period. This is the same heuristic used by ACME clients.
Classes
ComputeCertificateManager
class ComputeCertificateManager( hub: BitfountHub, key_directory: Path, private_key: RSAPrivateKey,):Manages the lifecycle of a compute's hub-issued TLS certificate.
Persists the issued certificate (leaf + CA bundle) alongside the pod's
existing RSA identity key, under key_directory / "compute.pem".
Arguments
hub: TheBitfountHubclient to request/poll certificates through.key_directory: The pod's key directory (the same directorypod_rsa.pemlives in).private_key: The pod's existing RSA identity key. Reused as the CSR key rather than generating a separate one.
Variables
fullchain_path : pathlib.Path- Path to the persisted leaf-certificate + CA-bundle PEM file.
-
tls_keyfile_path : pathlib.Path- Path to a PEM/PKCS8 copy of the private key, for TLS.Written lazily, on first access.
ComputeCertificateManageris constructed for every pod regardless of whether TLS is ever actually used, and callers (e.g. tests) may pass a mockedprivate_key.
Methods
current_fullchain_path
def current_fullchain_path(self) ‑> pathlib.Path | None:Returns fullchain_path if a certificate is already persisted.
poll
def poll(self, compute_id: str | None, domain: str | None) ‑> None:Runs one idempotent certificate-lifecycle tick.
Safe to call repeatedly (e.g. from a background thread). Never
raises: hub/network failures are logged and left for the next tick,
matching how Pod._pod_heartbeat handles the same failure modes.
Arguments
compute_id: The compute worker ID from the most recent heartbeat response, or None if not yet known.domain: The domain from the most recent heartbeat response, or None if not yet known.