Aller au contenu

Add Jetstack Helm repository

PlateformeCommande
kubectl (Static Manifests)kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.13.3/cert-manager.yaml
Helm (Recommended)helm install cert-manager jetstack/cert-manager --namespace cert-manager --create-namespace --set installCRDs=true
macOS (cmctl CLI)brew install cmctl
Linux (cmctl CLI)`curl -sSL https://github.com/cert-manager/cert-manager/releases/download/v1.13.3/cmctl-linux-amd64.tar.gz \
Windows (cmctl CLI)curl.exe -L -o cmctl.exe https://github.com/cert-manager/cert-manager/releases/download/v1.13.3/cmctl-windows-amd64.exe
Verify Installationkubectl get pods -n cert-manager
# Add Jetstack Helm repository
helm repo add jetstack https://charts.jetstack.io

# Update repository
helm repo update

# Install with custom values
helm install cert-manager jetstack/cert-manager \
  --namespace cert-manager \
  --create-namespace \
  --version v1.13.3 \
  --values custom-values.yaml
```## Installation

| Commande | Description |
|---------|-------------|
| `kubectl get certificates` | Lister tous les certificats dans l'espace de noms actuel |
| `kubectl get certificates -A` | Lister les certificats dans tous les espaces de noms |
| `kubectl describe certificate <name>` | Afficher les informations détaillées du certificat |
| `kubectl get certificate <name> -o yaml` | Afficher le certificat au format YAML |
| `kubectl get issuer` | Lister tous les émetteurs dans l'espace de noms actuel |
| `kubectl get clusterissuer` | Lister tous les émetteurs à l'échelle du cluster |
| `kubectl describe issuer <name>` | Afficher les informations détaillées de l'émetteur |
| `kubectl get certificaterequest` | Lister les demandes de certificat |
| `kubectl get order` | Afficher les commandes de certificat ACME |
| `kubectl get challenge` | Afficher les défis ACME pour la validation de domaine |
| `kubectl logs -n cert-manager deployment/cert-manager` | Afficher les journaux du contrôleur cert-manager |
| `kubectl logs -n cert-manager deployment/cert-manager-webhook` | Afficher les journaux webhook |
| `kubectl logs -n cert-manager deployment/cert-manager-cainjector` | Afficher les journaux de l'injecteur CA |
| `cmctl check api` | Vérifier que l'API cert-manager est disponible |
| `cmctl version` | Afficher les informations de version de cert-manager |
| `cmctl status certificate <name>` | Vérifier le statut et la préparation du certificat |
| `cmctl inspect secret <secret-name>` | Inspecter le secret TLS créé par cert-manager |
| `cmctl renew <cert-name>` | Déclencher manuellement le renouvellement du certificat |
| `kubectl get crd \ | grep cert-manager` | Lister toutes les Custom Resource Definitions de cert-manager |
| `kubectl get events --field-selector involvedObject.name=<cert-name>` | Afficher les événements liés à un certificat spécifique |### Configuration du dépôt Helm

| Commande | Description |
|---------|-------------|
| `cmctl approve <certificaterequest-name>` | Approuver manuellement une demande de certificat |
| `cmctl deny <certificaterequest-name>` | Refuser une demande de certificat |
| `cmctl create certificaterequest test --from-certificate-file=cert.yaml` | Créer une demande de certificat à partir d'un fichier |
| `cmctl convert --output-format=pem --input-file=cert.yaml` | Convertir le certificat au format PEM |
| `cmctl experimental create acmeaccount --server=<url> --email=<email>` | Inscription du compte de test ACME |
| `kubectl annotate certificate <name> cert-manager.io/issue-temporary-certificate="true" --overwrite` | Forcer le renouvellement immédiat du certificat |
| `kubectl delete certificaterequest <name>` | Supprimer la demande de certificat ayant échoué |
| `kubectl delete order <name>` | Supprimer la commande ACME |
| `kubectl delete challenge <name>` | Supprimer le challenge ACME bloqué |
| `kubectl get certificate <name> -o jsonpath='{.status.conditions}'` | Extraire les conditions de statut de certificat |
| `kubectl get secret <tls-secret> -o jsonpath='{.data.tls\.crt}' \ | base64 -d \ | openssl x509 -text -noout` | Décoder et afficher les détails du certificat |
| `kubectl get secret <tls-secret> -o jsonpath='{.data.tls\.crt}' \ | base64 -d \ | openssl x509 -noout -dates` | Vérifier les dates d'expiration des certificats |
| `helm upgrade cert-manager jetstack/cert-manager --namespace cert-manager --version v1.13.3` | Mettre à jour cert-manager vers une nouvelle version |
| `kubectl rollout restart deployment -n cert-manager` | Redémarrer tous les composants cert-manager |
| `kubectl scale deployment cert-manager -n cert-manager --replicas=2` | Mise à l'échelle de cert-manager pour une haute disponibilité |
| `kubectl get certificate --watch` | Suivez les changements de statut de certificat en temps réel |
| `kubectl patch certificate <name> --type merge -p '{"spec":{"renewBefore":"720h"}}'` | Modifier la fenêtre de renouvellement de certificat |
| `kubectl delete secret <tls-secret>` | Supprimer le secret de certificat (déclenche la recréation) |
| `cmctl experimental install` | Installer cert-manager à l'aide de l'outil cmctl |
| `cmctl experimental uninstall` | Désinstaller cert-manager et nettoyer les ressources |
```yaml
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: selfsigned-issuer
spec:
  selfSigned: {}
```## Commandes de base
```yaml
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
    solvers:
    - http01:
        ingress:
          class: nginx
```## Utilisation avancée
```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
    solvers:
    - dns01:
        cloudDNS:
          project: my-gcp-project
          serviceAccountSecretRef:
            name: clouddns-dns01-solver
            key: key.json
```## Configuration
```yaml
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
  name: ca-issuer
  namespace: default
spec:
  ca:
    secretName: ca-key-pair
```### ClusterIssuer auto-signé
```yaml
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: example-com
  namespace: default
spec:
  secretName: example-com-tls
  issuerRef:
    name: letsencrypt-prod
    kind: ClusterIssuer
  dnsNames:
  - example.com
  - www.example.com
  duration: 2160h      # 90 days
  renewBefore: 360h    # 15 days before expiry
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: wildcard-cert
  namespace: default
spec:
  secretName: wildcard-tls
  issuerRef:
    name: letsencrypt-prod
    kind: ClusterIssuer
  dnsNames:
  - "*.example.com"
  - example.com
```### Let's Encrypt Staging (Défi HTTP-01)
```yaml
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
  name: vault-issuer
  namespace: default
spec:
  vault:
    server: https://vault.example.com
    path: pki/sign/example-dot-com
    auth:
      kubernetes:
        mountPath: /v1/auth/kubernetes
        role: cert-manager
        secretRef:
          name: vault-token
          key: token
# custom-values.yaml
installCRDs: true
replicaCount: 2

resources:
  requests:
    cpu: 100m
    memory: 128Mi
  limits:
    cpu: 200m
    memory: 256Mi

prometheus:
  enabled: true
  servicemonitor:
    enabled: true

webhook:
  replicaCount: 2

cainjector:
  replicaCount: 2
```### Let's Encrypt Production (Défi DNS-01)
```bash
# Create ClusterIssuer
kubectl apply -f - <<EOF
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
    solvers:
    - http01:
        ingress:
          class: nginx
EOF

# Create Ingress with TLS annotation
kubectl apply -f - <<EOF
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: example-ingress
  annotations:
    cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
  ingressClassName: nginx
  tls:
  - hosts:
    - example.com
    secretName: example-com-tls
  rules:
  - host: example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: example-service
            port:
              number: 80
EOF

# Verify certificate creation
kubectl get certificate
kubectl describe certificate example-com-tls
# Create self-signed CA
kubectl apply -f - <<EOF
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: selfsigned-issuer
spec:
  selfSigned: {}
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: my-ca
  namespace: cert-manager
spec:
  isCA: true
  commonName: my-ca
  secretName: my-ca-secret
  privateKey:
    algorithm: ECDSA
    size: 256
  issuerRef:
    name: selfsigned-issuer
    kind: ClusterIssuer
EOF

# Create CA issuer from generated CA
kubectl apply -f - <<EOF
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: my-ca-issuer
spec:
  ca:
    secretName: my-ca-secret
EOF

# Issue service certificates
kubectl apply -f - <<EOF
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: service-a-cert
  namespace: default
spec:
  secretName: service-a-tls
  duration: 8760h
  renewBefore: 720h
  subject:
    organizations:
    - my-org
  commonName: service-a.default.svc.cluster.local
  dnsNames:
  - service-a.default.svc.cluster.local
  issuerRef:
    name: my-ca-issuer
    kind: ClusterIssuer
EOF
```### Émetteur CA (PKI interne)
```bash
# Create DNS provider secret (example: Cloudflare)
kubectl create secret generic cloudflare-api-token \
  --from-literal=api-token=YOUR_CLOUDFLARE_API_TOKEN

# Create ClusterIssuer with DNS-01 solver
kubectl apply -f - <<EOF
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
    solvers:
    - dns01:
        cloudflare:
          email: admin@example.com
          apiTokenSecretRef:
            name: cloudflare-api-token
            key: api-token
EOF

# Request wildcard certificate
kubectl apply -f - <<EOF
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: wildcard-example
  namespace: default
spec:
  secretName: wildcard-example-tls
  issuerRef:
    name: letsencrypt-dns
    kind: ClusterIssuer
  dnsNames:
  - "*.example.com"
  - example.com
EOF

# Monitor certificate issuance
kubectl get certificate wildcard-example -w
# Create certificate for webhook
kubectl apply -f - <<EOF
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: webhook-cert
  namespace: webhook-system
spec:
  secretName: webhook-server-cert
  duration: 8760h
  renewBefore: 720h
  issuerRef:
    name: selfsigned-issuer
    kind: ClusterIssuer
  dnsNames:
  - webhook-service.webhook-system.svc
  - webhook-service.webhook-system.svc.cluster.local
EOF

# Reference in webhook configuration
kubectl apply -f - <<EOF
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
  name: my-webhook
  annotations:
    cert-manager.io/inject-ca-from: webhook-system/webhook-cert
webhooks:
- name: webhook.example.com
  clientConfig:
    service:
      name: webhook-service
      namespace: webhook-system
      path: "/validate"
    caBundle: "" # Injected by cert-manager
EOF
```### Ressource de certificat
```bash
# Create certificate with short duration for testing
kubectl apply -f - <<EOF
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: short-lived-cert
  namespace: default
spec:
  secretName: short-lived-tls
  duration: 24h
  renewBefore: 8h
  issuerRef:
    name: selfsigned-issuer
    kind: ClusterIssuer
  dnsNames:
  - test.example.com
EOF

# Monitor renewal
kubectl get certificate short-lived-cert -w

# Force immediate renewal
kubectl annotate certificate short-lived-cert \
  cert-manager.io/issue-temporary-certificate="true" \
  --overwrite

# Check renewal history
kubectl get certificaterequest -l cert-manager.io/certificate-name=short-lived-cert

# Verify new certificate
cmctl inspect secret short-lived-tls

renewBefore### Certificat générique certmanager_certificate_expiration_timestamp_seconds

  • Utiliser DNS-01 pour les wildcards et services internes : Le challenge DNS-01 est requis pour les certificats wildcard et fonctionne mieux pour les services non exposés à internet

  • Implémenter un RBAC approprié : Restreindre l’accès aux Issuers et secrets de certificats en utilisant Kubernetes RBAC pour empêcher la création de certificats non autorisés

  • Versionner vos configurations : Stocker les manifestes de Certificate et Issuer dans Git pour suivre les modifications et activer les workflows GitOps

  • Utiliser des issuers séparés par environnement : Créer différents issuers pour dev/staging/prod pour isoler les identifiants et prévenir les problèmes de certificats inter-environnements

  • Activer l’injection de CA pour les webhooks : Utiliser cert-manager.io/inject-ca-froml’annotation pour injecter automatiquement les bundles CA dans les configurations de webhook

  • Planifier la reprise après sinistre : Sauvegarder les clés privées CA et les identifiants de compte ACME stockés dans les secrets Kubernetes vers un stockage externe sécurisé

Dépannage

ProblèmeSolution
Certificate stuck in “Pending”Check certificate request: kubectl describe certificaterequest <name>. Look for ACME challenge failures or issuer configuration errors
ACME HTTP-01 challenge failingVerify ingress is accessible: curl http://<domain>/.well-known/acme-challenge/test. Check ingress class matches solver configuration
DNS-01 challenge timeoutConfirm DNS provider credentials: kubectl get secret <dns-secret> -o yaml. Verify DNS propagation: dig TXT _acme-challenge.<domain>
”Too many certificates” rate limitPassez au serveur de test Let’s Encrypt ou attendez 7 jours. Vérifiez les limites de taux : https://letsencrypt.org/docs/rate-limits/
Certificate not renewing automaticallyCheck renewBefore setting and cert-manager logs: kubectl logs -n cert-manager deployment/cert-manager. Verify controller is running
Webhook connection failuresVerify webhook service is running: kubectl get svc -n cert-manager. Check webhook certificate validity: cmctl check api
CA injection not workingEnsure cainjector is running: kubectl get pods -n cert-manager. Verify annotation syntax: cert-manager.io/inject-ca-from: namespace/certificate
Certificate shows “Ready=False”Get detailed status: cmctl status certificate <name>. Check events: kubectl get events --field-selector involvedObject.name=<cert-name>
Order stuck in “Pending”Delete order to retry: kubectl delete order <order-name>. Certificate controller will create new order automatically
Secret not created after certificate readyCheck secret name matches secretName in Certificate spec. Verify namespace: kubectl get secret <name> -n <namespace>
Wildcard certificate validation failsAssurez-vous que le solveur DNS-01 est configuré (HTTP-01 ne prend pas en charge les wildcards). Vérifiez les autorisations du fournisseur DNS pour la création d’enregistrements TXT
Certificate shows wrong issuerDelete certificate request: kubectl delete certificaterequest <name>. Update Certificate spec with correct issuerRef
High memory usageReduce certificate count or increase resources: kubectl set resources deployment cert-manager -n cert-manager --limits=memory=512Mi
Duplicate certificates createdCheck for multiple Certificate resources with same secretName. Remove duplicates to prevent conflicts
ACME account registration failsVérifier le format de l’e-mail dans la spécification de l’émetteur. Vérifier que l’URL du serveur ACME est correcte. Examiner les journaux de cert-manager pour des messages d’erreur détaillés

Séquence de commandes de débogage

# Complete troubleshooting workflow
kubectl describe certificate <cert-name>
kubectl get certificaterequest -l cert-manager.io/certificate-name=<cert-name>
kubectl describe certificaterequest <request-name>
kubectl get order
kubectl describe order <order-name>
kubectl get challenge
kubectl describe challenge <challenge-name>
kubectl logs -n cert-manager deployment/cert-manager --tail=100

Modèles de journaux courants```bash

Search for specific certificate errors

kubectl logs -n cert-manager deployment/cert-manager | grep “certificate=

Find ACME challenge errors

kubectl logs -n cert-manager deployment/cert-manager | grep “challenge”

Check for rate limit errors

kubectl logs -n cert-manager deployment/cert-manager | grep “rate limit”

Monitor certificate renewal attempts

kubectl logs -n cert-manager deployment/cert-manager -f | grep “renewal”