TLS-Zertifikat-Ablauf mit Bash überwachen: openssl-Skripte für Monitoring
AI generated
$_
#!/
Bash · TLS · Security · Monitoring
TLS-Zertifikat-Ablauf mit Bash überwachen
Von openssl s_client bis zum Alarm-Skript

Ein abgelaufenes TLS-Zertifikat ist einer der wenigen Fehler, die einen Shop komplett offline nehmen können, ohne dass ein einziger Codefehler dahintersteckt. Wer TLS-Zertifikat-Ablauf mit Bash und openssl überwacht, erkennt drohende Ausfälle Wochen im Voraus und verhindert den nächtlichen Notfalleinsatz.

17 Min. Lesezeit openssl s_client · x509 · Cron Bash 4.x/5.x · Linux · Nagios/Icinga

1. Warum TLS-Zertifikat-Ablauf überwachen zum Standard gehört

Ein abgelaufenes TLS-Zertifikat unterscheidet sich von den meisten anderen Produktionsfehlern dadurch, dass es keine Vorwarnung durch Fehlermeldungen im Anwendungscode gibt. Der Browser zeigt plötzlich eine Sicherheitswarnung, APIs verweigern die Verbindung, und der Fehler tritt exakt zu einem vorhersehbaren Zeitpunkt auf, nämlich dem Ablaufdatum. Wer TLS-Zertifikat-Ablauf überwachen als festen Bestandteil des Betriebs etabliert, verwandelt diesen vorhersehbaren, aber leicht übersehenen Fehler in ein planbares Wartungsereignis.

Besonders kritisch ist das bei automatisierten Zertifikaten über Let's Encrypt mit kurzer Laufzeit von 90 Tagen: Ein fehlgeschlagener Renewal-Cronjob fällt oft erst auf, wenn das Zertifikat bereits abgelaufen ist. Ein separates Monitoring-Skript, das den TLS-Zertifikat-Ablauf überwacht, unabhängig vom Renewal-Prozess selbst, fängt genau diesen Fall ab, weil es die tatsächliche, nach außen sichtbare Gültigkeit prüft, nicht nur ob der Renewal-Befehl fehlerfrei durchgelaufen ist.

Auch bei manuell verwalteten Zertifikaten mit längerer Laufzeit (ein Jahr oder mehr) ist Monitoring wichtig, weil genau die seltene Wiederholung dazu führt, dass der Erneuerungsprozess in Vergessenheit gerät. Ein Skript, das TLS-Zertifikat-Ablauf für alle relevanten Domains überwacht und rechtzeitig warnt, ersetzt das Verlassen auf Kalendererinnerungen einzelner Mitarbeiter durch einen zuverlässigen, automatisierten Prozess.

2. Mit openssl s_client das Zertifikat eines Endpunkts abrufen

Der Kern jedes Skripts, das TLS-Zertifikat-Ablauf überwacht, ist der Befehl openssl s_client -connect host:443 -servername host. Die Option -servername ist bei Servern mit Server Name Indication (SNI) zwingend erforderlich, weil ohne sie oft ein Standardzertifikat statt des tatsächlich für die Domain konfigurierten Zertifikats zurückgegeben wird, was zu falschen Ergebnissen führt.

Da s_client interaktiv ist und auf eine Eingabe wartet, leitet man /dev/null als stdin um und schließt die Verbindung explizit mit der Option -quiet oder durch Timeout. Die Ausgabe wird an openssl x509 -noout -enddate weitergereicht, das ausschließlich das Ablaufdatum im Format notAfter=Mon DD HH:MM:SS YYYY GMT zurückgibt.


#!/usr/bin/env bash
# fetch-cert-expiry.sh — fetch a certificate's expiry date via openssl
set -euo pipefail

HOST="${1:?Usage: fetch-cert-expiry.sh <host> [port]}"
PORT="${2:-443}"

expiry_raw=$(echo | timeout 5 openssl s_client -connect "$HOST:$PORT" -servername "$HOST" 2>/dev/null \
  | openssl x509 -noout -enddate 2>/dev/null) || {
  echo "[ERROR] Could not retrieve certificate for $HOST:$PORT" >&2
  exit 1
}

# expiry_raw looks like: notAfter=Aug 15 12:00:00 2026 GMT
expiry_date="${expiry_raw#notAfter=}"
echo "[INFO] Certificate for $HOST expires on: $expiry_date"

3. Ablaufdatum extrahieren und in Tage umrechnen

Ein Ablaufdatum als Text ist für ein Monitoring-Skript wenig hilfreich, entscheidend ist die Anzahl verbleibender Tage. Bash selbst bietet dafür keine eingebaute Datumsarithmetik, aber date -d "$expiry_date" +%s wandelt das Datum in einen Unix-Timestamp um, den man dann mit dem aktuellen Timestamp vergleicht. Wichtig: Diese Syntax funktioniert mit GNU date (Linux), auf macOS mit BSD date ist die Optionssyntax anders (date -j -f).

Für ein Skript, das TLS-Zertifikat-Ablauf überwacht und portabel zwischen Linux und macOS laufen soll, lohnt sich eine kleine Erkennungslogik, die die passende date-Syntax wählt. In den meisten produktiven Umgebungen mit Linux-Servern reicht aber die GNU-date-Variante völlig aus.


#!/usr/bin/env bash
# days-until-expiry.sh — convert a certificate expiry date to remaining days
set -euo pipefail

HOST="${1:?Usage: days-until-expiry.sh <host>}"

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

expiry_epoch=$(date -d "$expiry_raw" +%s)
now_epoch=$(date +%s)
days_remaining=$(( (expiry_epoch - now_epoch) / 86400 ))

echo "[INFO] $HOST: certificate expires in $days_remaining day(s) ($expiry_raw)"

if (( days_remaining < 0 )); then
  echo "[CRITICAL] Certificate for $HOST has already expired!" >&2
  exit 2
fi

4. Mehrere Domains gleichzeitig prüfen

In der Praxis läuft ein Skript, das TLS-Zertifikat-Ablauf überwacht, selten für nur eine einzige Domain. Ein typisches Setup umfasst die Hauptdomain, mehrere Subdomains für Staging und API, sowie Domains von Partnerdiensten. Eine Domainliste in einer Datei kombiniert mit einer Bash-Schleife verarbeitet alle Endpunkte in einem Durchlauf und sammelt die Ergebnisse in einer strukturierten Übersicht.

Für schnellere Ausführung bei vielen Domains lohnt sich Parallelisierung mit Hintergrundprozessen, ähnlich wie bei anderen Bash-Automatisierungsaufgaben: Jede Prüfung ist unabhängig von den anderen, weshalb sich mehrere openssl s_client-Aufrufe problemlos gleichzeitig ausführen lassen, ohne dass sich die Ergebnisse gegenseitig beeinflussen.


#!/usr/bin/env bash
# check-multiple-domains.sh — monitor certificate expiry for a domain list
set -euo pipefail

DOMAIN_FILE="${1:?Usage: check-multiple-domains.sh <domain-list-file>}"

check_domain() {
  local host="$1"
  local expiry_raw expiry_epoch now_epoch days_remaining

  expiry_raw=$(echo | timeout 5 openssl s_client -connect "$host:443" -servername "$host" 2>/dev/null \
    | openssl x509 -noout -enddate 2>/dev/null | cut -d= -f2) || {
    printf '%-30s ERROR (unreachable or no cert)\n' "$host"
    return 1
  }

  expiry_epoch=$(date -d "$expiry_raw" +%s)
  now_epoch=$(date +%s)
  days_remaining=$(( (expiry_epoch - now_epoch) / 86400 ))
  printf '%-30s %4d days remaining (%s)\n' "$host" "$days_remaining" "$expiry_raw"
}

while IFS= read -r domain; do
  [[ -z "$domain" || "$domain" == \#* ]] && continue
  check_domain "$domain" &
done < "$DOMAIN_FILE"

wait

5. Schwellenwerte und Nagios-kompatible Exit-Codes

Für die Integration in Monitoring-Systeme wie Nagios oder Icinga ist eine klare Exit-Code-Konvention entscheidend: 0 für OK, 1 für Warning, 2 für Critical, 3 für Unknown. Ein Skript, das TLS-Zertifikat-Ablauf überwacht, definiert deshalb zwei Schwellenwerte, etwa 30 Tage für Warning und 7 Tage für Critical, und gibt den passenden Exit-Code zusammen mit einer aussagekräftigen Textausgabe zurück, die das Monitoring-System als Statusmeldung anzeigt.

Diese Konvention macht das Skript sofort in bestehende Monitoring-Infrastruktur integrierbar, ohne dass ein spezielles Plugin entwickelt werden muss. Nagios-kompatible Systeme erwarten zusätzlich Performance-Daten im Format | days_remaining=42 am Ende der Ausgabe, was Trend-Grafiken über die Zeit ermöglicht.


#!/usr/bin/env bash
# check-cert-nagios.sh — Nagios-compatible certificate expiry check
set -euo pipefail

HOST="${1:?Usage: check-cert-nagios.sh <host>}"
WARN_DAYS="${2:-30}"
CRIT_DAYS="${3:-7}"

expiry_raw=$(echo | timeout 5 openssl s_client -connect "$HOST:443" -servername "$HOST" 2>/dev/null \
  | openssl x509 -noout -enddate 2>/dev/null | cut -d= -f2) || {
  echo "UNKNOWN: could not retrieve certificate for $HOST"
  exit 3
}

expiry_epoch=$(date -d "$expiry_raw" +%s)
now_epoch=$(date +%s)
days_remaining=$(( (expiry_epoch - now_epoch) / 86400 ))

if (( days_remaining < 0 )); then
  echo "CRITICAL: certificate for $HOST expired $(( -days_remaining )) day(s) ago | days_remaining=$days_remaining"
  exit 2
elif (( days_remaining < CRIT_DAYS )); then
  echo "CRITICAL: certificate for $HOST expires in $days_remaining day(s) | days_remaining=$days_remaining"
  exit 2
elif (( days_remaining < WARN_DAYS )); then
  echo "WARNING: certificate for $HOST expires in $days_remaining day(s) | days_remaining=$days_remaining"
  exit 1
else
  echo "OK: certificate for $HOST valid for $days_remaining more day(s) | days_remaining=$days_remaining"
  exit 0
fi

6. Benachrichtigungen bei bevorstehendem Ablauf

Nicht jedes Team betreibt Nagios oder Icinga, viele bevorzugen direkte Benachrichtigungen über Slack, E-Mail oder Microsoft Teams. Ein Skript, das TLS-Zertifikat-Ablauf überwacht und einen Schwellenwert unterschreitet, sendet dann eine strukturierte Nachricht mit Domain, verbleibenden Tagen und exaktem Ablaufdatum an einen Webhook, statt nur einen Exit-Code zurückzugeben.

Wichtig ist, wiederholte Benachrichtigungen zu vermeiden, wenn ein Skript täglich läuft und ein Zertifikat seit Tagen im Warnbereich liegt: Eine einfache State-Datei, die den zuletzt benachrichtigten Tag speichert, verhindert, dass das Team jeden Tag dieselbe Meldung erhält und die Nachricht irgendwann ignoriert.

Werkzeug Setup-Aufwand Ketten-Prüfung Empfehlung
openssl s_client + x509 Minimal, überall vorhanden Ja, mit -showcerts Standardwahl für Bash-Monitoring
curl -vI Minimal Eingeschränkt Schnelle Sichtprüfung
Spezialisierte Tools (z.B. check_ssl_cert) Zusätzliche Installation Sehr umfangreich Große Nagios-Umgebungen
SaaS-Monitoring (extern) Vertrag/Kosten Ja Wenn keine eigene Infrastruktur gewünscht ist

Mironsoft

Shell-Automatisierung, TLS-Monitoring und Deployment-Infrastruktur

Keine überraschenden Zertifikatsausfälle mehr?

Wir richten Bash-basiertes TLS-Zertifikat-Monitoring für alle eure Domains ein, integrieren es in Nagios, Icinga oder Slack, und stellen sicher, dass Renewal-Fehler nicht erst beim Kunden auffallen.

Monitoring-Skripte

openssl-basierte Checks mit Schwellenwerten für alle Domains

Integration

Anbindung an Nagios, Icinga, Slack oder E-Mail-Benachrichtigung

Renewal-Absicherung

Unabhängige Prüfung des tatsächlichen Zertifikatsstatus, nicht nur des Cronjob-Exit-Codes

7. Zertifikatsketten und Zwischenzertifikate prüfen

Ein Endzertifikat kann selbst gültig sein, während ein Zwischenzertifikat in der Kette abgelaufen ist oder fehlt, was in manchen Clients zu Fehlern führt, während andere Clients es tolerieren. Wer TLS-Zertifikat-Ablauf überwacht, sollte deshalb nicht nur das Endzertifikat prüfen, sondern mit openssl s_client -showcerts die komplette Kette abrufen und jedes einzelne Zertifikat auf sein eigenes Ablaufdatum untersuchen.

In der Praxis ist das besonders bei selbst gehosteten Zertifikaten relevant, bei denen Zwischenzertifikate manuell aktualisiert werden müssen. Automatisierte Zertifikate über Let's Encrypt und die meisten Managed-Certificate-Dienste großer Cloud-Anbieter aktualisieren die komplette Kette automatisch, wodurch dieses Problem seltener auftritt, aber nicht ausgeschlossen ist.

8. Integration in Cron und CI für tägliche Prüfung

Ein Skript, das TLS-Zertifikat-Ablauf überwacht, gehört in einen täglichen Cronjob, nicht in eine manuelle Prüfliste. Eine Ausführung um 6 Uhr morgens mit Ausgabe in eine Logdatei und Benachrichtigung bei Schwellenwert-Unterschreitung reicht für die meisten Setups vollständig aus. Für Teams mit bestehender CI-Infrastruktur lässt sich derselbe Check zusätzlich als geplanter Pipeline-Job (Scheduled Pipeline in GitLab CI, Cron-Trigger in GitHub Actions) betreiben, was Monitoring-Konfiguration und Deployment-Konfiguration im selben Repository hält.

Ein zusätzlicher Vorteil der CI-Integration: Historische Läufe bleiben in den Pipeline-Logs nachvollziehbar, ohne eine separate Logging-Infrastruktur pflegen zu müssen. Für produktionskritische Domains empfiehlt sich trotzdem redundantes Monitoring über zwei unabhängige Wege, etwa Cronjob und CI-Pipeline gleichzeitig, damit ein Ausfall des einen Systems nicht zum blinden Fleck wird.

9. openssl vs. curl vs. spezialisierte Tools im Vergleich

openssl s_client bleibt die flexibelste und am weitesten verbreitete Methode, um TLS-Zertifikat-Ablauf zu überwachen, weil es auf praktisch jedem System vorhanden ist und die komplette Kontrolle über die Verbindung bietet. curl -vI https://host liefert ebenfalls Zertifikatsinformationen, aber in einem Format, das schwerer robust zu parsen ist als die klare x509 -noout -enddate-Ausgabe von openssl.

Spezialisierte Tools wie check_ssl_cert für Nagios bieten zusätzliche Prüfungen wie Schlüssellänge, unterstützte Cipher-Suiten und Revocation-Status, was für sicherheitskritische Umgebungen relevant sein kann. Für die reine Ablaufüberwachung, dem Kern jedes Skripts, das TLS-Zertifikat-Ablauf überwacht, ist ein selbst geschriebenes openssl-basiertes Skript aber oft ausreichend und deutlich einfacher zu warten als eine zusätzliche Tool-Abhängigkeit.

10. Zusammenfassung

TLS-Zertifikat-Ablauf überwachen mit Bash bedeutet, openssl s_client und x509 -noout -enddate zu kombinieren, das Ergebnis in verbleibende Tage umzurechnen und gegen definierte Schwellenwerte zu prüfen. Für mehrere Domains skaliert eine Schleife mit optionaler Parallelisierung, für Monitoring-Systeme liefern Nagios-kompatible Exit-Codes die nötige Integration, und für Teams ohne Nagios erledigen Webhook-Benachrichtigungen dieselbe Aufgabe direkt.

Der entscheidende Vorteil eines solchen Skripts liegt in der Unabhängigkeit vom eigentlichen Renewal-Prozess: Es prüft die tatsächlich nach außen sichtbare Gültigkeit, nicht nur ob ein Cronjob fehlerfrei durchgelaufen ist. Wer TLS-Zertifikat-Ablauf überwachen als tägliche, automatisierte Routine etabliert, verhindert damit eine der vermeidbarsten Ursachen für Produktionsausfälle.

TLS-Zertifikat-Ablauf mit Bash überwachen — Das Wichtigste auf einen Blick

Abruf

openssl s_client -servername HOST gefolgt von x509 -noout -enddate für das Ablaufdatum.

Umrechnung

date -d "$expiry" +%s minus aktueller Timestamp, geteilt durch 86400 für verbleibende Tage.

Schwellenwerte

Nagios-kompatible Exit-Codes (0/1/2/3) für Warning bei 30 und Critical bei 7 Tagen.

Automatisierung

Täglicher Cronjob oder CI-Scheduled-Pipeline, unabhängig vom Renewal-Prozess selbst.

11. FAQ: TLS-Zertifikat-Ablauf mit Bash überwachen

1Renewal-Cronjob überwachen reicht nicht?
Ein Job kann fehlerfrei laufen und trotzdem ein falsches Zertifikat hinterlassen. Unabhängige externe Prüfung deckt das auf.
2Warum -servername wichtig?
Ohne SNI liefert der Server oft ein falsches Standardzertifikat statt des für die Domain konfigurierten.
3Ablaufdatum in Tage umrechnen?
date -d in Unix-Timestamp umwandeln, aktuellen Timestamp abziehen, durch 86400 teilen.
4Welche Exit-Codes für Nagios?
0 OK, 1 Warning, 2 Critical, 3 Unknown. Performance-Daten mit | days_remaining=N für Trends.
5Viele Domains performant prüfen?
Mit Hintergrundprozessen parallelisieren, jede Prüfung ist unabhängig, wait sammelt die Ergebnisse.
6Zwischenzertifikate prüfen?
openssl s_client -showcerts liefert die komplette Kette, jedes Zertifikat einzeln prüfbar.
7Tägliche Wiederholungs-Alarme vermeiden?
State-Datei mit zuletzt benachrichtigtem Tag verhindert doppelte Meldungen.
8Cronjob oder auch CI?
Cronjob reicht meist. Für kritische Domains redundant über Cron und CI-Pipeline gleichzeitig.
9curl -vI statt openssl?
Liefert ähnliche Daten, aber schwerer robust zu parsen als die klare openssl x509 enddate-Ausgabe.
10Unterschied zu check_ssl_cert?
Spezialisierte Tools prüfen zusätzlich Schlüssellänge und Revocation. Für reine Ablaufprüfung reicht ein eigenes Skript.