====== Monitoring isteka ====== **Složenost:** Niska-Srednja \\ **Trajanje:** 1-2 sata postavljanja \\ **Cilj:** Niti jedan certifikat ne smije neprimijećeno isteći Nadzor datuma isteka certifikata s različitim alatima i strategijama upozorenja. ---- ===== Arhitektura ===== flowchart LR subgraph SOURCES["📁 IZVORI"] F[Datotečni sustav] K[Kubernetes Secrets] R[Udaljeni TLS] S[Spremišta certifikata] end subgraph COLLECTOR["📊 COLLECTOR"] E[cert-exporter] N[node_exporter] B[blackbox_exporter] end subgraph STORAGE["💾 PROMETHEUS"] P[(Prometheus)] end subgraph ALERT["🚨 ALERT"] A[Alertmanager] M[E-Mail/Slack/Teams] end F --> E --> P --> A --> M K --> E R --> B --> P S --> N --> P style A fill:#ffebee style P fill:#e3f2fd ---- ===== Opcija 1: Prometheus + cert-exporter ===== ==== Instalacija ==== # Preuzimanje cert-exportera wget https://github.com/enix/x509-certificate-exporter/releases/download/v3.12.0/x509-certificate-exporter_3.12.0_linux_amd64.tar.gz tar xzf x509-certificate-exporter_*.tar.gz sudo mv x509-certificate-exporter /usr/local/bin/ # Kreiranje Systemd servisa cat << 'EOF' | sudo tee /etc/systemd/system/cert-exporter.service [Unit] Description=X509 Certificate Exporter After=network.target [Service] Type=simple ExecStart=/usr/local/bin/x509-certificate-exporter \ --watch-file=/etc/ssl/certs/*.pem \ --watch-file=/etc/nginx/ssl/*.crt \ --watch-kubeconf=false Restart=always [Install] WantedBy=multi-user.target EOF sudo systemctl daemon-reload sudo systemctl enable --now cert-exporter ==== Prometheus konfiguracija ==== # /etc/prometheus/prometheus.yml scrape_configs: - job_name: 'cert-exporter' static_configs: - targets: ['localhost:9793'] relabel_configs: - source_labels: [__address__] target_label: instance replacement: 'pki-server' # Provjera udaljenih TLS endpointa - job_name: 'blackbox-tls' metrics_path: /probe params: module: [tls_connect] static_configs: - targets: - https://api.example.com - https://web.example.com - https://mail.example.com:465 relabel_configs: - source_labels: [__address__] target_label: __param_target - source_labels: [__param_target] target_label: instance - target_label: __address__ replacement: blackbox-exporter:9115 ==== Alert Rules ==== # /etc/prometheus/rules/cert-alerts.yml groups: - name: certificate-alerts rules: - alert: CertificateExpiringSoon expr: x509_cert_not_after - time() < 30 * 24 * 3600 for: 1h labels: severity: warning annotations: summary: "Certifikat {{ $labels.filepath }} ističe za < 30 dana" description: "Preostalo vrijeme: {{ $value | humanizeDuration }}" - alert: CertificateExpireCritical expr: x509_cert_not_after - time() < 7 * 24 * 3600 for: 10m labels: severity: critical annotations: summary: "KRITIČNO: Certifikat {{ $labels.filepath }} ističe za < 7 dana" description: "Datum isteka: {{ $value | humanizeTimestamp }}" - alert: CertificateExpired expr: x509_cert_not_after - time() < 0 for: 0m labels: severity: critical annotations: summary: "Certifikat {{ $labels.filepath }} je ISTEKAO" - alert: CAExpiringSoon expr: x509_cert_not_after{is_ca="true"} - time() < 365 * 24 * 3600 for: 1d labels: severity: warning annotations: summary: "CA certifikat {{ $labels.subject }} ističe za < 1 godinu" ---- ===== Opcija 2: Grafana Dashboard ===== { "dashboard": { "title": "Certificate Expiry Dashboard", "panels": [ { "title": "Certifikati koji ističu (< 30 dana)", "type": "table", "targets": [ { "expr": "sort_desc((x509_cert_not_after - time()) / 86400)", "format": "table" } ], "fieldConfig": { "overrides": [ { "matcher": { "id": "byName", "options": "Value" }, "properties": [ { "id": "custom.displayMode", "value": "color-background" }, { "id": "thresholds", "value": { "steps": [ { "color": "red", "value": 0 }, { "color": "orange", "value": 7 }, { "color": "yellow", "value": 30 }, { "color": "green", "value": 90 } ] } } ] } ] } }, { "title": "Certifikati prema vremenu isteka", "type": "stat", "targets": [ { "expr": "count(x509_cert_not_after - time() < 7 * 86400)", "legendFormat": "< 7 dana" }, { "expr": "count(x509_cert_not_after - time() < 30 * 86400)", "legendFormat": "< 30 dana" } ] } ] } } ---- ===== Opcija 3: Jednostavna skripta (bez Prometheusa) ===== #!/bin/bash # /usr/local/bin/cert-check-notify.sh WARN_DAYS=30 CRIT_DAYS=7 MAIL_TO="pki-team@example.com" WEBHOOK_URL="https://teams.example.com/webhook/..." check_cert() { local cert="$1" local days_left=$(( ($(openssl x509 -enddate -noout -in "$cert" 2>/dev/null | cut -d= -f2 | date -f - +%s) - $(date +%s)) / 86400 )) local subject=$(openssl x509 -subject -noout -in "$cert" 2>/dev/null | sed 's/subject=//') if [ "$days_left" -lt 0 ]; then echo "EXPIRED|$cert|$subject|$days_left" elif [ "$days_left" -lt "$CRIT_DAYS" ]; then echo "CRITICAL|$cert|$subject|$days_left" elif [ "$days_left" -lt "$WARN_DAYS" ]; then echo "WARNING|$cert|$subject|$days_left" fi } # Provjera svih certifikata results="" for cert in /etc/ssl/certs/*.pem /etc/nginx/ssl/*.crt; do [ -f "$cert" ] || continue result=$(check_cert "$cert") [ -n "$result" ] && results+="$result\n" done # Slanje obavijesti ako je potrebno if [ -n "$results" ]; then # E-Mail echo -e "Pronađeni problemi s certifikatima:\n\n$results" | \ mail -s "PKI Alert: Certifikati" "$MAIL_TO" # Teams/Slack Webhook curl -s -X POST "$WEBHOOK_URL" \ -H "Content-Type: application/json" \ -d "{\"text\": \"PKI Alert: Certifikati\n\n$(echo -e "$results" | sed 's/|/ | /g')\"}" fi # Cron: Dnevno u 08:00 echo "0 8 * * * root /usr/local/bin/cert-check-notify.sh" > /etc/cron.d/cert-check ---- ===== Opcija 4: PowerShell (Windows) ===== # Check-CertificateExpiry.ps1 param( [int]$WarnDays = 30, [int]$CritDays = 7, [string]$SmtpServer = "smtp.example.com", [string]$MailTo = "pki-team@example.com" ) $results = @() # Lokalni certifikati Get-ChildItem Cert:\LocalMachine\My | ForEach-Object { $daysLeft = ($_.NotAfter - (Get-Date)).Days $severity = if ($daysLeft -lt 0) { "EXPIRED" } elseif ($daysLeft -lt $CritDays) { "CRITICAL" } elseif ($daysLeft -lt $WarnDays) { "WARNING" } else { $null } if ($severity) { $results += [PSCustomObject]@{ Severity = $severity Subject = $_.Subject Thumbprint = $_.Thumbprint DaysLeft = $daysLeft NotAfter = $_.NotAfter } } } # Udaljeni TLS endpointi $endpoints = @( "api.example.com:443", "web.example.com:443" ) foreach ($endpoint in $endpoints) { try { $host, $port = $endpoint -split ':' $cert = (New-Object System.Net.Sockets.TcpClient($host, [int]$port)).GetStream() | ForEach-Object { (New-Object System.Net.Security.SslStream($_)).AuthenticateAsClient($host); $_.RemoteCertificate } $daysLeft = ($cert.NotAfter - (Get-Date)).Days # ... analogno kao gore } catch { $results += [PSCustomObject]@{ Severity = "ERROR" Subject = $endpoint Thumbprint = "N/A" DaysLeft = -1 NotAfter = "Connection failed: $_" } } } # Slanje izvještaja if ($results.Count -gt 0) { $body = $results | Format-Table -AutoSize | Out-String Send-MailMessage -To $MailTo -From "pki@example.com" ` -Subject "PKI Alert: $($results.Count) certifikat(a) zahtijeva pažnju" ` -Body $body ` -SmtpServer $SmtpServer } # Izlaz za logiranje $results | Format-Table ---- ===== Kubernetes: cert-manager Metrike ===== # ServiceMonitor za cert-manager apiVersion: monitoring.coreos.com/v1 kind: ServiceMonitor metadata: name: cert-manager namespace: monitoring spec: selector: matchLabels: app.kubernetes.io/name: cert-manager namespaceSelector: matchNames: - cert-manager endpoints: - port: tcp-prometheus-servicemonitor interval: 60s **Važne metrike:** | Metrika | Opis | |---------|------| | ''certmanager_certificate_expiration_timestamp_seconds'' | Vrijeme isteka | | ''certmanager_certificate_ready_status'' | Ready-Status (1=OK) | | ''certmanager_certificate_renewal_timestamp_seconds'' | Posljednja obnova | ---- ===== Najbolje prakse ===== | Preporuka | Obrazloženje | |-----------|--------------| | **30/14/7/1 dan** Alerti | Stupnjevita eskalacija | | **CA certifikati zasebno** | Duže vrijeme upozorenja (1 godina) | | **Udaljeno + Lokalno** provjera | Različiti izvori grešaka | | **Deduplikacija** | Ne 100 alertova za 1 certifikat | | **Runbook link** u alertu | Direktne upute za djelovanje | ---- ===== Kontrolna lista ===== | # | Točka provjere | ✓ | |---|----------------|---| | 1 | Exporter instaliran | ☐ | | 2 | Prometheus Scrape konfiguriran | ☐ | | 3 | Alert Rules definirani | ☐ | | 4 | Alertmanager Routing | ☐ | | 5 | Grafana Dashboard | ☐ | | 6 | Test-Alert poslan | ☐ | ---- ===== Povezana dokumentacija ===== * [[.:alerting-setup|Alerting Setup]] – Konfiguracija obavijesti * [[..:tagesgeschaeft:health-check|Health Check]] – Ručna provjera * [[..:automatisierung:scheduled-renewal|Scheduled Renewal]] – Auto-Renewal ---- << [[.:start|← Monitoring]] | [[.:revocation-check|→ Provjera opoziva]] >> ---- //Wolfgang van der Stille @ EMSR DATA d.o.o. - Post-Quantum Cryptography Professional// {{tag>monitoring prometheus grafana istek expiry operator}}