Let's Encrypt et ACME sur OPNsense : certificats TLS gratuits pour tous vos services internes

Déployez Let's Encrypt sur OPNsense avec le plugin os-acme-client : challenge DNS-01 Cloudflare, certificat wildcard *.botum.ca, distribution HAProxy/Nginx/Docker, renouvellement automatique et alerting.

Let's Encrypt et ACME sur OPNsense : certificats TLS gratuits pour tous vos services internes
Pourquoi TLS pour les services internes - HSTS et sécurité navigateur
TLS interne : HSTS, confiance navigateur, Zero-Trust — indispensable même sur le LAN

1. Pourquoi TLS même pour les services internes ?

La plupart des administrateurs négligent TLS sur le réseau interne : "personne ne peut intercepter le trafic LAN de toute façon". C'est une erreur critique. Voici pourquoi :

  • HSTS (HTTP Strict Transport Security) : les navigateurs modernes refusent les connexions HTTP vers des domaines ayant déjà répondu en HTTPS. Sans TLS interne, vos services deviennent inaccessibles après une première visite HTTPS.
  • Confiance navigateur : les alertes "certificat invalide" forment les utilisateurs à ignorer les avertissements — les rendant vulnérables aux vraies attaques.
  • Zero-Trust interne : un attaquant sur le VLAN IoT (Billet 2) peut intercepter le trafic non chiffré. TLS interne = défense en profondeur.
  • APIs et webhooks : Grafana, Wazuh, AdGuard Home exposent des APIs. Sans TLS, les tokens d'authentification circulent en clair.
  • Let's Encrypt = gratuit : le plugin ACME d'OPNsense automatise tout, sans raison économique de s'en priver.

2. Installer le plugin os-acme-client sur OPNsense

Le plugin os-acme-client est disponible directement dans le gestionnaire de plugins OPNsense. Il intègre le client ACME acme.sh et gère nativement Let's Encrypt.

# Via l'interface Web OPNsense :
# System > Firmware > Plugins > rechercher "acme"
# Installer : os-acme-client
# Redémarrer OPNsense après installation

# Menu disponible dans :
# Services > ACME Client > Settings / Accounts / Certificates / Automations

# Créer un compte ACME :
# Services > ACME Client > Accounts > Add
Name        : botum-letsencrypt
E-Mail      : admin@botum.ca
ACME Server : Let's Encrypt (production)
              https://acme-v02.api.letsencrypt.org/directory
DNS-01 ACME challenge flow - validation sans port 80
Challenge DNS-01 : validation Let's Encrypt via enregistrement TXT Cloudflare — aucun port 80 requis

3. Valider le domaine : challenge DNS sans port 80

La validation DNS-01 est la seule méthode qui fonctionne sans exposer le port 80 au public — indispensable pour les services internes et les certificats wildcard.

# Cloudflare — token API minimal (recommandé) :
# Cloudflare Dashboard > My Profile > API Tokens > Create Token
# Permissions : Zone > DNS > Edit | Zone : Specific zone > botum.ca

# OPNsense > Services > ACME Client > Challenge Types > Add
Name          : cloudflare-dns
Challenge     : DNS-01
DNS Service   : Cloudflare
CF_Token      : [votre-token-api-cloudflare]
CF_Account_ID : [votre-account-id]

# OVH
OVH_AK / OVH_AS / OVH_CK / OVH_ENDPOINT : ovh-ca

# Gandi LiveDNS
GANDI_LIVEDNS_KEY : [clé API Gandi]

4. Générer un certificat wildcard *.botum.ca

Un certificat wildcard couvre tous les sous-domaines : grafana.botum.ca, wazuh.botum.ca, adguard.botum.ca. Un seul certificat, renouvellement centralisé.

# Services > ACME Client > Certificates > Add
Name               : wildcard-botum-ca
Common Name        : *.botum.ca
Challenge Type     : cloudflare-dns
Key Length         : 4096 bit (ou ec-384 pour ECDSA)
Auto Renew         : activer
Renew before (d)   : 30

# Cliquer "Issue / Renew" — le plugin ACME :
# 1. Contacte Let's Encrypt
# 2. Crée le TXT record _acme-challenge.botum.ca via Cloudflare API
# 3. Let's Encrypt valide le TXT record
# 4. Certificat téléchargé et stocké dans OPNsense
# 5. TXT record supprimé automatiquement

# Vérification : System > Trust > Certificates
# -> wildcard-botum-ca avec expiration ~90 jours
Distribution du certificat wildcard vers OPNsense HAProxy Nginx Docker
Distribution du certificat wildcard : OPNsense, HAProxy, Nginx, services Docker — un seul cert, tous les services

5. Distribuer le certificat : OPNsense, HAProxy, Nginx, Docker

5.1 OPNsense Web UI

# System > Settings > Administration
SSL Certificate : wildcard-botum-ca
# -> Interface admin passe en HTTPS valide, accessible via https://fw.botum.ca/

5.2 HAProxy (reverse proxy)

# Services > HAProxy > Settings > Frontend HTTPS
SSL Certificates : wildcard-botum-ca
SSL offloading   : activer
# HAProxy gère le TLS termination pour tous les services derrière

5.3 Nginx + Docker

# Automation post-renouvellement OPNsense :
# Services > ACME Client > Automations > Add
Name    : deploy-to-nginx
Command : /usr/local/sbin/deploy_cert_nginx.sh

# Docker Compose — monter le certificat en volume :
services:
  grafana:
    volumes:
      - /opt/certs/botum.ca.crt:/etc/grafana/ssl/cert.pem:ro
      - /opt/certs/botum.ca.key:/etc/grafana/ssl/key.pem:ro
    environment:
      GF_SERVER_PROTOCOL: https
      GF_SERVER_CERT_FILE: /etc/grafana/ssl/cert.pem
      GF_SERVER_CERT_KEY: /etc/grafana/ssl/key.pem
Monitoring renouvellement automatique certificats ACME Grafana alerting
Renouvellement automatique + alerting : cron ACME natif, Prometheus ssl_exporter, notifications Telegram sur expiration

6. Renouvellement automatique (cron ACME natif)

Le plugin intègre un cron natif qui renouvelle automatiquement les certificats 30 jours avant expiration. Let's Encrypt émet des certificats valides 90 jours.

# Services > ACME Client > Settings
# [x] Enable Cron Job
# Run interval : Daily
# Scheduled at : 03:30

# Vérification des logs :
tail -100 /var/log/acme.log | grep -E "SUCCESS|ERROR|Renew"

7. Alerting sur expiration (intégration monitoring Billet 9)

#!/bin/bash
# /opt/scripts/check_cert_expiry.sh
TELEGRAM_TOKEN="[token]"
TELEGRAM_CHAT="-1001234567890"
WARN_DAYS=14 ; CRIT_DAYS=7

for cert in grafana.botum.ca wazuh.botum.ca adguard.botum.ca fw.botum.ca; do
    EXPIRY=$(echo | openssl s_client -connect ${cert}:443 -servername ${cert} 2>/dev/null              | openssl x509 -noout -enddate 2>/dev/null | cut -d= -f2)
    DAYS_LEFT=$(( ($(date -d "$EXPIRY" +%s) - $(date +%s)) / 86400 ))
    [ $DAYS_LEFT -le $CRIT_DAYS ] &&         curl -s "https://api.telegram.org/bot${TELEGRAM_TOKEN}/sendMessage"              -d "chat_id=${TELEGRAM_CHAT}&text=CRITIQUE: Cert ${cert} expire dans ${DAYS_LEFT}j" > /dev/null
done

# Prometheus ssl_exporter + règle d'alerte :
# expr: ssl_cert_not_after - time() < 86400 * 14
Stack BOTUM sécurisé TLS - AdGuard DoH Grafana Wazuh OPNsense
Stack BOTUM entièrement sécurisé TLS : AdGuard Home DoH, Grafana, Wazuh Dashboard et OPNsense avec certificats valides

8. Cas d'usage : AdGuard DoH, Grafana, Wazuh Dashboard

8.1 AdGuard Home DNS-over-HTTPS (Billet 8)

# AdGuard Home > Settings > Encryption Settings
Enable encryption : Yes
Server name       : adguard.botum.ca
DNS-over-HTTPS    : https://adguard.botum.ca/dns-query
TLS certificate   : /etc/adguard/ssl/botum.ca.crt
Private key       : /etc/adguard/ssl/botum.ca.key

8.2 Grafana (Billet 9)

# grafana.ini
[server]
protocol     = https
cert_file    = /etc/grafana/ssl/cert.pem
cert_key     = /etc/grafana/ssl/key.pem
domain       = grafana.botum.ca
root_url     = https://grafana.botum.ca/
enforce_domain = true

8.3 Wazuh Dashboard (Billet 11)

# /etc/wazuh-dashboard/opensearch_dashboards.yml
server.ssl.enabled: true
server.ssl.certificate: /etc/wazuh-dashboard/certs/wazuh-dashboard.pem
server.ssl.key: /etc/wazuh-dashboard/certs/wazuh-dashboard-key.pem
# Remplacer les certs auto-signés par botum.ca.crt / botum.ca.key
# systemctl restart wazuh-dashboard

9. Conclusion

Avec le Billet 14, tous les services du Stack OPNsense BOTUM sont sécurisés par un certificat TLS valide, renouvelé automatiquement, sans intervention manuelle :

  • os-acme-client — Plugin OPNsense natif, intégration Let's Encrypt
  • DNS-01 challenge — Validation sans port 80, support Cloudflare/OVH/Gandi
  • Wildcard *.botum.ca — Un certificat pour tous les sous-domaines
  • HAProxy + Nginx + Docker — Distribution automatisée post-renouvellement
  • Cron ACME natif — Renouvellement automatique 30j avant expiration
  • Alerting Telegram + Prometheus — Surveillance proactive des expirations

Prochaine étape → Billet 15 (dernier) : Netflow + ntopng sur OPNsense — analyse de trafic réseau en temps réel, le dernier billet de la série !

📥 Guide PDF complet

Téléchargez ce guide en PDF pour le consulter hors ligne.

⬇ Télécharger le guide (PDF)

🚀 Aller plus loin avec BOTUM

Ce guide couvre les bases. En production, chaque environnement a ses spécificités. Les équipes BOTUM accompagnent les organisations dans le déploiement, la configuration avancée et la sécurisation de leur infrastructure. Si vous avez un projet, parlons-en.

Discuter de votre projet →
Série OPNsense 📋 Voir la série complète →