What to do when mTLS breaks or is compromised. Read this BEFORE you have an incident. Covers the four most common scenarios.
Audience: operator on-call, super-admin. Scope: source-side mTLS, internal gRPC mTLS, cert rotation, CA compromise. Last reviewed: 2026-06-16 (initial draft, pre-M14-backend ship).
| Symptom | Likely cause | Jump to |
|---|---|---|
| Source can't connect, 401 from ingestd | cert expired | Cert expired |
| 401 from ingestd after a recent change | cert revoked, or wrong CN/SAN | Cert revoked |
mTLSHandshakeErrorsHigh alert firing |
clock skew, missing CA, or wrong issuer | Handshake errors spiking |
| Private key leaked (Slack DM, repo push, etc.) | key compromise | Private key compromise |
| Root CA key leaked (the worst day of your life) | CA compromise | CA compromise |
Symptoms: source operator reports 401s. PromQL CertExpired
alert fired. ingestd logs show tls: failed to verify client's
certificate: x509: certificate has expired.
Cause: the source's leaf cert passed its notAfter. cert-manager
auto-rotates serving certs (90d, renew at 30d), but source certs
are issued on demand — no auto-rotation. Operator must re-issue.
Resolution:
<company> →
<source> → Cert tab.mtls_required=true and there's an existing cert: re-issue
via "Auto-generate" or "Upload CSR". This creates a new leaf signed
by the current intermediate..zip with cert + chain + key).If the source is one of OUR services (ingestd, routerd,
deliverd-*): cert-manager handles this automatically. The 30-day
renewal window means the cert is re-issued well before expiry. If
you see a serving cert expire, check cert-manager logs and the
Certificate CR status.
Symptoms: source reports 401s after a recent revoke. PromQL
CertRevoked alert fired. CRL may not have propagated yet.
Cause: revocation is propagated via CRL, which is checked by the verifier. The CRL refresh interval in cert-manager defaults to 600s (10 min). Within that window, a revoked cert may still validate.
Resolution:
openssl x509 -in <cert> -noout -text | grep -A2
"CRL Distribution".Mitigation: the spec calls for OCSP (real-time) in v2, which removes the 10-min lag. For now, accept the lag.
Symptoms: PromQL mTLSHandshakeErrorsHigh > 1% for 5 min.
ingestd logs show many tls: failed to verify client's certificate
with various x509 errors.
Cause (most likely first):
now to be within notBefore–notAfter.
Check NTP sync on both sides.clientAuth
EKU. Generator issue.Diagnosis:
# From a source host, test against ingestd
openssl s_client -connect ingestd:8443 -cert source.crt -key source.key -CAfile intermediate-ca.crt
# Look for "Verify return code: 0 (ok)" or the specific error
# Common: "certificate has expired", "unable to get local issuer
# certificate", "wrong issuer"
Resolution by cause:
| Cause | Fix |
|---|---|
| Clock skew | Sync NTP. Verify chronyc tracking or ntpq -p on both sides. |
| Missing intermediate | Re-import intermediate into K8s Secret. Restart ingestd. |
| Wrong issuer | Re-issue source cert against current intermediate. |
| Key usage | Re-generate CSR with extendedKeyUsage=clientAuth in the extfile. |
Symptoms: a source's private key was leaked (pushed to a public repo, stolen from a backup, exfiltrated). You may or may not have a specific incident — sometimes you find out later.
Severity: high. The attacker can impersonate the source until you revoke.
Immediate response (within 1 hour):
<source> → Cert tab → Revoke.
Confirm with typed slug. Within ~10 min, the CRL propagates and
the cert stops validating.audit_log for cert.revoke events. Look for
any other activity from the same actor or IP that might indicate
broader compromise.Within 24 hours:
alerts table for the source_id in
the period between compromise and revocation.Symptoms: the root CA private key was leaked, or you have strong reason to believe the entire PKI is compromised. This is a catastrophic event — every cert in the system is suspect.
Severity: catastrophic. Treat as a P0.
Immediate response (within 1 hour):
fail-closed behavior). Every source falls back to
HMAC + API key (which is still secure if those weren't also
compromised).Certificate CRs, let cert-manager re-issue).Within 24 hours:
This is the worst day. Plan for it, but hopefully never have it.
These reduce the chance of needing the runbook:
| Measure | Where |
|---|---|
| Root CA key on encrypted USB in a safe | Physical security |
| Intermediate CA key in K8s sealed-secrets | Encrypted at rest |
| Serving certs rotate 90d, renew 30d | cert-manager config |
| Source certs rotate 90d (planned v1.1) | PromQL alert at 30/7/1 days |
mTLSHandshakeErrorsHigh alert at >1% for 5m |
PromQL |
CertExpiringSoon alert at 30/7/1 days |
PromQL |
CertExpired alert at expiry |
PromQL |
| Audit log on every cert issue/revoke/expire | audit_log table |
| Quarterly rotation drill (rotate one env, verify) | Manual |
| Annual root ceremony review | Manual |
Owner: super-admin team. Review this runbook quarterly.