Packaging & Config

cert-manager

Opérateur Kubernetes CNCF Graduated pour certificats TLS automatiques - Let's Encrypt HTTP-01/DNS-01, Vault, CA privée, renouvellement auto. Apache 2.0.

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

ComposantValeur
CRDsIssuer, ClusterIssuer, Certificate, CertificateRequest, Order, Challenge
IssuersLet's Encrypt (ACME), Vault, Venafi, CA, SelfSigned
Challenge ACMEHTTP-01 (via Ingress), DNS-01 (15+ providers DNS)
RenouvellementAutomatique (30 jours avant expiration par défaut)
Namespace installcert-manager

Prérequis

RessourceValeur
Kubernetes1.22+
Ingress controllerRequis 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

Newsletter · 2 000+ abonnés

Reste au courant de ce qui bouge en prod

RudeOps veille devops hebdo, droit au but.

Gratuit · Sans spam · Désinscription en un clic