diff --git a/monitoring/grafana/dashboards/security/clamav-blocks.json b/monitoring/grafana/dashboards/security/clamav-blocks.json new file mode 100644 index 0000000..4e01f9b --- /dev/null +++ b/monitoring/grafana/dashboards/security/clamav-blocks.json @@ -0,0 +1,146 @@ +{ + "uid": "threadnet-clamav", + "title": "ClamAV — blockierte Inhalte", + "description": "Wie oft ClamAV tatsaechlich etwas blockiert (management #0077). Zwei Quellen: der Client-seitige Scanner (clamav-http-scanner, greift beim Senden UND beim Empfangen, deckt auch E2E-verschluesselte Raeume ab) und das Synapse-Modul (nur unverschluesselte Uploads). Das dritte Panel zeigt Fail-open-Faelle - wenn clamd nicht erreichbar ist, laesst der Scanner Dateien bewusst durch; ohne dieses Panel bliebe das unsichtbar.", + "tags": ["security", "clamav", "matrix"], + "timezone": "browser", + "schemaVersion": 41, + "editable": true, + "time": { "from": "now-7d", "to": "now" }, + "refresh": "5m", + "panels": [ + { + "type": "stat", + "title": "Blockiert — Client (Senden + Empfangen)", + "description": "clamav-http-scanner. Deckt auch verschluesselte Raeume ab, weil der Client vor dem Verschluesseln bzw. nach dem Entschluesseln prueft.", + "gridPos": { "h": 4, "w": 8, "x": 0, "y": 0 }, + "datasource": { "type": "loki", "uid": "cfk1pam8svmkgd" }, + "targets": [ + { + "refId": "A", + "datasource": { "type": "loki", "uid": "cfk1pam8svmkgd" }, + "queryType": "instant", + "expr": "sum(count_over_time({job=\"loki.source.kubernetes.k8s_logs\", instance=~\"matrix/clamav-http-scanner.*\"} |= \"ClamAV flagged\" [$__range]))" + } + ], + "options": { "reduceOptions": { "calcs": ["lastNotNull"] }, "colorMode": "value", "graphMode": "none" }, + "fieldConfig": { + "defaults": { + "unit": "short", + "thresholds": { "mode": "absolute", "steps": [ { "color": "green", "value": null }, { "color": "orange", "value": 1 } ] } + }, + "overrides": [] + } + }, + { + "type": "stat", + "title": "Blockiert — Synapse-Modul", + "description": "Server-seitiges Modul, sieht nur unverschluesselte Uploads. Null ist hier der Normalfall, solange der Client schon vor dem Upload blockt.", + "gridPos": { "h": 4, "w": 8, "x": 8, "y": 0 }, + "datasource": { "type": "loki", "uid": "cfk1pam8svmkgd" }, + "targets": [ + { + "refId": "A", + "datasource": { "type": "loki", "uid": "cfk1pam8svmkgd" }, + "queryType": "instant", + "expr": "sum(count_over_time({job=\"loki.source.kubernetes.k8s_logs\", instance=~\"matrix/matrix-stack-synapse.*\"} |= \"ClamAV rejected an upload\" [$__range]))" + } + ], + "options": { "reduceOptions": { "calcs": ["lastNotNull"] }, "colorMode": "value", "graphMode": "none" }, + "fieldConfig": { + "defaults": { + "unit": "short", + "thresholds": { "mode": "absolute", "steps": [ { "color": "green", "value": null }, { "color": "orange", "value": 1 } ] } + }, + "overrides": [] + } + }, + { + "type": "stat", + "title": "Fail-open — Scanner nicht erreichbar", + "description": "Wenn clamd nicht antwortet, laesst der Scanner die Datei bewusst durch (fail-open). Jeder Treffer hier ist eine Datei, die UNGEPRUEFT durchging - deshalb rot ab eins.", + "gridPos": { "h": 4, "w": 8, "x": 16, "y": 0 }, + "datasource": { "type": "loki", "uid": "cfk1pam8svmkgd" }, + "targets": [ + { + "refId": "A", + "datasource": { "type": "loki", "uid": "cfk1pam8svmkgd" }, + "queryType": "instant", + "expr": "sum(count_over_time({job=\"loki.source.kubernetes.k8s_logs\", instance=~\"matrix/clamav-http-scanner.*\"} |= \"ClamAV scan failed\" [$__range]))" + } + ], + "options": { "reduceOptions": { "calcs": ["lastNotNull"] }, "colorMode": "background", "graphMode": "none" }, + "fieldConfig": { + "defaults": { + "unit": "short", + "thresholds": { "mode": "absolute", "steps": [ { "color": "green", "value": null }, { "color": "red", "value": 1 } ] } + }, + "overrides": [] + } + }, + { + "type": "timeseries", + "title": "Blockierte Inhalte ueber Zeit", + "gridPos": { "h": 8, "w": 14, "x": 0, "y": 4 }, + "datasource": { "type": "loki", "uid": "cfk1pam8svmkgd" }, + "targets": [ + { + "refId": "A", + "datasource": { "type": "loki", "uid": "cfk1pam8svmkgd" }, + "legendFormat": "Client (Senden/Empfangen)", + "expr": "sum(count_over_time({job=\"loki.source.kubernetes.k8s_logs\", instance=~\"matrix/clamav-http-scanner.*\"} |= \"ClamAV flagged\" [$__interval]))" + }, + { + "refId": "B", + "datasource": { "type": "loki", "uid": "cfk1pam8svmkgd" }, + "legendFormat": "Synapse-Modul", + "expr": "sum(count_over_time({job=\"loki.source.kubernetes.k8s_logs\", instance=~\"matrix/matrix-stack-synapse.*\"} |= \"ClamAV rejected an upload\" [$__interval]))" + }, + { + "refId": "C", + "datasource": { "type": "loki", "uid": "cfk1pam8svmkgd" }, + "legendFormat": "Fail-open", + "expr": "sum(count_over_time({job=\"loki.source.kubernetes.k8s_logs\", instance=~\"matrix/clamav-http-scanner.*\"} |= \"ClamAV scan failed\" [$__interval]))" + } + ], + "fieldConfig": { + "defaults": { "unit": "short", "custom": { "drawStyle": "bars", "fillOpacity": 60, "stacking": { "mode": "normal" } } }, + "overrides": [] + }, + "options": { "legend": { "displayMode": "list", "placement": "bottom", "showLegend": true }, "tooltip": { "mode": "multi" } } + }, + { + "type": "table", + "title": "Nach Signatur", + "description": "Welche Schadsoftware tatsaechlich auftaucht. Die Signatur wird aus der Logzeile geschnitten.", + "gridPos": { "h": 8, "w": 10, "x": 14, "y": 4 }, + "datasource": { "type": "loki", "uid": "cfk1pam8svmkgd" }, + "targets": [ + { + "refId": "A", + "datasource": { "type": "loki", "uid": "cfk1pam8svmkgd" }, + "queryType": "instant", + "format": "table", + "expr": "sum by (signature) (count_over_time({job=\"loki.source.kubernetes.k8s_logs\", instance=~\"matrix/clamav-http-scanner.*\"} |= \"ClamAV flagged\" | regexp \"ClamAV flagged an upload/download: (?P[^\\\\s]+)\" [$__range]))" + } + ], + "transformations": [ { "id": "organize", "options": { "excludeByName": { "Time": true } } } ], + "fieldConfig": { "defaults": {}, "overrides": [] } + }, + { + "type": "logs", + "title": "Ereignisse", + "description": "Rohzeilen beider Quellen, neueste zuerst.", + "gridPos": { "h": 9, "w": 24, "x": 0, "y": 12 }, + "datasource": { "type": "loki", "uid": "cfk1pam8svmkgd" }, + "targets": [ + { + "refId": "A", + "datasource": { "type": "loki", "uid": "cfk1pam8svmkgd" }, + "expr": "{job=\"loki.source.kubernetes.k8s_logs\", instance=~\"matrix/(clamav-http-scanner|matrix-stack-synapse).*\"} |~ \"ClamAV (flagged|rejected an upload|scan failed)\"" + } + ], + "options": { "showTime": true, "sortOrder": "Descending", "wrapLogMessage": true } + } + ] +}