DR Drill Log — Certificate Expiry (2026-04-22)
Evidence artifact for Scenario: Certificate
Expiry. Exercises the
cert-manager-failed degenerate case: cert-manager is down while a
component's mTLS cert is minutes from expiry, and the only way back
is manual re-issue from the CA Secret.
Infrastructure
| Item |
Value |
| Cluster |
Two-droplet k3s, dcs-dr-ctrl + dcs-dr-edge, DigitalOcean NYC1 |
| Chart revision |
sha-257f3dd |
| cert-manager |
v1.16.2 (patched --cluster-resource-namespace=dcs-system) |
| mTLS |
mtls.enabled=true, certManager.clusterIssuer=true, duration=24h, renewBefore=8h |
| CA Secret |
cloud-native-dcs-mtls-ca in dcs-system (auto-created) |
| Target component |
Gateway (cloud-native-dcs-gateway-mtls Certificate / Secret) |
Drill procedure (wall clock timestamps are UTC)
| Step |
Action |
Timestamp |
Notes |
| 1 |
Baseline dcs health green |
19:20:33 |
Pre-flight |
| 2 |
Scaled cert-manager + cert-manager-webhook + cert-manager-cainjector to 0 replicas |
19:20:40 |
T0 — "cert-manager failed" simulated |
| 3 |
Patched cloud-native-dcs-gateway-mtls Secret tls.crt with garbage (Zm9vYmFyCg==); kubectl rollout restart deploy/cloud-native-dcs-gateway |
19:21:05 |
Forces new pod to fail cert load so failure surfaces; old pod stays up until new one is ready |
| 4 |
kubectl delete pod on the old gateway pod to end the grace window |
19:21:25 |
Deployment now has no Ready replicas; port-forward returns EOF |
| 5 |
Confirmed cert load failure in pod logs: failed to build runtime TLS transport: loading certificate: tls: failed to find any PEM data in certificate input |
19:21:34 |
Detection confirmed |
| 6 |
Pulled tls.crt + tls.key from cloud-native-dcs-mtls-ca Secret |
19:21:40 |
Break-glass material |
| 7 |
openssl ecparam -name prime256v1 … + CSR with DNS:cloud-native-dcs-gateway{,.dcs-system.svc,.dcs-system.svc.cluster.local} + openssl x509 -req -days 1 … against the CA |
19:21:58 |
Intentional 1-day expiry forces followup once cert-manager is healthy |
| 8 |
kubectl create secret generic cloud-native-dcs-gateway-mtls --from-file=tls.crt=… --from-file=tls.key=… --from-file=ca.crt=… --type=kubernetes.io/tls --dry-run=client -o yaml \| kubectl apply -n dcs-system -f - |
19:22:10 |
Secret patched in place |
| 9 |
kubectl rollout restart deploy/cloud-native-dcs-gateway; rollout status successfully rolled out |
19:22:43 |
T1 — service restored |
| 10 |
dcs health green via port-forward |
19:23:13 |
End-to-end verification |
| 11 |
Scaled cert-manager back to 1; deleted the manually-issued Secret; cert-manager re-created it within ~10 s; rolled the gateway to pick up the canonical cert |
19:24:00 |
Returned to steady state |
| 12 |
Ran dcs qualify dr --fail-on-deviation; signed qualification qual-20260422-192458-ca6ef6e0 |
19:24:58 |
Seals the drill |
Measured RTO
| Metric |
Value |
| cert-manager-down to gateway-healthy (wall clock) |
123 s |
| Detection window (cert-manager-down to pod logs showing TLS error) |
~54 s |
| Recovery window (openssl + kubectl apply + rollout) |
~69 s |
The bulk of the wall clock is openssl invocation + kubectl
round-trips. A templated re-issue-component-cert.sh script checked
into ops would compress this substantially — file that ticket after
the drill.
Evidence trail
| Artifact |
Value |
| Qualification AuditRecord |
audit-rkm22 (dr-qual-20260422-192458-ca6ef6e0) |
| Target Certificate |
cloud-native-dcs-gateway-mtls in dcs-system |
| CA fingerprint (SHA-256) |
FC:5F:FB:86:10:E2:5D:66:70:39:7A:A7:B6:32:C9:4B:3B:FD:59:95:1F:6C:1D:43:E0:52:77:9C:B6:B0:34:FD |
Follow-ups
- The Certificate Expiry section of dr-runbook.md
was flipped from "blocked on #168 / tabletop-only" to a drilled
procedure with the full openssl + Secret-patch sequence and the
measured 123 s wall clock.
- Break-glass certs minted with
-days 1 — if the drill clone of
this procedure is ever run on a live cluster, verify the followup
cert-manager re-issue happened before that window closes.
- Templated re-issue script: open a ticket against the deploy
skill to land
scripts/break-glass-component-cert.sh so the
openssl steps are canned and tested.
Teardown
Drill cluster destroyed via scripts/dr-drill-infra.sh down. The
qualification AuditRecord above is the only surviving artifact.