Inhaltsverzeichnis
Provjera opoziva
Složenost: Niska
Trajanje: 30 minuta postavljanja
Cilj: Osiguranje dostupnosti CRL/OCSP
Nadzor informacija o opozivu (CRL i OCSP) za funkcionalni PKI.
Arhitektura
flowchart LR
subgraph CHECK["🔍 PROVJERA"]
C1[CRL preuzimanje]
C2[CRL parsiranje]
C3[OCSP zahtjev]
end
subgraph VALIDATE["✅ VALIDACIJA"]
V1[Potpis OK?]
V2[Nije istekao?]
V3[Dostupan?]
end
subgraph ALERT["🚨 ALERT"]
A1[CRL istekao]
A2[OCSP Timeout]
A3[CDP nedostupan]
end
C1 --> V1 & V2
C3 --> V3
V1 -->|Ne| A1
V2 -->|Ne| A1
V3 -->|Ne| A2
style A1 fill:#ffebee
style A2 fill:#ffebee
CRL Monitoring
Provjera CRL statusa
#!/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 # Upozorenje ako < 3 dana do Next Update CRIT_HOURS=24 # Kritično ako < 1 dan do Next Update for url in "${CRL_URLS[@]}"; do echo "Provjera: $url" # Preuzimanje CRL-a crl_data=$(curl -sf --max-time 10 "$url") if [ $? -ne 0 ]; then echo "GREŠKA: CRL nije dostupan - $url" continue fi # Parsiranje CRL-a (DER ili 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 # Ekstrakcija Next Update 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 ' ') # Izlaz statusa if [ "$hours_left" -lt 0 ]; then echo "KRITIČNO: CRL istekao! - $url" elif [ "$hours_left" -lt "$CRIT_HOURS" ]; then echo "KRITIČNO: CRL ističe za $hours_left sati - $url" elif [ "$hours_left" -lt "$WARN_HOURS" ]; then echo "UPOZORENJE: CRL ističe za $hours_left sati - $url" else echo "OK: CRL valjan još $hours_left sati - $url (CRL#: $crl_number)" fi # Broj opozvanih certifikata revoked_count=$(echo "$crl_info" | grep -c "Serial Number:") echo " Opozvano: $revoked_count certifikata" echo "" done
Prometheus Exporter za CRL
#!/bin/bash # crl-exporter.sh - Generira Prometheus metrike 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 }} ističe za < 24h" - alert: CRLUnreachable expr: crl_reachable == 0 for: 5m labels: severity: critical annotations: summary: "CRL {{ $labels.name }} nije dostupan"
OCSP Monitoring
Provjera OCSP respondera
#!/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" # Slanje OCSP zahtjeva 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) # Izračun vremena odziva (ms) response_time=$(( (end_time - start_time) / 1000000 )) # Ekstrakcija statusa if echo "$response" | grep -q "good"; then status="good" elif echo "$response" | grep -q "revoked"; then status="revoked" else status="error" fi # Izlaz echo "Status: $status" echo "Vrijeme odziva: ${response_time}ms" if [ "$status" = "error" ]; then echo "GREŠKA: OCSP Responder ne funkcionira" exit 1 fi if [ "$response_time" -gt 2000 ]; then echo "UPOZORENJE: Vrijeme odziva OCSP > 2s" fi
OCSP Prometheus Exporter
#!/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 }} nije dostupan" - alert: OCSPResponseSlow expr: ocsp_response_time_ms > 2000 for: 5m labels: severity: warning annotations: summary: "OCSP {{ $labels.name }} spor: {{ $value }}ms"
Blackbox Exporter
# 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
PowerShell (Windows)
# Check-Revocation.ps1 param( [string]$OcspUrl = "http://ocsp.example.com", [string]$CrlUrl = "http://crl.example.com/intermediate.crl" ) # Provjera CRL-a Write-Host "=== CRL Check ===" -ForegroundColor Cyan try { $crlResponse = Invoke-WebRequest -Uri $CrlUrl -TimeoutSec 10 Write-Host "CRL dostupan: OK ($($crlResponse.StatusCode))" -ForegroundColor Green # Parsiranje CRL-a (zahtijeva dodatne alate ili .NET) $crlBytes = $crlResponse.Content # ... CRL parsiranje ovdje } catch { Write-Host "CRL GREŠKA: $_" -ForegroundColor Red } # Provjera OCSP-a (pojednostavljeno putem 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 GREŠKA: $_" -ForegroundColor Red }
Kontrolna lista
| # | Točka provjere | ✓ |
| — | —————- | — |
| 1 | CRL URL-ovi definirani | ☐ |
| 2 | CRL preuzimanje funkcionira | ☐ |
| 3 | Upozorenje za istek CRL-a konfigurirano | ☐ |
| 4 | OCSP URL definiran | ☐ |
| 5 | OCSP odziv funkcionira | ☐ |
| 6 | Prometheus Exporter aktivan | ☐ |
| 7 | Alerti konfigurirani | ☐ |
Povezana dokumentacija
- Opoziv certifikata – Ažuriranje CRL-a
- Monitoring isteka – Istek certifikata
- Scenariji opoziva – Detaljne upute
« ← Monitoring isteka | → Audit Logging »
Wolfgang van der Stille @ EMSR DATA d.o.o. - Post-Quantum Cryptography Professional
Zuletzt geändert: 30.01.2026. u 06:32