criticalFoundationSymptom-first#tls#certificate#expired#handshake

TLS certificate expired — clients failing handshake

Clients get 'certificate has expired' or verification error

Likely source:availabilitysecurity

Focused incident mode — strips away everything but this runbook.

Symptoms

  • Clients get 'certificate has expired' or verification error
  • Browser shows NET::ERR_CERT_DATE_INVALID
  • openssl s_client shows verify error after tomorrow/since-date check

Evidence to grab

Collect these artifacts before you change anything — they prove (or rule out) each cause.

  • Expiry check on the serving certificate

    echo | openssl s_client -connect <HOST>:443 2>/dev/null | openssl x509 -noout -dates
  • Server time

    date -u

Diagnostic flow

Run the steps in order, marking each claim confirmed or refuted. The evidence you gather feeds the ranked causes below.

Guided decision tree is ready.

Steps with commands, expected output, and pass/fail branches.

Ranked root causes

Evidence checklist

  • notAfter has passed on multiple clients
  • No rotation automation or rotation broke silently

Confirm before fixing

echo | openssl s_client -connect <HOST>:443 2>/dev/null | openssl x509 -noout -enddate
READ

Read the exact notAfter

Fix

openssl s_client -connect <HOST>:443 -servername <HOST> -showcerts
READ

Confirm the new cert is served after issuing the replacement via your PKI/ACME

Resolution runbook

Apply from top to bottom after the cause is confirmed. Review every command before running it — risk tags are shown on each.

1
echo | openssl s_client -connect <HOST>:443 2>/dev/null | openssl x509 -noout -enddate
READ

Prove the expiry

2
kubectl get certificate -A 2>/dev/null || true
READ

If cert-manager is in use, find the source Certificate

3
kubectl rollout restart deployment -A -l k8s-app=<app> 2>/dev/null || true
CHANGE

Restart workloads to remount the rotated secret

Prevention

  • Automate renewal at 1/3 of lifetime (cert-manager / Let's Encrypt / internal CA).
  • Alert early: min(cert.age) or Prometheus ssl_expire_days_seconds < 21.
  • Ship NTP/chrony on every host and container.
  • Have a kill-switch alert list for prod certificates in your calendar.

Commands marked READ CHANGE DESTRUCTIVE — never run DESTRUCTIVE commands against production data you cannot restore. Copy → verify → execute.