cert-manager est un opérateur Kubernetes, CNCF Graduated, qui automatise le cycle de vie complet des certificats TLS : émission, renouvellement avant expiration, et distribution dans des Secrets Kubernetes. Il supporte Let's Encrypt (via ACME HTTP-01 et DNS-01), HashiCorp Vault, Venafi, et les autorités de certification privées (CA internes). Les certificats sont définis déclarativement via les CRDs Issuer/ClusterIssuer et Certificate, et injectés automatiquement dans les ressources Ingress annotées.
Informations essentielles
Origine : Jetstack → CNCF Graduated · Licence : Apache 2.0 · Architectures : x86_64, ARM64
Liens : Site officiel · Documentation · GitHub · Releases
Support : CNCF Graduated. Maintenu activement par Jetstack/Venafi.
Stack par défaut
| Composant | Valeur |
|---|---|
| CRDs | Issuer, ClusterIssuer, Certificate, CertificateRequest, Order, Challenge |
| Issuers | Let's Encrypt (ACME), Vault, Venafi, CA, SelfSigned |
| Challenge ACME | HTTP-01 (via Ingress), DNS-01 (15+ providers DNS) |
| Renouvellement | Automatique (30 jours avant expiration par défaut) |
| Namespace install | cert-manager |
Prérequis
| Ressource | Valeur |
|---|---|
| Kubernetes | 1.22+ |
| Ingress controller | Requis pour challenge HTTP-01 (NGINX, Traefik, etc.) |
| Accès DNS (DNS-01) | API du provider DNS (Cloudflare, Route53, etc.) |
Installation
helm repo add jetstack https://charts.jetstack.io
helm repo update
helm install cert-manager jetstack/cert-manager \
--namespace cert-manager \
--create-namespace \
--set crds.enabled=true # Installe les CRDs via Helm
# Vérifier
kubectl get pods -n cert-manager
# cert-manager, cert-manager-cainjector, cert-manager-webhook Running
Alternatively via kubectl
kubectl apply -f \
https://github.com/cert-manager/cert-manager/releases/latest/download/cert-manager.yaml
Configurer Let's Encrypt
ClusterIssuer HTTP-01 (staging)
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-staging
spec:
acme:
server: https://acme-staging-v02.api.letsencrypt.org/directory
email: admin@example.com
privateKeySecretRef:
name: letsencrypt-staging-key
solvers:
- http01:
ingress:
ingressClassName: nginx
ClusterIssuer HTTP-01 (production)
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-key
solvers:
- http01:
ingress:
ingressClassName: nginx
ClusterIssuer DNS-01 avec Cloudflare
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-dns
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: admin@example.com
privateKeySecretRef:
name: letsencrypt-dns-key
solvers:
- dns01:
cloudflare:
apiTokenSecretRef:
name: cloudflare-api-token
key: api-token
# Secret Cloudflare API token
apiVersion: v1
kind: Secret
metadata:
name: cloudflare-api-token
namespace: cert-manager
type: Opaque
stringData:
api-token: "cf_xxxxxxxxxxxx"
Émettre un certificat
Via annotation Ingress (automatique)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-app
namespace: production
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
ingressClassName: nginx
tls:
- hosts:
- app.example.com
secretName: app-example-tls # cert-manager crée ce secret automatiquement
rules:
- host: app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: my-app
port:
number: 80
Via CRD Certificate (contrôle explicite)
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: app-example-tls
namespace: production
spec:
secretName: app-example-tls
issuerRef:
name: letsencrypt-prod
kind: ClusterIssuer
dnsNames:
- app.example.com
- www.app.example.com
duration: 2160h # 90 jours
renewBefore: 720h # Renouveler 30 jours avant
CA interne (self-signed pour cluster privé)
# 1. Issuer self-signed pour bootstrapper
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: selfsigned-issuer
spec:
selfSigned: {}
---
# 2. CA root du cluster
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: cluster-ca
namespace: cert-manager
spec:
isCA: true
commonName: cluster-ca
secretName: cluster-ca-secret
issuerRef:
name: selfsigned-issuer
kind: ClusterIssuer
---
# 3. Issuer utilisant la CA root
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: cluster-ca-issuer
spec:
ca:
secretName: cluster-ca-secret
Mise à jour
helm repo update
helm upgrade cert-manager jetstack/cert-manager \
--namespace cert-manager \
--reuse-values
Troubleshooting
# État des certificats
kubectl get certificates -A
kubectl describe certificate app-example-tls -n production
# État des challenges ACME en cours
kubectl get challenges -A
kubectl describe challenge <nom> -n production
# Logs cert-manager
kubectl logs -n cert-manager -l app=cert-manager --tail=50
# Certificat bloqué en NotReady
# 1. Vérifier que l'Issuer est Ready
kubectl get clusterissuer letsencrypt-prod
# 2. Vérifier que l'Ingress est accessible depuis Internet (HTTP-01)
# 3. Vérifier les credentials DNS (DNS-01)
# Forcer le renouvellement d'un certificat
# Option 1 : CLI cmctl
cmctl renew app-example-tls -n production
# Option 2 : supprimer le CertificateRequest (cert-manager en crée un nouveau)
kubectl delete certificaterequest -n production \
$(kubectl get certificaterequest -n production -o name | grep app-example-tls | head -1 | cut -d/ -f2)
Commandes utiles
kubectl get certificates -A # Tous les certificats
kubectl get clusterissuers # Issuers cluster-wide
kubectl get orders -A # Ordres ACME en cours
kubectl get challenges -A # Challenges ACME en cours
kubectl describe certificate <nom> -n <ns> # Détails et events
Ressources
- Site officiel : https://cert-manager.io
- Documentation : https://cert-manager.io/docs/
- GitHub : https://github.com/cert-manager/cert-manager
- Configuration Issuers : https://cert-manager.io/docs/configuration/
- Providers DNS-01 : https://cert-manager.io/docs/configuration/acme/dns01/
- Releases : https://github.com/cert-manager/cert-manager/releases