Introduction
Les défaillances de certificats dans Kubernetes sont généralement silencieuses jusqu'à ce qu'un composant du plan de contrôle cesse de faire confiance à sa propre identité TLS ou qu'une charge de travail rejette un certificat de service expiré. Ce guide vous propose un flux de travail pratique, orienté commandes, pour la surveillance et l'alerte des certificats Kubernetes : de la découverte des certificats existants dans votre cluster, à la surveillance de leur expiration à l'aide de métriques et de tableaux de bord, jusqu'à la réponse sécurisée lorsqu'une alerte se déclenche.
Vous y trouverez des commandes concrètes, des sorties attendues, des requêtes Prometheus, des règles d'alerte et des étapes de récupération. L'objectif est la sécurité opérationnelle : observez avant de modifier, limitez le rayon d'impact, protégez les données sensibles et vérifiez chaque correction.
Cet article s'adresse aux développeurs, consultants DevOps et équipes techniques de startups qui exploitent des clusters Kubernetes et doivent prévenir les pannes liées aux certificats.
Inventaire de la version et de l'environnement
Avant de surveiller ou de modifier quoi que ce soit, capturez l'environnement du cluster. Les différentes distributions et versions de Kubernetes gèrent les certificats différemment, votre première étape consiste donc à identifier ce avec quoi vous travaillez.
Identifier la version du cluster et la distribution
Exécutez la commande suivante pour obtenir la version du serveur :
kubectl version --short
Sortie attendue (exemple pour un cluster Kubernetes vanilla) :
Client Version: v1.27.3
Kustomize Version: v5.0.1
Server Version: v1.27.3
Si vous utilisez un service managé tel qu'Amazon EKS, Google GKE ou Azure AKS, la version du serveur est également renvoyée, mais la gestion des certificats diffère. Par exemple, EKS renouvelle automatiquement les certificats de service du kubelet, mais le certificat du serveur d'API du plan de contrôle est géré par le fournisseur cloud et vous ne pouvez pas l'inspecter directement. Sur un cluster kubeadm, les certificats du plan de contrôle sont stockés sous forme de fichiers dans /etc/kubernetes/pki et peuvent être vérifiés avec openssl.
Pour déterminer si votre cluster a été créé avec kubeadm, recherchez la ConfigMap kubeadm :
kubectl get configmap kubeadm-config -n kube-system
Si cela renvoie une ConfigMap, vous êtes sur un cluster kubeadm. Si vous obtenez NotFound, vous êtes probablement sur une distribution managée ou personnalisée.
Lister les ressources liées aux certificats
Inspectez les objets CertificateSigningRequest. Ils sont utilisés lorsque des certificats sont demandés via l'API Kubernetes.
kubectl get csr
Sortie attendue lorsqu'il y a des demandes en attente :
NAME AGE SIGNERNAME REQUESTOR REQUESTEDDURATION CONDITION
my-csr 2m kubernetes.io/kube-apiserver-client system:node:worker1 <none> Pending
Une condition Pending signifie qu'un administrateur du cluster doit approuver la CSR. Une condition Denied signifie que la demande a été rejetée, et vous devez en rechercher la raison.
Si vous utilisez cert-manager, listez les ressources Certificate dans tous les namespaces :
kubectl get certificates --all-namespaces
Sortie possible :
NAMESPACE NAME READY SECRET AGE
app-team web-tls True web-tls-secret 30d
default internal-ca False internal-ca-secret 10d
Un état False signifie que cert-manager n'a pas délivré ou renouvelé ce certificat. La raison peut être trouvée dans les conditions de statut du Certificate ou dans les événements.
Capturer l'état actuel sans rien modifier
Avant toute intervention, enregistrez l'état actuel et l'horodatage. Utilisez un script ou un journal manuel :
kubectl get certificates --all-namespaces -o wide > cert-inventory-$(date +%Y%m%d-%H%M%S).txt
kubectl get csr -o wide > csr-inventory-$(date +%Y%m%d-%H%M%S).txt
Cela vous donne un point de restauration et une piste d'audit. Protégez les fichiers contenant du matériel de clé privée : ne les stockez jamais dans un emplacement partagé sans chiffrement.
Prérequis pour la surveillance
Pour suivre les exemples de cet article, assurez-vous d'avoir :
kubectlconfiguré avec des autorisations RBAC d'administrateur de cluster ou suffisantes pour lire les secrets et les métriques.opensslinstallé pour l'inspection directe des fichiers de certificats.curletjqpour interroger les points de terminaison de métriques.- Si vous utilisez Prometheus, l'accès au navigateur d'expressions Prometheus ou à Grafana.
Chemin de configuration sécurisé
Modifier la configuration des certificats peut rompre la communication du cluster. Suivez un chemin sûr : inspectez, sauvegardez, modifiez un élément limité, vérifiez et sachez comment revenir en arrière.
Inspecter les dates d'expiration des certificats
Pour un cluster kubeadm, les certificats du plan de contrôle se trouvent généralement dans /etc/kubernetes/pki. Vérifiez leur expiration à l'aide d'une boucle sur un nœud du plan de contrôle.
Connectez-vous en SSH au nœud du plan de contrôle et exécutez :
find /etc/kubernetes/pki -type f -name "*.crt" -print0 | while IFS= read -r -d '' cert; do
echo "$cert"
openssl x509 -in "$cert" -noout -enddate
done
Exemple de sortie :
/etc/kubernetes/pki/apiserver.crt
notAfter=Oct 12 09:30:00 2024 GMT
/etc/kubernetes/pki/ca.crt
notAfter=Nov 1 10:00:00 2029 GMT
Le ca.crt a généralement une longue validité, mais apiserver.crt expire annuellement s'il n'est pas renouvelé.
Renouveler un certificat en toute sécurité avec kubeadm
Si vous devez renouveler le certificat du serveur d'API avant son expiration (ou après), utilisez les commandes de renouvellement intégrées de kubeadm. Tout d'abord, vérifiez ce qui serait renouvelé (simulation) :
kubeadm certs renew apiserver --dry-run
Si la commande est prise en charge, elle montre quels certificats seraient renouvelés sans apporter de modifications. Si --dry-run n'est pas disponible dans votre version de kubeadm, effectuez d'abord une sauvegarde de /etc/kubernetes/pki :
cp -a /etc/kubernetes/pki /etc/kubernetes/pki-backup-$(date +%Y%m%d)
Ensuite, exécutez le renouvellement :
kubeadm certs renew apiserver
Après le renouvellement, redémarrez le pod statique kube-apiserver. Habituellement, kubeadm le fait automatiquement, mais vous pouvez le forcer :
crictl ps | grep kube-apiserver
# Notez l'ID du conteneur et tuez-le ; kubelet le redémarrera.
Alternativement, sur les systèmes avec systemd, redémarrez kubelet :
systemctl restart kubelet
Vérifiez que le nouveau certificat est chargé en consultant les journaux de kube-apiserver ou en interrogeant le serveur d'API :
kubectl get --raw /readyz
Sortie attendue : ok
Renouveler un certificat de service avec cert-manager
Si vous utilisez cert-manager, ne modifiez pas manuellement une ressource Certificate à moins de bien comprendre les implications. Pour déclencher un renouvellement manuellement (pour un test ou une urgence), vous pouvez supprimer le Secret associé au Certificate.
Tout d'abord, sauvegardez le Secret :
kubectl get secret web-tls-secret -n app-team -o yaml > web-tls-secret-backup.yaml
Ensuite, supprimez-le. cert-manager délivrera un nouveau certificat et créera un nouveau Secret en quelques minutes, selon l'émetteur.
kubectl delete secret web-tls-secret -n app-team
Surveillez l'état du Certificate :
kubectl get certificate web-tls -n app-team -w
Attendez que READY devienne True. Vérifiez ensuite la nouvelle date d'expiration du certificat :
kubectl get secret web-tls-secret -n app-team -o jsonpath='{.data.tls\.crt}' | base64 -d | openssl x509 -noout -enddate
Sortie attendue : une nouvelle date notAfter.
Protéger les secrets et le matériel privé
N'affichez jamais une clé privée dans le terminal lors de sessions partagées. Lors de l'inspection d'un secret TLS, utilisez jsonpath pour extraire uniquement le certificat, pas la clé privée, sauf en cas de nécessité absolue. Si vous avez besoin de la clé privée, redirigez-la vers un fichier avec des permissions restrictives :
umask 077
kubectl get secret web-tls-secret -n app-team -o jsonpath='{.data.tls\.key}' | base64 -d > tls.key
Supprimez ensuite le fichier après utilisation.
Vérification et diagnostics
La surveillance ne consiste pas seulement à collecter des métriques ; vous devez vérifier que votre pile de surveillance voit les bonnes données et que les alertes se déclenchent comme prévu.
Vérifier l'exposition des métriques
Les composants Kubernetes exposent des métriques pour leurs propres certificats. Par exemple, le kube-apiserver expose apiserver_certificate_expiration_seconds en tant que jauge. Pour vérifier cette métrique depuis un nœud du plan de contrôle, utilisez kubectl get --raw :
kubectl get --raw /metrics | grep apiserver_certificate_expiration_seconds
Exemple de sortie :
# HELP apiserver_certificate_expiration_seconds [ALPHA] Expiration timestamps of API server certificates.
# TYPE apiserver_certificate_expiration_seconds gauge
apiserver_certificate_expiration_seconds{name="apiserver"} 2.592e+06
apiserver_certificate_expiration_seconds{name="apiserver-etcd-client"} 2.592e+06
Si vous ne voyez pas cette métrique, votre version de kube-apiserver peut ne pas l'exposer (elle a été introduite dans Kubernetes 1.23 en état alpha, passée en bêta en 1.26, et est stable dans les versions ultérieures). Activez le feature gate CertificateExpiration si nécessaire.
Pour cert-manager, il expose des métriques sur /metrics sur son pod contrôleur (port par défaut 9402). Pour vérifier, faites un port-forward vers le pod cert-manager :
kubectl port-forward -n cert-manager deployment/cert-manager 9402:9402
Puis dans un autre terminal :
curl -s localhost:9402/metrics | grep certmanager_certificate_expiration_timestamp_seconds
Exemple de sortie attendue :
certmanager_certificate_expiration_timestamp_seconds{name="web-tls",namespace="app-team"} 1.728e+09
La valeur est un horodatage Unix ; vous pouvez le convertir avec date -d @1728000000.
Interroger Prometheus pour l'expiration des certificats
Si Prometheus collecte ces métriques, vous pouvez écrire des requêtes pour alerter sur les expirations imminentes. Pour les certificats du kube-apiserver, la métrique est apiserver_certificate_expiration_seconds. Pour obtenir les certificats expirant dans moins de 30 jours, utilisez :
apiserver_certificate_expiration_seconds - time() < 30 * 24 * 3600
Cela renvoie un vecteur de certificats avec un délai avant expiration inférieur à 30 jours. Si la requête ne renvoie aucune donnée, soit votre collecte ne fonctionne pas, soit tous les certificats ont plus de 30 jours restants.
Pour cert-manager, la métrique est certmanager_certificate_expiration_timestamp_seconds. La requête pour une expiration dans moins de 30 jours est :
(certmanager_certificate_expiration_timestamp_seconds - time()) < 30 * 24 * 3600
De plus, cert-manager possède une métrique certmanager_certificate_ready_status qui vaut 1 quand le certificat est prêt et 0 sinon. Alertez également sur celle-ci.
Configurer des règles d'alerte
Voici un exemple de règle d'alerte Prometheus pour les certificats cert-manager expirant dans les 30 jours :
groups:
- name: kubernetes-certificates
rules:
- alert: CertificateExpiringSoon
expr: (certmanager_certificate_expiration_timestamp_seconds - time()) < 30 * 24 * 3600
for: 5m
labels:
severity: warning
annotations:
summary: "Certificate {{ $labels.name }} in namespace {{ $labels.namespace }} expires in less than 30 days"
description: "The certificate {{ $labels.name }} in namespace {{ $labels.namespace }} will expire at {{ $value | humanizeTimestamp }}."
- alert: CertificateNotReady
expr: certmanager_certificate_ready_status == 0
for: 5m
labels:
severity: critical
annotations:
summary: "Certificate {{ $labels.name }} in namespace {{ $labels.namespace }} is not ready"
Pour les certificats du kube-apiserver, une règle similaire :
- alert: ApiServerCertificateExpiringSoon
expr: (apiserver_certificate_expiration_seconds - time()) < 30 * 24 * 3600
for: 5m
labels:
severity: warning
annotations:
summary: "API server certificate {{ $labels.name }} expires in less than 30 days"
Vérifications diagnostiques en cas de défaillance
Si une alerte se déclenche ou si vous soupçonnez un problème de certificat, exécutez ces diagnostics :
- Vérifiez directement l'état du certificat :
kubectl get certificate <name> -n <namespace> -o yaml
Recherchez status.conditions avec type: Ready et status: False. Le champ message indique souvent la raison de l'échec.
- Vérifiez les événements dans le namespace :
kubectl get events -n app-team --sort-by=.lastTimestamp
- Pour les problèmes de certificat de service du kubelet sur un nœud, consultez les journaux du kubelet :
journalctl -u kubelet -n 100 --no-pager
- Pour les composants du plan de contrôle, consultez les journaux des pods statiques :
kubectl logs -n kube-system kube-apiserver-<node-name>
Remplacez <node-name> par le nom réel du nœud du plan de contrôle.
Modes de défaillance et récupération
Les certificats échouent de manière prévisible. Voici les modes de défaillance courants et les étapes de récupération pas à pas.
Certificat du serveur d'API expiré
Symptôme : kubectl ne peut pas se connecter ; le serveur d'API renvoie des erreurs TLS ou ne démarre pas. Dans les journaux de kube-apiserver, vous pouvez voir :
TLS handshake error from 10.0.0.5:53210: remote error: tls: bad certificate
ou
Error: x509: certificate has expired or is not yet valid
Récupération sur un cluster kubeadm :
- Connectez-vous en SSH au nœud du plan de contrôle.
- Sauvegardez le répertoire PKI :
cp -a /etc/kubernetes/pki /etc/kubernetes/pki-backup-$(date +%Y%m%d-%H%M%S)
- Exécutez
kubeadm certs renew allpour renouveler tous les certificats :
kubeadm certs renew all
- Redémarrez le kube-apiserver et les autres composants du plan de contrôle :
crictl ps | grep -E 'kube-apiserver|kube-controller-manager|kube-scheduler' | awk '{print $1}' | xargs -r crictl stop
Ou si vous utilisez systemd, redémarrez kubelet :
systemctl restart kubelet
- Vérifiez en contrôlant la disponibilité du serveur d'API :
kubectl get --raw /readyz
Certificat de service expiré délivré par cert-manager
Symptôme : L'Ingress ou le service renvoie des erreurs d'expiration de certificat dans le navigateur ou les clients refusent la connexion. Le cert-manager peut avoir échoué à renouveler en raison de problèmes DNS ou d'émetteur.
Récupération :
- Vérifiez la ressource Certificate :
kubectl describe certificate web-tls -n app-team
Recherchez les événements de statut indiquant un échec de renouvellement, tels que Issuing ou Failed.
- Consultez les journaux de cert-manager :
kubectl logs -n cert-manager -l app=cert-manager --tail=100
- Raisons courantes : échec du défi ACME DNS01, émetteur mal configuré, dépassement de limite de débit. Corrigez le problème sous-jacent (par exemple, mettez à jour les informations d'identification DNS, augmentez la limite de débit).
- Si le certificat est déjà expiré et que cert-manager ne peut pas le renouveler automatiquement, vous pouvez forcer une nouvelle émission en supprimant le Secret comme décrit dans le Chemin de configuration sécurisé. Mais assurez-vous d'abord que l'émetteur est sain.
Expiration du certificat client du kubelet
Sur les nœuds, le kubelet utilise un certificat client pour s'authentifier auprès du serveur d'API. S'il expire, le nœud devient NotReady et les pods sont évincés. Vérifiez l'état des nœuds :
kubectl get nodes
Si un nœud est NotReady, inspectez les journaux du kubelet :
journalctl -u kubelet -n 200 | grep -i certificate
Sur les clusters kubeadm, le certificat client du kubelet est renouvelé automatiquement par défaut si le feature gate RotateKubeletClientCertificate est activé (il est activé par défaut depuis Kubernetes 1.20). Sinon, vous devrez peut-être approuver manuellement les CSR ou renouveler le certificat du kubelet sur le nœud en supprimant les anciens fichiers de certificat et en redémarrant le kubelet.
Prévenir les défaillances : surveillance et alertes
La meilleure récupération est la prévention. Assurez-vous que vos règles d'alerte couvrent :
- Seuils d'avertissement d'expiration : 60 jours et 30 jours.
- Certificats non prêts (pour cert-manager).
- Tentatives de renouvellement échouées (par exemple, taux d'erreur élevé dans les métriques cert-manager).
- Demandes de signature de certificat en attente depuis trop longtemps.
Pour les CSR en attente, vous pouvez configurer une alerte en utilisant l'API Kubernetes via un exportateur personnalisé ou en utilisant kube-state-metrics s'il expose des métriques CSR (non disponible par défaut). À la place, vous pouvez avoir un cron job qui vérifie les CSR en attente et envoie une alerte.
Exemple de commande cron job :
kubectl get csr | grep Pending && echo "Alert: pending CSR" | mail -s "Pending CSR" [email protected]
Il est préférable d'intégrer cela à votre système d'alerte.
Liste de contrôle des opérations
Utilisez cette liste de contrôle avant et pendant les opérations sur les certificats. Elle est conçue pour minimiser les risques et garantir la vérification.
Avant tout changement
- [ ] Enregistrez la version actuelle du cluster et la distribution (
kubectl version --short). - [ ] Inventoriez toutes les ressources Certificate et CSR (
kubectl get certificates --all-namespaces,kubectl get csr). - [ ] Sauvegardez les Secrets et fichiers PKI pertinents (par exemple,
cp -a /etc/kubernetes/pki /etc/kubernetes/pki-backup-<date>). - [ ] Confirmez que vous avez les autorisations nécessaires pour effectuer l'opération et un plan de restauration.
- [ ] Informez les parties prenantes si le changement peut entraîner une brève interruption.
Après tout changement
- [ ] Vérifiez que la ressource est dans l'état attendu (par exemple, Certificate READY=True).
- [ ] Vérifiez la nouvelle date d'expiration du certificat avec
openssl x509 -noout -enddate. - [ ] Testez les connexions client vers le service ou le serveur d'API.
- [ ] Vérifiez les journaux pour détecter des erreurs dans le composant concerné.
- [ ] Mettez à jour la documentation et les seuils de surveillance si nécessaire.
Exemple de scénario réalisé
Supposons que le certificat web-tls dans le namespace app-team expire dans 10 jours et est géré par cert-manager. Vous recevez une alerte de Prometheus.
Suivez cette séquence :
- Vérifiez que l'alerte est réelle :
kubectl get certificate web-tls -n app-team -o jsonpath='{.status.notAfter}'
Sortie attendue : un horodatage dans les 10 jours.
- Vérifiez les journaux de cert-manager pour les échecs de renouvellement :
kubectl logs -n cert-manager -l app=cert-manager --tail=100 | grep web-tls
Si vous voyez une erreur comme failed to perform self check, cela peut être un problème temporaire.
- Déclenchez un renouvellement manuel en supprimant le Secret (après sauvegarde) :
kubectl get secret web-tls-secret -n app-team -o yaml > web-tls-secret-backup.yaml
kubectl delete secret web-tls-secret -n app-team
- Attendez que le certificat soit prêt :
kubectl wait --for=condition=ready certificate/web-tls -n app-team --timeout=300s
- Vérifiez la nouvelle expiration du certificat :
kubectl get secret web-tls-secret -n app-team -o jsonpath='{.data.tls\.crt}' | base64 -d | openssl x509 -noout -enddate
- Confirmez que le service HTTP fonctionne (s'il est exposé via Ingress) :
curl -v https://your-app.example.com 2>&1 | grep -E 'expire date|SSL certificate verify ok'
Cela termine la récupération.
Conclusion
La surveillance des certificats Kubernetes n'est pas une configuration unique ; elle nécessite une observation continue, des alertes et un chemin de récupération testé. En suivant l'inventaire de version, les changements de configuration sécurisés, les techniques de vérification et les étapes de récupération en cas de défaillance de cet article, vous pouvez réduire le risque de pannes liées aux certificats.
Commencez par une vérification à faible risque : choisissez un certificat, enregistrez son expiration actuelle, configurez une collecte de métriques pour celui-ci et créez une alerte de test. Simulez ensuite une expiration en ajustant le seuil de l'alerte pour confirmer que la notification fonctionne. Cela vous donne confiance en votre système avant qu'un incident réel ne se produise.
Rappelez-vous les principes : observez avant de modifier, limitez le rayon d'impact, protégez les secrets, vérifiez les résultats et documentez la récupération. Avec ces pratiques, vos certificats Kubernetes ne seront pas la cause de votre prochaine alerte à 3 heures du matin.