Aller au contenu
Conteneurs & Orchestration medium

cert-manager : certificats TLS automatiques dans Kubernetes

12 min de lecture

logo kubernetes

cert-manager automatise l'émission et le renouvellement des certificats TLS dans Kubernetes. Vous décrivez le certificat voulu dans un objet Certificate, cert-manager le demande à une autorité (une CA interne, Let's Encrypt via ACME, Vault...), stocke le résultat dans un Secret et le renouvelle tout seul avant expiration. Ce guide s'adresse aux administrateurs de clusters qui veulent du HTTPS fiable sans surveiller des dates d'expiration.

Vous partirez d'un certificat auto-signé pour comprendre le mécanisme, puis monterez une CA interne et enfin des certificats Let's Encrypt rattachés à un Ingress.

  • Installer cert-manager et vérifier ses composants.
  • Émettre un premier certificat avec un Issuer self-signed.
  • Construire une CA interne pour signer tous vos services.
  • Obtenir des certificats Let's Encrypt avec les challenges HTTP-01 et DNS-01.
  • Sécuriser un Ingress automatiquement via une simple annotation.
  • Diagnostiquer un certificat qui ne s'émet pas.
  • Un cluster Kubernetes fonctionnel et kubectl configuré (un cluster k3d ou kubeadm de test convient).
  • Des notions de TLS (certificat, autorité de certification, chaîne de confiance). En cas de doute, voir le diagnostic TLS avec openssl.
  • Pour Let's Encrypt : un nom de domaine public qui pointe vers votre cluster.

cert-manager est un contrôleur Kubernetes qui ajoute des ressources dédiées aux certificats. Vous ne manipulez plus openssl ni des fichiers .pem : vous déclarez ce que vous voulez, le contrôleur s'occupe du reste.

Trois objets suffisent pour démarrer :

ObjetRôlePortée
IssuerUne source de certificats (CA, ACME, Vault...)Un seul namespace
ClusterIssuerIdentique, mais utilisable par tout le clusterCluster entier
CertificateLa demande d'un certificat concret (domaines, durée)Un namespace

Quand vous créez un Certificate, cert-manager déroule en interne une chaîne d'objets (CertificateRequest, puis Order et Challenge pour ACME). Vous n'avez pas à les créer vous-même : ils servent au suivi et au débogage. Le certificat final atterrit dans un Secret de type kubernetes.io/tls, prêt à être monté par vos pods ou consommé par un Ingress.

L'installation se fait avec un unique manifeste qui déploie les contrôleurs, le webhook, le cainjector et les CRD. Épinglez une version précise plutôt que latest.

Fenêtre de terminal
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.20.3/cert-manager.yaml

Attendez que les trois déploiements soient disponibles :

Fenêtre de terminal
kubectl -n cert-manager wait --for=condition=Available deploy --all --timeout=180s

La sortie doit lister cert-manager, cert-manager-webhook et cert-manager-cainjector avec la condition Available. Vérifiez la version déployée :

Fenêtre de terminal
kubectl -n cert-manager get deploy cert-manager \
-o jsonpath='{.spec.template.spec.containers[0].image}'
# quay.io/jetstack/cert-manager-controller:v1.20.3

L'émetteur self-signed ne dépend d'aucune autorité externe : chaque certificat se signe lui-même. Ce n'est pas utilisable en production, mais c'est parfait pour valider l'installation et pour amorcer une CA interne.

Créez un ClusterIssuer self-signed puis un Certificate de test :

premier-certificat.yaml
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: selfsigned
spec:
selfSigned: {}
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: test-cert
namespace: default
spec:
secretName: test-cert-tls
issuerRef:
name: selfsigned
kind: ClusterIssuer
commonName: test.example.com
dnsNames:
- test.example.com

Appliquez et observez l'état du certificat :

Fenêtre de terminal
kubectl apply -f premier-certificat.yaml
kubectl get certificate test-cert \
-o jsonpath='{.status.conditions[?(@.type=="Ready")].status}'
# True

Un statut Ready: True signifie que le Secret test-cert-tls contient désormais une clé et un certificat. C'est ce Secret que vos applications ou votre Ingress monteront.

En interne (homelab, réseau privé, environnements de test), vous voulez souvent une seule autorité de certification qui signe tous vos services. Le schéma est classique : un émetteur self-signed amorce une CA racine, et cette CA devient à son tour un ClusterIssuer.

  1. Créer la CA racine signée par l'émetteur self-signed (isCA: true) :

    ca-interne.yaml
    apiVersion: cert-manager.io/v1
    kind: Certificate
    metadata:
    name: ca-root
    namespace: cert-manager
    spec:
    isCA: true
    commonName: mon-lab-ca
    secretName: mon-lab-ca-secret
    issuerRef:
    name: selfsigned
    kind: ClusterIssuer
  2. Déclarer un ClusterIssuer basé sur cette CA :

    apiVersion: cert-manager.io/v1
    kind: ClusterIssuer
    metadata:
    name: mon-lab-ca
    spec:
    ca:
    secretName: mon-lab-ca-secret
  3. Émettre un certificat applicatif signé par la CA, avec plusieurs SAN et un renouvellement anticipé :

    apiVersion: cert-manager.io/v1
    kind: Certificate
    metadata:
    name: app-cert
    namespace: default
    spec:
    secretName: app-cert-tls
    issuerRef:
    name: mon-lab-ca
    kind: ClusterIssuer
    commonName: app.interne.lab
    dnsNames:
    - app.interne.lab
    - api.interne.lab
    duration: 2160h # 90 jours
    renewBefore: 360h # renouvelle 15 jours avant l'expiration

Vérifiez que le certificat est bien signé par votre CA, pas par lui-même :

Fenêtre de terminal
kubectl get secret app-cert-tls -o jsonpath='{.data.tls\.crt}' \
| base64 -d | openssl x509 -noout -issuer
# issuer=CN = mon-lab-ca

Distribuez ensuite le certificat public de mon-lab-ca-secret aux postes clients (navigateurs, curl) pour qu'ils fassent confiance à cette CA. Tous les services signés par elle seront alors reconnus sans avertissement.

Pour des services exposés sur Internet, Let's Encrypt délivre des certificats gratuits et reconnus par tous les navigateurs. cert-manager parle le protocole ACME et prouve que vous contrôlez le domaine via un challenge.

Deux challenges existent :

  • HTTP-01 : cert-manager expose un fichier temporaire sur http://votre-domaine/.well-known/acme-challenge/. Simple, mais le domaine doit être joignable publiquement en HTTP.
  • DNS-01 : cert-manager crée un enregistrement TXT dans votre zone DNS. Plus complexe, mais seul moyen d'obtenir un certificat wildcard (*.example.com) et il fonctionne sans exposer le service.

Voici un ClusterIssuer Let's Encrypt avec le challenge HTTP-01 résolu par la classe d'Ingress :

letsencrypt.yaml
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: admin@example.com
privateKeySecretRef:
name: letsencrypt-prod-account
solvers:
- http01:
ingress:
ingressClassName: nginx

Pour un wildcard, remplacez le solver par un challenge DNS-01 rattaché à votre fournisseur DNS (Cloudflare, Route 53, OVH...). La configuration exacte dépend du provider ; reportez-vous à la liste des solvers DNS-01 supportés par cert-manager.

L'intérêt majeur de cert-manager apparaît ici : une annotation suffit pour qu'un Ingress obtienne et renouvelle son certificat. Ajoutez cert-manager.io/cluster-issuer et un bloc tls :

ingress-tls.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: mon-app
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
ingressClassName: nginx
tls:
- hosts:
- app.example.com
secretName: app-example-tls
rules:
- host: app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: mon-app
port:
number: 80

cert-manager détecte l'annotation, crée le Certificate correspondant, résout le challenge et remplit le Secret app-example-tls. L'Ingress sert alors le trafic en HTTPS sans intervention. Pour la configuration complète d'un Ingress, voir le guide Ingress Kubernetes.

C'est le cœur de l'outil : cert-manager surveille chaque certificat et le renouvelle avant expiration. Le champ renewBefore fixe la marge (par défaut, un tiers de la durée de vie). Vous n'avez rien à planifier : ni cron, ni script.

Inspectez les échéances d'un certificat :

Fenêtre de terminal
kubectl get certificate app-cert \
-o jsonpath='{.status.notAfter}'

À l'approche de la date, cert-manager relance une demande, met à jour le même Secret, et vos pods rechargent le nouveau certificat (immédiatement pour un Ingress, au prochain montage pour un volume).

Quand un Certificate ne passe pas à Ready, remontez la chaîne d'objets du plus proche au plus lointain. Chaque niveau porte un message d'erreur.

Fenêtre de terminal
# 1. le certificat lui-même
kubectl describe certificate app-cert
# 2. la demande sous-jacente
kubectl describe certificaterequest
# 3. pour ACME : l'ordre et le challenge
kubectl describe order
kubectl describe challenge
SymptômeCause probableSolution
failed calling webhookWebhook pas encore prêtAttendre la condition Available du webhook
Challenge HTTP-01 en pendingDomaine non joignable publiquement en HTTPVérifier DNS et exposition de l'Ingress
rateLimited sur ACMEQuota Let's Encrypt production atteintRepasser en staging le temps des tests
Secret CA absentLa CA racine n'est pas ReadyCorriger d'abord le Certificate de la CA

cert-manager manipule des clés privées : traitez-le comme un composant sensible.

  • Mettez-le à jour rapidement. La version 1.20.3 corrige une faille HIGH (GHSA-8rvj-mm4h-c258) : le ClusterRole agrégé cert-manager-edit accordait à tort le droit de créer des ressources ACME Challenge et Order, ce qui permettait de détourner la configuration d'un solver. Ne restez pas sur une version antérieure.
  • Limitez l'accès aux Secrets TLS. Un Secret kubernetes.io/tls contient la clé privée : restreignez les Role qui peuvent les lire.
  • Protégez la clé de la CA interne. Le Secret mon-lab-ca-secret peut signer n'importe quel certificat : traitez-le avec le même soin qu'une CA classique (accès minimal, sauvegarde hors cluster).
  • Préférez un ClusterIssuer par usage. Séparez l'émetteur de staging, de production et la CA interne pour cloisonner les portées.

Pour une autorité de certification pilotée hors du cluster, cert-manager peut aussi s'appuyer sur Vault PKI comme provider.

  • cert-manager automatise l'émission et le renouvellement des certificats TLS dans Kubernetes.
  • Trois objets suffisent : Issuer/ClusterIssuer (la source) et Certificate (la demande).
  • L'émetteur self-signed valide l'installation ; la CA interne signe tous vos services privés.
  • Let's Encrypt via ACME délivre des certificats publics : HTTP-01 pour un domaine simple, DNS-01 pour un wildcard.
  • Une annotation cert-manager.io/cluster-issuer suffit à sécuriser un Ingress en HTTPS.
  • Passez toujours par le staging Let's Encrypt avant la production, et gardez cert-manager à jour (faille 1.20.3).

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracking. Un soutien, même symbolique, m'aide à couvrir l'hébergement et à garder ces ressources gratuites. Merci pour votre appui.

Le formulaire ne s'affiche pas ? Ouvrir Ko-fi dans un onglet.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn