domino_admin_toolkit.checks.test_webhook_ca_bundle_expiration module
- pydantic model domino_admin_toolkit.checks.test_webhook_ca_bundle_expiration.WebhookCaBundleExpiryAnalyzer
Bases:
AnalyzerBase[WebhookCaBundleRow]Validates webhook admission-config caBundle expiry with WARN/FAIL tiers.
Thresholds mirror RE-3163’s test_tls_secret_expiration defaults: an expiring caBundle is functionally identical to an expiring TLS secret cert for alerting purposes, even though the failure mode here (broken admission) is more severe than a single service’s TLS handshake failing.
- Fields:
- analyze(data)
Analyzes one row and returns a list of CheckResult instances.
- Return type:
- Args:
data: One row dict (
TRow). The Runner calls this once per DataFrame row.- Returns:
List[CheckResult]: A list containing the results of the analysis.
- Raises:
NotImplementedError: If this method is not implemented by subclasses.
- name: ClassVar[str] = 'WebhookCaBundleExpiryAnalyzer'
- class domino_admin_toolkit.checks.test_webhook_ca_bundle_expiration.WebhookCaBundleRow
Bases:
TypedDict
- domino_admin_toolkit.checks.test_webhook_ca_bundle_expiration.test_webhook_ca_bundle_expiration(webhook_ca_bundle_data, runner)
- Description:
Checks caBundle expiry across every MutatingWebhookConfiguration and ValidatingWebhookConfiguration in the cluster. Each webhook entry’s clientConfig.caBundle (service-based or url-based — both are included, only a missing/empty caBundle is skipped) is parsed and every certificate it contains is evaluated individually, so a multi-cert caBundle surfaces one row per cert.
The caBundle signs the webhook’s serving cert; when it expires, every admission request the webhook fronts is rejected by the API server. This typically manifests as “nothing deploys, nothing admits, the cluster feels stuck” even though every workload already running looks healthy — a classic 3am incident. Unlike test_tls_secret_expiration.py (the storage layer) or test_cert_manager_resources.py (the declarative Certificate/Issuer layer), this check inspects the actual client config the API server uses to trust the webhook at admission time; the caBundle does not automatically rotate with the cert behind it unless cert-manager’s cainjector (or an equivalent mechanism) actively re-injects it.
Prototype incident OT-3385 (cloud-braze, 2025-06-17, P0): data-plane-workloads-webhook-server.domino-compute.svc’s caBundle expired 2025-04-28 and broke execution-start; discovery lagged expiry by 46 days. This check alerts on the same signal ~30 days in advance (see Warning Conditions).
is_ca_injector_managed is informational only — True when either cert-manager.io/inject-ca-from or cert-manager.io/inject-ca-from-secret is present on the parent webhook config. It does not affect the FAIL/WARN verdict: a cainjector-managed caBundle can still expire if the cainjector itself is broken (see test_cert_manager.py).
- Failure Conditions:
A caBundle certificate has already expired
A caBundle certificate expires in fewer than 7 days
- Warning Conditions:
A caBundle certificate expires in fewer than 30 days
- Error Conditions:
The toolkit could not list MutatingWebhookConfiguration or ValidatingWebhookConfiguration objects (RBAC denial, API server error, etc.), or could not process an already-listed config’s webhook entries — surfaced as an ERROR naming which kind failed, whether the failure was in listing or processing, and why, rather than silently omitting that kind from the report. If only one kind fails, the other kind’s rows still render normally alongside this ERROR.
- Troubleshooting Steps:
Inspect a specific webhook’s caBundle expiry directly: kubectl get validatingwebhookconfiguration <name> -o jsonpath=’{.webhooks[0].clientConfig.caBundle}’
base64 -d | openssl x509 -noout -dates(use mutatingwebhookconfiguration for mutating configs)
Check whether the config carries a cainjector annotation (is_ca_injector_managed=True in this check’s output) — if so, the fix is upstream in cert-manager, not the webhook: kubectl get validatingwebhookconfiguration <name> -o jsonpath=’{.metadata.annotations}’
If cainjector-managed, verify cert-manager (and specifically the cainjector controller) is healthy: see test_cert_manager.py
If not cainjector-managed, find what is expected to re-inject the caBundle (a Job, a Helm hook, a manual process) and check whether it last ran successfully
Domsed mutating-webhook runbook: Confluence page 1368555604 — opens with “It’s cert-manager. It’s always cert-manager.”
On an ERROR naming a failed list call: verify the toolkit’s ServiceAccount has list/get RBAC on the named resource (see Required Permissions) and that the API server is otherwise healthy (kubectl get –raw /healthz)
- Resolution Steps:
For cainjector-managed webhooks: fix the underlying Certificate/Issuer (see test_cert_manager_resources.py) so cainjector can re-populate the caBundle; no direct edit is needed once cert-manager is healthy again
For manually-managed webhooks: regenerate the caBundle and patch it onto the *WebhookConfiguration directly: kubectl patch validatingwebhookconfiguration <name> –type=json
-p=’[{“op”:”replace”,”path”:”/webhooks/0/clientConfig/caBundle”,”value”:”<new-b64-bundle>”}]’
Confirm admission is restored by re-running a request that exercises the webhook (e.g. creating the resource kind it validates/mutates)
- Required Permissions:
kubectl read access to MutatingWebhookConfiguration and ValidatingWebhookConfiguration (cluster-scoped)
- See also:
test_tls_secret_expiration.py — storage-layer cert expiry (RE-3163); this check reuses its parse_pem_bundle helper (lib/cert_parsing.py)
test_cert_manager_resources.py — cert-manager Certificate/Issuer readiness (Ticket 2); check this first when a cainjector-managed caBundle is expiring
test_cert_manager.py — cert-manager controller health; if cainjector is broken, this check (webhook caBundle expiry) is how you notice
test_mutations_patch.py — Domsed MutatingWebhookConfiguration detection; the same webhook configs this check inspects for caBundle expiry
cert-manager cainjector docs: https://cert-manager.io/docs/concepts/ca-injector/
Confluence: cert-manager runbook, page 2716729345
Confluence: Domsed mutating-webhook runbook, page 1368555604
Incident: OT-3385 (cloud-braze, P0, data-plane-workloads-webhook-server caBundle expiry)
- domino_admin_toolkit.checks.test_webhook_ca_bundle_expiration.webhook_ca_bundle_data(k8s_client)
Collect webhook admission-config caBundle expiry data cluster-wide.