Zertifikate überwachen mit Zabbix

Abstract

Es ist sehr ärgerlich, wenn das Zertifikat einer Webseite abgelaufen ist. Große rote Warnlampen springen den Besucher der Seite an, sie sind verunsichert und können im schlimmsten Fall sogar die Seite meiden. Der Administrator versucht verzweifelt das Zertifikat zu erneuern, was er das letzte Mal von ca. zwei Jahren gemacht hat und natürlich nun, wenn er es braucht, vergessen hat. Das gleiche gilt natürlich auch für Mailserver, die TLS Verschlüsselung für SMTP oder IMAP anbieten.

Zertifikate überwachen mit Zabbix

Es ist sehr ärgerlich, wenn das Zertifikat einer Webseite abgelaufen ist. Große rote Warnlampen springen den Besucher der Seite an, sie sind verunsichert und können im schlimmsten Fall sogar die Seite meiden. Der Administrator versucht verzweifelt das Zertifikat zu erneuern, was er das letzte Mal von ca. zwei Jahren gemacht hat und natürlich nun, wenn er es braucht, vergessen hat. Das gleiche gilt natürlich auch für Mailserver, die TLS Verschlüsselung für SMTP oder IMAP anbieten.

Grundlagen

Wenn man Zabbix als Monitoring System einsetzt, kann man so die Gültigkeit von Zertifikaten überwachen und rechtzeitig Alarm schlagen. Ein Item liefert wie viele Tage ein Zertifikat noch gültig ist. Wenn diese Zeit kleiner als ein Schwellwert ist, bekommt der Admin eine Mail und kann sich entspannt um das Problem kümmern.

Bei der Suche im Internet bin ich auf den Blog-Eintrag SSL certificate expiration monitoring with Zabbix gestossen, der das Problem für Webserver löst. Das openssl Kommando wird benuzt, um das Zertifikat der Webseite auszulesen, die Datumsangaben anzuzeigen und die Zeile mit notAfter herauszufiltern. Die Daten dieser Zeile werden mit dem aktuellen Datum verglichen.

END_DATE="$(openssl s_client $S_CLIENT_OPTS </dev/null 2>$TMP | \
  openssl x509 -dates -noout | \
  sed -n 's/notAfter=//p')"

Überwachung anderer Protokolle

In den man Seiten von openssl steht, dass der Befehl noch viel mehr kann, als nur das Zertifikat von Webseiten auszulesen. Deshalb ist es einfach, das originale Script so zu erweitern, dass es die Gültigkeit von Zertifikaten von SMTP, IMAP, POP3, FTP und XMPP Servern überwacht. Das Protokoll wird mit der Option -P dem Script übergeben und ein case Befehl im Script passst die S_CLIENT_OPTS an, die im openssl Befehl genutzt werden.

Das Script

Die originale Option, den Herausgeber des Zertifikats zu überprüfen, habe ich übernommen. Zusammengefasst schaut das Script nun so aus:

#!/bin/bash
#
# Authors:
#       Michael Schwartzkopff <ms@sys4.de>
#       Marc Schiffbauer <m@sys4.de>
#

trap clean_exit EXIT

clean_exit() {
  [[ $TMP && -f $TMP ]] && rm -f "$TMP"
}

debug() {
  [[ $DEBUG -gt 0 ]] && echo "$*"
}

debugexec() {
  [[ $DEBUG -gt 0 ]] && "$*"
}

error() {
  echo "ERROR: $*"
}

die() {
  error "$*"
  exit 1
}

usage() {
  cat <<EOF
    Usage:
    $(basename $0) [options]

    -H <hostname>         Hostname to connect to. Default: localhost
    -P <protocol>         Protocol to use (SSL, SMTP, IMAP, POP3, FTP, XMPP). Default: SSL
    -d                    Turn on debug mode
    -i                    Get certificate issuer instead of days left until certificate will expire
    -p <port>             Port to connect to. Defaults: 443 (SSL), 25 (SMTP), 143 (IMAP),
                          110 (POP3), 21 (FTP), 5269 (XMPP)

EOF
  exit 0
}

while getopts "idhH:p:P:" opt; do
  case "$opt" in
    H) HOST="$OPTARG";;
    P) PROTO="$OPTARG";;
    d) DEBUG=1; set -x;;
    i) WHAT="ISSUER";;
    p) PORT="$OPTARG";;
    *) usage;;
  esac
done

# set default values
HOST=${HOST:-localhost}
PROTO=${PROTO:-SSL}
WHAT=${WHAT:-TIME}

debug "Checking protocol $PROTO on ${HOST}:${PORT}"

case $PROTO in
  SSL)
    PORT=${PORT:-443}
    S_CLIENT_OPTS=" -host $HOST -port $PORT -showcerts"
  ;;
  SMTP)
    PORT=${PORT:-25}
    S_CLIENT_OPTS="-connect $HOST:$PORT -starttls smtp"
  ;;
  IMAP)
    PORT=${PORT:-143}
    S_CLIENT_OPTS="-connect $HOST:$PORT -starttls imap"
  ;;
  POP3)
    PORT=${PORT:-110}
    S_CLIENT_OPTS="-connect $HOST:$PORT -starttls pop3"
  ;;
  FTP)
    PORT=${PORT:-21}
    S_CLIENT_OPTS="-connect $HOST:$PORT -starttls ftp"
  ;;
  XMPP)
    PORT=${PORT:-5269}
    S_CLIENT_OPTS="-connect $HOST:$PORT -starttls xmpp"
  ;;
  *)
    die "Unknown protocol"
  ;;
esac

debug "Certificate:"
debugexec "openssl s_client $S_CLIENT_OPTS </dev/null 2>$TMP"

case $WHAT in
  TIME)
    TMP="$(mktemp)"
    END_DATE="$(openssl s_client $S_CLIENT_OPTS </dev/null 2>$TMP | openssl x509 -dates -noout | sed -n 's/notAfter=//p')"
    NOW="$(date '+%s')"
    if [[ $END_DATE ]]; then
      SEC_LEFT="$(date '+%s' --date "${END_DATE}")"
      echo $((($SEC_LEFT-$NOW)/24/3600))
    else
      die "openssl error: $(cat $TMP)"
    fi
  ;;
  ISSUER)
    TMP="$(mktemp)"
    openssl s_client $S_CLIENT_OPTS </dev/null 2>$TMP | openssl x509 -issuer -noout | sed -n 's/.*CN=//p'
  ;;
  *)
    die "BUG: unknown WHAT value: $WHAT"
  ;;
esac

exit 0

Der Aufruf des externen Scriptes beeinflusst die Performance des Zabbix Servers nur wenig, da der Test nur einmal pro Tag ausgeführt wird.

Integration in Zabbix

Nachdem das Script in das Verzeichnis kopiert wurde, in dem der Zabbix Server es erwartet (Konfigurationsoption ExternalScripts) und nachdem die Rechte der Datei so geändert wurden, dass der Zabbix Server das Script ausführen darf, können Sie ein Item in Zabbix definieren, das die Gültigkeit des Zertifikats einer Webseite prüft. Der Typ des Items ist natürlich ExternalCheck:

$ zext_ssl_cert.sh[-d,{HOST.CONN}]

Wenn Sie die Gültigkeit des Zertifikats eines SMTP Mailservers testen wollen, müssen Sie einfach dem Item mehr Optionen mitgeben:

$ zabbix_check_cert.sh[-H,{HOST.CONN},-P,SMTP]

Sie können auf der originalen Webseite die Vorlage Template_zext_ssl_cert für Zabbix herunterladen. Natürlich kann das nur die Zertifikate von Webseiten testen. Aber Sie können die Vorlage einfach erweitern, um Items und Trigger für die anderen Server zu definieren.

Michael Schwartzkopff, 02. September 2013