Comment utiliser cert-manager et Apache pour générer un certificat Let’s Encrypt et gérer les défis ACME

Dans certains cas, des retards dans la prestation de certificats SSL peuvent poser problème, notamment si vos applications ou sites nécessitent une connexion sécurisée en HTTPS. Heureusement, la combinaison de cert-manager (outil de gestion des certificats pour Kubernetes) et de Let’s Encrypt permet de contourner cette situation efficacement. Cet article explique comment configurer Apache pour gérer les défis ACME, tout en permettant à cert-manager de générer des certificats Let’s Encrypt, et comment récupérer ces certificats pour les utiliser sur Apache.


Problématique : Retard dans la prestation des certificats SSL

Les retards dans l’obtention de certificats SSL peuvent avoir plusieurs causes : validation manuelle, procédures administratives ou dépendances externes. Pendant ce temps, vos services restent sans HTTPS, entraînant :

  • Des avertissements « Connexion non sécurisée » pour les utilisateurs.
  • Une non-conformité avec les normes modernes de sécurité.
  • Un frein à la mise en production de vos applications.

C’est ici qu’intervient Let’s Encrypt, une solution gratuite et rapide pour obtenir des certificats SSL, associée à cert-manager pour l’automatisation sur Kubernetes.


Architecture utilisée

Dans cet exemple, nous utilisons :

  1. Un cluster Kubernetes avec un Ingress Controller (comme nginx-ingress).
  2. Un serveur Apache agissant comme un reverse proxy pour relayer les requêtes vers Kubernetes.

Étape 1 : Configurer Apache pour gérer les défis ACME

Pour valider les noms de domaine, Let’s Encrypt effectue des requêtes sur une URL spécifique (ex. http://votre-domaine.com/.well-known/acme-challenge/). Apache doit être configuré pour relayer ces requêtes vers Kubernetes.

Exemple de configuration Apache

Ajoutez ou modifiez un VirtualHost dans votre fichier Apache pour gérer les requêtes ACME :

<VirtualHost *:80>
    ServerName votre-domaine.com
    ServerAdmin [email protected]

    LogLevel warn
    ErrorLog ${APACHE_LOG_DIR}/acme.error.log
    CustomLog ${APACHE_LOG_DIR}/acme.access.log combined

    # Relayer les défis ACME vers Kubernetes
    <Location /.well-known/acme-challenge/ >
        ProxyPass http://10.100.50.5/.well-known/acme-challenge/
        ProxyPassReverse http://10.100.50.5/.well-known/acme-challenge/
        ProxyPreserveHost On
    </Location>

    # Redirection HTTP -> HTTPS pour tout le reste
    RewriteEngine On
    RewriteCond %{REQUEST_URI} !^/.well-known/acme-challenge/
    RewriteRule ^(.*)$ https://%{HTTP_HOST}$1 [R=301,L]
</VirtualHost>
  • ProxyPass et ProxyPassReverse : Relais les requêtes ACME vers Kubernetes, où cert-manager gère la validation.
  • IP externe de Kubernetes : Dans cet exemple, l’IP du service ingress-nginx est 10.100.50.5.

Rechargez Apache après avoir appliqué cette configuration :

sudo systemctl reload apache2

Étape 2 : Installer cert-manager dans Kubernetes

Si ce n’est pas déjà fait, installez cert-manager dans votre cluster Kubernetes :

kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.13.0/cert-manager.yaml

Vérifiez que les pods de cert-manager sont en cours d’exécution :

kubectl get pods -n cert-manager

Étape 3 : Configurer cert-manager pour Let’s Encrypt

a. Créer un ClusterIssuer

Cert-manager utilise un ClusterIssuer pour demander des certificats auprès de Let’s Encrypt. Créez un fichier YAML pour le ClusterIssuer :

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: [email protected]
    privateKeySecretRef:
      name: letsencrypt-prod-account-key
    solvers:
    - http01:
        ingress:
          class: nginx

Appliquez ce fichier :

kubectl apply -f cluster-issuer.yaml

b. Créer une ressource Certificate

Créez un objet Certificate pour demander un certificat Let’s Encrypt :

apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: votre-domaine-cert
  namespace: default
spec:
  secretName: votre-domaine-tls
  dnsNames:
  - votre-domaine.com
  - www.votre-domaine.com
  issuerRef:
    name: letsencrypt-prod
    kind: ClusterIssuer

Appliquez ce fichier :

kubectl apply -f certificate.yaml

Cert-manager générera un certificat Let’s Encrypt et le stockera dans un Secret nommé votre-domaine-tls.


Étape 4 : Récupérer le certificat pour Apache

Une fois le certificat généré, récupérez-le depuis Kubernetes pour l’utiliser avec Apache.

Commandes pour extraire le certificat

  • Certificat SSL : kubectl get secret votre-domaine-tls -n default -o jsonpath='{.data.tls\.crt}' | base64 -d > /etc/apache2/ssl/votre-domaine.crt
  • Clé privée : kubectl get secret votre-domaine-tls -n default -o jsonpath='{.data.tls\.key}' | base64 -d > /etc/apache2/ssl/votre-domaine.key
  • Chaîne de certification (si nécessaire) : kubectl get secret votre-domaine-tls -n default -o jsonpath='{.data.ca\.crt}' | base64 -d > /etc/apache2/ssl/chain.crt

Étape 5 : Configurer Apache pour HTTPS

Ajoutez un VirtualHost HTTPS dans Apache :

<VirtualHost *:443>
    ServerName votre-domaine.com
    ServerAdmin [email protected]

    SSLEngine on
    SSLCertificateFile /etc/apache2/ssl/votre-domaine.crt
    SSLCertificateKeyFile /etc/apache2/ssl/votre-domaine.key
    SSLCACertificateFile /etc/apache2/ssl/chain.crt

    LogLevel warn
    ErrorLog ${APACHE_LOG_DIR}/ssl.error.log
    CustomLog ${APACHE_LOG_DIR}/ssl.access.log combined

    # Proxy vers Kubernetes
    ProxyPreserveHost On
    ProxyPass / https://10.100.50.5/
    ProxyPassReverse / https://10.100.50.5/

    SSLProxyEngine On
    SSLProxyVerify none
    SSLProxyCheckPeerCN off
    SSLProxyCheckPeerName off
</VirtualHost>

Rechargez Apache :

sudo systemctl reload apache2

Étape 6 : Automatiser le renouvellement des certificats

Cert-manager renouvelle automatiquement les certificats Let’s Encrypt. Cependant, vous devez synchroniser les certificats mis à jour sur Apache.

Créez un script pour récupérer les certificats mis à jour :

#!/bin/bash
kubectl get secret votre-domaine-tls -n default -o jsonpath='{.data.tls\.crt}' | base64 -d > /etc/apache2/ssl/votre-domaine.crt
kubectl get secret votre-domaine-tls -n default -o jsonpath='{.data.tls\.key}' | base64 -d > /etc/apache2/ssl/votre-domaine.key
kubectl get secret votre-domaine-tls -n default -o jsonpath='{.data.ca\.crt}' | base64 -d > /etc/apache2/ssl/chain.crt
systemctl reload apache2

Planifiez ce script avec cron pour l’exécuter régulièrement.


Conclusion

Cette solution montre comment Apache et cert-manager peuvent être utilisés pour gérer des certificats Let’s Encrypt dans un environnement Kubernetes. Bien que cette configuration soit fonctionnelle, une approche plus idéale pourrait être :

  • Certbot : Si votre serveur Apache peut directement gérer les certificats Let’s Encrypt, il simplifie le processus.
  • Nginx avec SSL Passthrough : Utiliser Nginx en tant que reverse proxy avec un mode default_server permettrait de relayer directement les connexions HTTPS vers Kubernetes, sans besoin de récupérer les certificats sur Apache.

Ces options peuvent réduire la complexité et offrir une solution encore plus transparente et maintenable.