Runbook: TLSCertExpiresSoon¶
Alerte : TLSCertExpiresSoon (PrometheusRule, severity warning à J-30, critical à J-7)
Symptôme :
Un certificat TLS (ingress, Keycloak, Harbor) expire dans moins de 30 jours et n'a pas été renouvelé automatiquement.
Severity : 🟡 warning à J-30, 🔴 critical à J-7
Diagnostic¶
1. Identifier le certificat qui expire¶
export KUBECONFIG=/etc/rancher/k3s/k3s.yaml
# Via cert-manager
kubectl get certificate -A \
-o custom-columns=NAMESPACE:.metadata.namespace,NAME:.metadata.name,READY:.status.conditions[0].status,NOT_AFTER:.status.notAfter
# Via les secrets TLS directement
for s in $(kubectl get secret -A -o json | jq -r '.items[] | select(.type=="kubernetes.io/tls") | "\(.metadata.namespace)/\(.metadata.name)"'); do
NS=$(echo $s | cut -d/ -f1)
NAME=$(echo $s | cut -d/ -f2)
NOT_AFTER=$(kubectl get secret -n $NS $NAME -o jsonpath='{.data.tls\.crt}' | base64 -d | openssl x509 -noout -enddate 2>/dev/null | cut -d= -f2)
echo "$NS/$NAME -> $NOT_AFTER"
done | sort
2. Vérifier cert-manager est sain¶
3. Vérifier le Issuer/ClusterIssuer¶
Causes fréquentes + fix¶
| Cause | Symptôme | Fix |
|---|---|---|
| ACME rate limit Let's Encrypt | too many certificates already issued |
Utiliser staging pendant les tests + attendre 1 semaine. |
| HTTP-01 challenge bloqué | self-check failed |
Vérifier que l'Ingress acme-http-solver est reachable depuis internet (80/TCP). |
| DNS-01 challenge non configuré | Pour wildcard certs | Configurer le DNS provider (Cloudflare, Route53) dans ClusterIssuer. |
| Secret TLS corrompu | failed to parse certificate |
kubectl delete secret <name> → cert-manager recrée. |
| Certificate request bloqué | CertificateRequest en Pending |
Voir kubectl describe certificaterequest <name>. |
| Lost Let's Encrypt account key | 401 Unauthorized |
Recréer le ClusterIssuer avec nouveau privateKey. |
Fix d'urgence (< 10 min)¶
Forcer un renouvellement manuel (cert-manager)¶
# Supprime le cert, cert-manager le recrée
kubectl delete certificate -n <namespace> <cert-name>
# Ou annotation pour force renew
kubectl annotate certificate -n <namespace> <cert-name> \
cert-manager.io/issue-temporary-certificate=true --overwrite
Si Let's Encrypt prod rate-limited — temporairement switcher vers staging¶
Jamais en prod long terme — uniquement pendant investigation.
Fix pérenne (R02)¶
- cert-manager auto-renewal doit être sain :
- Tous les certs doivent avoir
renewBefore: 720h(30 jours avant expiration) - Monitoring alertes précoces : PrometheusRule à J-30 pas J-7
- Wildcard cert via DNS-01 pour éviter les issues HTTP-01 par subdomain
Jamais : copier un cert en live avec kubectl create secret tls. Toujours via cert-manager + Git.
Prévention¶
- PrometheusRule précoce : alerte à J-30 via
probe_ssl_earliest_cert_expiry(blackbox-exporter) - Playwright test hebdomadaire : vérifier HTTPS root + expiry > 7j
- Documentation : liste des certs critiques + qui les renouvelle
Lessons learned¶
- Let's Encrypt a des rate limits stricts (50 certs/semaine/domain, 5 duplicates/week). Utiliser le staging pour tous les tests.
Liens utiles¶
- cert-manager docs
- Let's Encrypt rate limits
- Monitoring : dashboard Dashboards "TLS expiry"