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.
Inhaltsverzeichnis
- 1. Warum TLS-Zertifikat-Ablauf überwachen zum Standard gehört
- 2. Mit openssl s_client das Zertifikat eines Endpunkts abrufen
- 3. Ablaufdatum extrahieren und in Tage umrechnen
- 4. Mehrere Domains gleichzeitig prüfen
- 5. Schwellenwerte und Nagios-kompatible Exit-Codes
- 6. Benachrichtigungen bei bevorstehendem Ablauf
- 7. Zertifikatsketten und Zwischenzertifikate prüfen
- 8. Integration in Cron und CI für tägliche Prüfung
- 9. openssl vs. curl vs. spezialisierte Tools im Vergleich
- 10. Zusammenfassung
- 11. FAQ
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.