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.

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

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

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

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

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 !
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 →