← retour aux snippets

openssl: vérifier l'expiration d'un certificat TLS

Contrôler la date d'expiration d'un certificat TLS et le nombre de jours restants (Linux/macOS).

bash sécurité #openssl#tls#cert#expiry

objectif

Vérifier l’expiration d’un certificat TLS pour un domaine, afficher les jours restants et éviter les coupures de service liées à des certificats périmés.

code minimal

# Linux (GNU date): affiche la date d'expiration et les jours restants
host="data.pm"; port=443
end="$(openssl s_client -servername "$host" -connect "$host:$port" < /dev/null 2>/dev/null \
  | openssl x509 -noout -enddate | cut -d= -f2)"
exp_epoch="$(date -d "$end" +%s)"
now_epoch="$(date -u +%s)"
days_left="$(( (exp_epoch - now_epoch) / 86400 ))"
printf '%s:%s expires on %s (%s days left)\n' "$host" "$port" "$end" "$days_left"

utilisation

# macOS/BSD (date -j -f): même résultat
host="data.pm"; port=443
end="$(openssl s_client -servername "$host" -connect "$host:$port" < /dev/null 2>/dev/null \
  | openssl x509 -noout -enddate | cut -d= -f2)"
exp_epoch="$(date -j -f "%b %e %T %Y %Z" "$end" +%s)"
now_epoch="$(date -u +%s)"
days_left="$(( (exp_epoch - now_epoch) / 86400 ))"
printf '%s:%s expires on %s (%s days left)\n' "$host" "$port" "$end" "$days_left"

# vérifier hostname/SAN et la chaîne (hostname verification)
host="data.pm"; port=443
openssl s_client -servername "$host" -connect "$host:$port" -verify_hostname "$host" < /dev/null | \
  openssl x509 -noout -subject -issuer -enddate -ext subjectAltName

# service avec STARTTLS (ex: SMTP sur 587)
host="smtp.data.pm"; port=587
openssl s_client -starttls smtp -servername "$host" -connect "$host:$port" < /dev/null | \
  openssl x509 -noout -enddate -issuer -subject

# lire un certificat depuis un fichier PEM
openssl x509 -in cert.pem -noout -enddate -issuer -subject

# vérifier plusieurs hôtes (Linux)
for host in data.pm api.data.pm cdn.data.pm; do
  end="$(openssl s_client -servername "$host" -connect "$host:443" < /dev/null 2>/dev/null \
    | openssl x509 -noout -enddate | cut -d= -f2)"
  [ -n "$end" ] || { echo "$host: no cert"; continue; }
  exp_epoch="$(date -d "$end" +%s)"
  now_epoch="$(date -u +%s)"
  days_left="$(( (exp_epoch - now_epoch) / 86400 ))"
  printf '%-30s %4s days left | %s\n' "$host" "$days_left" "$end"
done

variante(s) utile(s)

# seuil d'alerte (Linux): exit 1 si < 30 jours restants
host="data.pm"; warn=30
end="$(openssl s_client -servername "$host" -connect "$host:443" < /dev/null 2>/dev/null | openssl x509 -noout -enddate | cut -d= -f2)"
exp_epoch="$(date -d "$end" +%s)"; now_epoch="$(date -u +%s)"
days_left="$(( (exp_epoch - now_epoch) / 86400 ))"
echo "$host: $days_left days left"
[ "$days_left" -lt "$warn" ] && exit 1 || exit 0

# extraire et afficher le CN et les SAN
openssl s_client -servername data.pm -connect data.pm:443 < /dev/null 2>/dev/null \
  | openssl x509 -noout -subject -ext subjectAltName

# forcer TLS1.2 si besoin (dépannage de compatibilité)
openssl s_client -tls1_2 -servername data.pm -connect data.pm:443 < /dev/null | \
  openssl x509 -noout -enddate

notes

  • utilisez -servername pour le SNI (indispensable sur les hôtes mutualisés).
  • la sortie “notAfter” est en GMT; convertissez avec date (Linux: -d, macOS: -j -f).
  • -verify_hostname fait échouer si le certificat ne correspond pas au domaine demandé.
  • pour des services non HTTPS, utilisez -starttls <proto> (smtp, imap, ldap, postgres, etc.).
  • derrière certains proxies, s_client peut afficher la chaîne du proxy; testez depuis un réseau qui atteint directement la cible si besoin.