vendredi 25 septembre 2026

À propos

Contact

Outils & workflow

Détecter un certificat TLS qui expire bientôt sur tout un parc de sites

Une vérification périodique qui alerte avant l'expiration d'un certificat plutôt que de découvrir la coupure au moment où elle survient.

Par Clément Hadrot • 28 janvier 2025 • 5 min de lecture • Aucun commentaire
Détecter un certificat TLS qui expire bientôt sur tout un parc de sites

Un certificat TLS expiré coupe l’accès HTTPS d’un site du jour au lendemain, remplaçant la page normale par un avertissement de sécurité effrayant dans le navigateur du visiteur. Ce genre d’incident, en théorie éliminé par le renouvellement automatique de Let’s Encrypt, survient pourtant encore régulièrement : un client sous un certificat payant renouvelé manuellement, un renouvellement automatique silencieusement cassé après une migration de serveur, ou un sous-domaine oublié qui ne fait plus partie du script de renouvellement.

Ce texte ne traite pas Let’s Encrypt et son mécanisme de renouvellement automatique, déjà couvert en détail. Il s’agit ici d’un filet de sécurité indépendant : une vérification périodique qui interroge chaque certificat du parc depuis l’extérieur, sans dépendre du mécanisme de renouvellement lui-même, pour détecter une expiration imminente même si ce mécanisme a échoué sans que personne ne s’en aperçoive.

Interroger un certificat distant avec openssl

La commande openssl s_client permet d’obtenir les informations d’un certificat TLS sans rien installer côté serveur cible, en se contentant d’établir une connexion et de lire les métadonnées échangées lors de la poignée de main :

echo | openssl s_client -servername boutique.example.com \
  -connect boutique.example.com:443 2>/dev/null \
  | openssl x509 -noout -enddate

Cette commande renvoie une ligne du type notAfter=15 Mar 2025 12:00:00 GMT, la date d’expiration du certificat présenté par le serveur. C’est cette date qu’il faut comparer à la date du jour pour décider si une alerte se justifie.

Un script qui parcourt tout le parc

L’agence maintient un fichier texte listant tous les domaines suivis, un par ligne, et un script qui interroge chacun d’eux :

L'essentiel à retenir : openssl interroge un certificat distant sans rien installer côté serveur ; Un script cron parcourt tout le parc en une seule exécution ; L'alerte part quinze jours avant l'échéance, pas le jour même
#!/usr/bin/env bash
set -uo pipefail

DOMAINES_FILE="/opt/monitoring/domaines.txt"
SEUIL_JOURS=15
WEBHOOK_SLACK="$SLACK_WEBHOOK_URL"

while IFS= read -r domaine; do
  [ -z "$domaine" ] && continue

  DATE_EXPIRATION=$(echo | openssl s_client -servername "$domaine" \
    -connect "$domaine:443" 2>/dev/null \
    | openssl x509 -noout -enddate 2>/dev/null \
    | cut -d= -f2)

  if [ -z "$DATE_EXPIRATION" ]; then
    echo "Impossible de récupérer le certificat de $domaine"
    curl -s -X POST -H 'Content-Type: application/json' \
      -d "{\"text\":\"⚠️ Certificat introuvable ou connexion TLS échouée pour ${domaine}\"}" \
      "$WEBHOOK_SLACK"
    continue
  fi

  EPOCH_EXPIRATION=$(date -d "$DATE_EXPIRATION" +%s)
  EPOCH_AUJOURDHUI=$(date +%s)
  JOURS_RESTANTS=$(( (EPOCH_EXPIRATION - EPOCH_AUJOURDHUI) / 86400 ))

  if [ "$JOURS_RESTANTS" -le "$SEUIL_JOURS" ]; then
    curl -s -X POST -H 'Content-Type: application/json' \
      -d "{\"text\":\"🔴 Certificat de ${domaine} expire dans ${JOURS_RESTANTS} jours\"}" \
      "$WEBHOOK_SLACK"
  fi

  echo "$domaine : ${JOURS_RESTANTS} jours restants"
done < "$DOMAINES_FILE"

Pourquoi quinze jours et pas la veille

Une alerte le jour même de l'expiration, ou même la veille, ne laisse pratiquement aucune marge de manœuvre si le renouvellement automatique a réellement échoué et nécessite une intervention manuelle, par exemple parce que le port 80 requis pour la validation ACME HTTP-01 se trouve bloqué par un pare-feu mal configuré après une migration. Un délai de quinze jours laisse le temps de diagnostiquer calmement la cause du blocage, plutôt que de gérer une urgence un vendredi soir.

Programmer la vérification

Une exécution quotidienne, via une simple entrée cron, suffit largement : un certificat ne passe jamais de « valide plus de quinze jours » à « expiré » entre deux exécutions journalières.

0 7 * * * /opt/monitoring/verifier-certificats.sh >> /var/log/verif-tls.log 2>&1

Cas particuliers à gérer

  • Un domaine derrière Cloudflare en mode proxy présente le certificat de Cloudflare, pas celui du serveur d'origine : le script vérifie alors la chaîne visible publiquement, ce qui reste pertinent puisque c'est ce que voit réellement le visiteur.
  • Un sous-domaine avec un certificat wildcard partagé (*.exemple-agence.fr) n'a besoin d'être vérifié qu'une seule fois pour l'ensemble des sous-domaines qui l'utilisent, à condition de le documenter clairement dans le fichier de domaines pour éviter une alerte redondante par sous-domaine.
  • Un serveur qui répond mais sans TLS du tout, par exemple une redirection HTTP mal configurée, doit générer sa propre alerte distincte plutôt que de faire échouer silencieusement le script entier.

Étendre à un tableau de bord

Sur le parc le plus large suivi par l'agence, ce script alimente désormais aussi une métrique Prometheus via un exporteur textfile, ce qui permet de visualiser dans Grafana un compte à rebours par domaine plutôt que de dépendre uniquement des alertes Slack ponctuelles. Cette intégration reste optionnelle : le script seul, avec son entrée cron et son webhook, couvre déjà l'essentiel du besoin pour une agence de taille modeste.

Un certificat qui expire sans prévenir n'est jamais une surprise technique, c'est toujours l'absence d'une vérification qu'on avait remise à plus tard.

En résumé

Cette vérification indépendante du mécanisme de renouvellement automatique a permis de détecter, sur le parc de l'agence, deux certificats dont le renouvellement s'était silencieusement arrêté après une migration serveur, plusieurs semaines avant que la coupure ne survienne réellement. Le coût de mise en place, un script shell et une entrée cron, reste dérisoire comparé au coût de réputation d'un certificat expiré découvert par un client.

Partager :

À propos de l'auteur

Clément Hadrot

Développeur WordPress, passionné par Elementor, le FSE et l’automatisation par IA.

Voir tous ses articles

Dans la même veine

À lire aussi