Komplexität: Niedrig
Dauer: 30 Minuten Setup
Ziel: CRL/OCSP Verfügbarkeit sicherstellen
Überwachung der Widerrufsinformation (CRL und OCSP) für eine funktionierende PKI.
#!/bin/bash # /usr/local/bin/check-crl.sh CRL_URLS=( "http://crl.example.com/intermediate.crl" "http://crl.example.com/root.crl" ) WARN_HOURS=72 # Warnung wenn < 3 Tage bis Next Update CRIT_HOURS=24 # Kritisch wenn < 1 Tag bis Next Update for url in "${CRL_URLS[@]}"; do echo "Prüfe: $url" # CRL herunterladen crl_data=$(curl -sf --max-time 10 "$url") if [ $? -ne 0 ]; then echo "FEHLER: CRL nicht erreichbar - $url" continue fi # CRL parsen (DER oder PEM) if [[ "$crl_data" == *"-----BEGIN"* ]]; then crl_info=$(echo "$crl_data" | openssl crl -text -noout) else crl_info=$(echo "$crl_data" | openssl crl -inform DER -text -noout) fi # Next Update extrahieren next_update=$(echo "$crl_info" | grep "Next Update" | sed 's/.*: //') next_epoch=$(date -d "$next_update" +%s) now_epoch=$(date +%s) hours_left=$(( (next_epoch - now_epoch) / 3600 )) # CRL Number crl_number=$(echo "$crl_info" | grep -A1 "CRL Number" | tail -1 | tr -d ' ') # Status ausgeben if [ "$hours_left" -lt 0 ]; then echo "KRITISCH: CRL abgelaufen! - $url" elif [ "$hours_left" -lt "$CRIT_HOURS" ]; then echo "KRITISCH: CRL läuft in $hours_left Stunden ab - $url" elif [ "$hours_left" -lt "$WARN_HOURS" ]; then echo "WARNUNG: CRL läuft in $hours_left Stunden ab - $url" else echo "OK: CRL gültig für $hours_left Stunden - $url (CRL#: $crl_number)" fi # Anzahl widerrufener Zertifikate revoked_count=$(echo "$crl_info" | grep -c "Serial Number:") echo " Widerrufen: $revoked_count Zertifikate" echo "" done
#!/bin/bash # crl-exporter.sh - Generiert Prometheus-Metriken METRICS_FILE="/var/lib/node_exporter/textfile_collector/crl.prom" cat /dev/null > "$METRICS_FILE" CRL_URLS=( "intermediate|http://crl.example.com/intermediate.crl" "root|http://crl.example.com/root.crl" ) for entry in "${CRL_URLS[@]}"; do IFS='|' read -r name url <<< "$entry" crl_data=$(curl -sf --max-time 10 "$url" 2>/dev/null) if [ $? -ne 0 ]; then echo "crl_reachable{name=\"$name\"} 0" >> "$METRICS_FILE" continue fi echo "crl_reachable{name=\"$name\"} 1" >> "$METRICS_FILE" next_update=$(echo "$crl_data" | openssl crl -inform DER -nextupdate -noout 2>/dev/null | cut -d= -f2) if [ -n "$next_update" ]; then next_epoch=$(date -d "$next_update" +%s) echo "crl_next_update_timestamp{name=\"$name\"} $next_epoch" >> "$METRICS_FILE" fi revoked=$(echo "$crl_data" | openssl crl -inform DER -text -noout 2>/dev/null | grep -c "Serial Number:") echo "crl_revoked_count{name=\"$name\"} $revoked" >> "$METRICS_FILE" done
Alert Rule:
- alert: CRLExpiringSoon expr: crl_next_update_timestamp - time() < 86400 labels: severity: critical annotations: summary: "CRL {{ $labels.name }} läuft in < 24h ab" - alert: CRLUnreachable expr: crl_reachable == 0 for: 5m labels: severity: critical annotations: summary: "CRL {{ $labels.name }} nicht erreichbar"
#!/bin/bash # /usr/local/bin/check-ocsp.sh OCSP_URL="http://ocsp.example.com" ISSUER_CERT="/etc/pki/CA/intermediate-ca.pem" TEST_CERT="/etc/ssl/certs/test-server.pem" echo "OCSP Responder Check: $OCSP_URL" # OCSP Request senden start_time=$(date +%s%N) response=$(openssl ocsp \ -issuer "$ISSUER_CERT" \ -cert "$TEST_CERT" \ -url "$OCSP_URL" \ -resp_text 2>&1) end_time=$(date +%s%N) # Response-Zeit berechnen (ms) response_time=$(( (end_time - start_time) / 1000000 )) # Status extrahieren if echo "$response" | grep -q "good"; then status="good" elif echo "$response" | grep -q "revoked"; then status="revoked" else status="error" fi # Ausgabe echo "Status: $status" echo "Response-Zeit: ${response_time}ms" if [ "$status" = "error" ]; then echo "FEHLER: OCSP Responder nicht funktionsfähig" exit 1 fi if [ "$response_time" -gt 2000 ]; then echo "WARNUNG: OCSP Response-Zeit > 2s" fi
#!/bin/bash # ocsp-exporter.sh METRICS_FILE="/var/lib/node_exporter/textfile_collector/ocsp.prom" OCSP_ENDPOINTS=( "intermediate|http://ocsp.example.com|/etc/pki/CA/intermediate.pem|/etc/ssl/certs/test.pem" ) cat /dev/null > "$METRICS_FILE" for entry in "${OCSP_ENDPOINTS[@]}"; do IFS='|' read -r name url issuer cert <<< "$entry" start_time=$(date +%s%N) response=$(openssl ocsp -issuer "$issuer" -cert "$cert" -url "$url" -resp_text 2>&1) exit_code=$? end_time=$(date +%s%N) response_time=$(( (end_time - start_time) / 1000000 )) echo "ocsp_response_time_ms{name=\"$name\"} $response_time" >> "$METRICS_FILE" if [ $exit_code -eq 0 ]; then echo "ocsp_up{name=\"$name\"} 1" >> "$METRICS_FILE" else echo "ocsp_up{name=\"$name\"} 0" >> "$METRICS_FILE" fi if echo "$response" | grep -q "good"; then echo "ocsp_status{name=\"$name\"} 0" >> "$METRICS_FILE" # 0=good elif echo "$response" | grep -q "revoked"; then echo "ocsp_status{name=\"$name\"} 1" >> "$METRICS_FILE" # 1=revoked else echo "ocsp_status{name=\"$name\"} 2" >> "$METRICS_FILE" # 2=unknown/error fi done
Alert Rules:
- alert: OCSPResponderDown expr: ocsp_up == 0 for: 2m labels: severity: critical annotations: summary: "OCSP Responder {{ $labels.name }} nicht erreichbar" - alert: OCSPResponseSlow expr: ocsp_response_time_ms > 2000 for: 5m labels: severity: warning annotations: summary: "OCSP {{ $labels.name }} langsam: {{ $value }}ms"
# blackbox.yml modules: tls_connect: prober: tcp timeout: 5s tcp: tls: true tls_config: insecure_skip_verify: false http_crl: prober: http timeout: 10s http: method: GET valid_status_codes: [200] fail_if_body_not_matches_regexp: ["-----BEGIN X509 CRL-----|^\x30"] ocsp_check: prober: http timeout: 5s http: method: POST headers: Content-Type: application/ocsp-request
# Check-Revocation.ps1 param( [string]$OcspUrl = "http://ocsp.example.com", [string]$CrlUrl = "http://crl.example.com/intermediate.crl" ) # CRL prüfen Write-Host "=== CRL Check ===" -ForegroundColor Cyan try { $crlResponse = Invoke-WebRequest -Uri $CrlUrl -TimeoutSec 10 Write-Host "CRL erreichbar: OK ($($crlResponse.StatusCode))" -ForegroundColor Green # CRL parsen (erfordert zusätzliche Tools oder .NET) $crlBytes = $crlResponse.Content # ... CRL-Parsing hier } catch { Write-Host "CRL FEHLER: $_" -ForegroundColor Red } # OCSP prüfen (vereinfacht via openssl) Write-Host "`n=== OCSP Check ===" -ForegroundColor Cyan try { $certPath = "C:\certs\test.pem" $issuerPath = "C:\certs\intermediate.pem" $ocspResult = & openssl ocsp -issuer $issuerPath -cert $certPath -url $OcspUrl -text 2>&1 if ($ocspResult -match "good") { Write-Host "OCSP Status: GOOD" -ForegroundColor Green } elseif ($ocspResult -match "revoked") { Write-Host "OCSP Status: REVOKED" -ForegroundColor Yellow } else { Write-Host "OCSP Status: ERROR" -ForegroundColor Red } } catch { Write-Host "OCSP FEHLER: $_" -ForegroundColor Red }
| # | Prüfpunkt | ✓ |
| — | ———– | — |
| 1 | CRL-URLs definiert | ☐ |
| 2 | CRL-Download funktioniert | ☐ |
| 3 | CRL-Ablaufwarnung konfiguriert | ☐ |
| 4 | OCSP-URL definiert | ☐ |
| 5 | OCSP-Response funktioniert | ☐ |
| 6 | Prometheus Exporter aktiv | ☐ |
| 7 | Alerts konfiguriert | ☐ |
« ← Ablauf-Monitoring | → Audit-Logging »
Wolfgang van der Stille @ EMSR DATA d.o.o. - Post-Quantum Cryptography Professional