SIEM mit KI anreichern
Standard-Wazuh-Alarme in hochpriorisierte, von KI analysierte Vorfallberichte umwandeln.

Ich arbeite aktuell daran, meine Alarme in meinem SIEM mit KI anzureichern. Obwohl das Projekt noch in Arbeit ist, möchte ich schon jetzt einen Einblick in meinen bisherigen Fortschritt geben.
Lokale KI?
Ich nutze in meiner kleinen Cloud im Keller ollama, um all meinen Diensten größeren Funktionsumfang zur Verfügung zu stellen. Warum also nicht auch bei Alarmen in wazuh?
Das Gesamtbild: Von Alarm bis zur KI-Analyse
Der Prozess ist ebenso geradlinig wie wirkungsvoll. Zuerst erkennt Wazuh einen verdächtigen Vorfall, beispielsweise einen Brute-Force-Angriff. Anstatt nur einen simplen Alarm zu erzeugen, startet Wazuh eine Active Response. Diese führt ein Skript aus, das alle zugehörigen Log-Einträge sammelt und sie an eine lokale KI – in diesem Fall über Ollama – zur Analyse sendet. Die von der KI erstellte Zusammenfassung wird in eine dedizierte Log-Datei geschrieben, welche Wazuh wiederum überwacht, um einen neuen, hoch priorisierten Alarm zu generieren, der die Analyse des Vorfalls enthält.
Das Active-Response-Skript
Den Kern der Automatisierung bildet ein Shell-Skript. Es ist dafür verantwortlich, die Daten für die KI aufzubereiten und die Analyse anzustoßen.
Speicherort: /var/ossec/active-response/bin/ai_summary.sh
#!/bin.bash
# by M. Meister
# Dieses Skript sammelt Daten zu einem Alarm und fragt eine KI um ihre Meinung.
# Wazuh übergibt den Pfad zur Alarm-Datei als ersten Parameter
ALERT_FILE="$1"
OLLAMA_HOST="http://ai:11434"
# Das Modell 'gemma3n:latest' ist ein guter Allrounder. Jedes andere passende Modell kann ebenfalls verwendet werden.
MODEL="gemma3n:latest"
OUTPUT_LOG="/var/log/wazuh-ai-alarms.log"
# Die Quell-IP ist der Schlüssel zu allem. Ohne sie tappen wir im Dunkeln.
SOURCE_IP=$(jq -r '.parameters.alert.data.srcip' "$ALERT_FILE")
if [ -z "$SOURCE_IP" ] || [ "$SOURCE_IP" == "null" ]; then
# Manchmal gibt es keine IP, dann können wir hier leider nicht weitermachen.
echo "Keine Quell-IP im Alarm gefunden. Skript wird beendet."
exit 0
fi
# Jetzt wird's spannend: Wir durchsuchen die Log-Archive nach der verdächtigen IP.
# Das kann einen Moment dauern, je nachdem, wie gesprächig die Systeme sind.
NOW=$(date +%s)
START_TIME=$((NOW - 600)) # Erstmal mit 600 Sekunden = 10 Minuten
EVENTS=$(jq -c --arg ip "$SOURCE_IP" \
--argjson start "$START_TIME" \
'select(.location != "wazuh-ai-alarms.log" and .data.srcip == $ip and (.timestamp | fromdateiso8601) >= $start)' \
/var/ossec/logs/archives/archives.json)
# Wenn keine weiteren Events gefunden wurden, macht eine Analyse wenig Sinn.
if [ -z "$EVENTS" ]; then
echo "Keine korrelierten Events für die IP $SOURCE_IP in den letzten 10 Minuten gefunden."
exit 0
fi
# Wir basteln einen schönen Prompt für unsere KI. Je besser die Frage, desto besser die Antwort.
PROMPT="Du bist ein erfahrener Cybersecurity-Analyst. Analysiere die folgenden JSON-Events, die von der IP-Adresse $SOURCE_IP stammen:
$EVENTS
Bitte fasse kurz und prägnant auf Deutsch zusammen, was passiert ist. Bewerte den Schweregrad und gib eine klare Handlungsempfehlung."
# Ab die Post! Wir schicken die Anfrage an Ollama.
# Dafür nutzen wir ein separates Python-Skript, weil das mit APIs einfach eleganter ist.
SUMMARY=$(python3 /var/ossec/active-response/bin/ai_summary_ollama_client.py "$OLLAMA_HOST" "$MODEL" "$PROMPT")
# Das Ergebnis der KI schreiben wir in unser eigenes Logbuch.
# Dieses Log wird dann von Wazuh wieder eingelesen. Ein schöner Kreislauf.
echo "{\"timestamp\": \"$(date --iso-8601=seconds)\", \"data\": {\"srcip\": \"$SOURCE_IP\"}, \"agent\": {\"name\": \"wazuh-ai-analyzer\"}, \"rule\": {\"description\": \"$SUMMARY\"}, \"alert_type\": \"ai_analysis\"}" >> "$OUTPUT_LOG"
Dieses Script soll später nicht nur die SourceIP sondern auch Userverhalten analysieren.
Anschließend muss das Skript ausführbar gemacht und die korrekten Berechtigungen gesetzt werden:
chmod 750 /var/ossec/active-response/bin/ai_summary.sh
chown root:wazuh /var/ossec/active-response/bin/ai_summary.sh
Der Ollama-Kommunikator in Python
Für die Kommunikation mit der Ollama REST-API wird ein kleines Python-Skript verwendet. Dies ist sauberer als die alleinige Verwendung von curl
, insbesondere bei der Verarbeitung der JSON-Antwort.
Speicherort: /var/ossec/active-response/bin/ai_summary_ollama_client.py
# M. Meister hat hier mitgewirkt.
# Dieses Skript ist der kleine Bote, der mit der Ollama-API spricht.
import sys
import requests
import json
if len(sys.argv) != 4:
print("Verwendung: python_script.py <ollama_host> <model> <prompt>")
sys.exit(1)
OLLAMA_HOST = sys.argv[1]
MODEL = sys.argv[2]
PROMPT = sys.argv[3]
# Die Daten für die API-Anfrage vorbereiten.
data = {
"model": MODEL,
"prompt": PROMPT,
"stream": False # Wir wollen die Antwort am Stück, nicht als Stream.
}
try:
# Die Anfrage an den Ollama-Server senden.
resp = requests.post(f"{OLLAMA_HOST}/api/generate", json=data, timeout=120) # 120 Sekunden Timeout
resp.raise_for_status()
# Die Antwort der KI extrahieren und für die JSON-Ausgabe im Shell-Skript bereinigen.
# Anführungszeichen und Zeilenumbrüche könnten unser schönes JSON-Format zerstören.
result = resp.json().get("response", "").replace('"', '\\"').replace('\n', ' ').strip()
print(result)
except requests.exceptions.RequestException as e:
# Wenn etwas schiefgeht, geben wir eine Fehlermeldung aus.
print(f"Fehler bei der Anfrage an Ollama: {e}")
sys.exit(1)
Dieses Skript benötigt das requests
-Paket, das mit pip
installiert werden kann:
pip3 install requests
Wazuh beibringen, das Skript auszuführen
Nun muss Wazuh konfiguriert werden, um das Skript bei einem relevanten Alarm auszuführen. Dies geschieht in der zentralen Konfigurationsdatei ossec.conf
.
Datei: /var/ossec/etc/ossec.conf
<ossec_config>
<command>
<name>ai_summary</name>
<executable>ai_summary.sh</executable>
<expect>srcip</expect>
<timeout_allowed>no</timeout_allowed>
</command>
<active-response>
<command>ai_summary</command>
<location>local</location>
<rules_id>5710,...,...</rules_id> <!-- Kommagetrente Alarmliste für KI Analyse -->
</active-response>
</ossec_config>
Diese Konfiguration weist Wazuh an, das ai_summary.sh
-Skript lokal auf dem Manager auszuführen, sobald ein Alarm mit der Regel-ID 5710
(SSH-Brute-Force-Versuche) oder andere aus der Liste ausgelöst werden.
Die KI-Erkenntnisse für Wazuh lesbar machen
Das Skript schreibt seine Ergebnisse in die Datei /var/log/wazuh-ai-alarms.log
. Damit Wazuh diese neuen Informationen verarbeiten kann, muss diese Datei als Log-Quelle hinzugefügt werden.
Datei: /var/ossec/etc/ossec.conf
<ossec_config>
<localfile>
<log_format>json</log_format>
<location>/var/log/wazuh-ai-alarms.log</location>
</localfile>
</ossec_config>
Wazuh liest nun jede neue Zeile aus dieser Datei und verarbeitet sie dank log_format:json
automatisch als JSON-Eintrag.
Die benutzerdefinierte Regel für den KI-Alarm
Der letzte Schritt ist die Erstellung einer benutzerdefinierten Regel. Diese Regel sorgt dafür, dass aus dem Log-Eintrag der KI ein hochpriorisierter Alarm im Wazuh-Dashboard wird.
Datei: /var/ossec/etc/rules/local_rules.xml
<group name="ai_analysis,">
<rule id="100100" level="15">
<field name="alert_type">^ai_analysis$</field>
<description>KI-Analyse: $(rule.description)</description>
<group>ai,</group>
</rule>
</group>
Diese Regel wird ausgelöst, wenn ein Log-Eintrag das Feld alert_type
mit dem Wert ai_analysis
enthält. Sie wird mit Level 15 eingestuft, was einer der höchsten Prioritäten entspricht und somit maximale Aufmerksamkeit sicherstellt. Besonders elegant: Der Inhalt des Feldes rule.description
aus unserem JSON-Log wird direkt als Beschreibung des Alarms übernommen.
Feinschliff und bewährte Praktiken
Während meiner Experimente ist mir einiges aufgefallen:
- Logrotation: Die Log-Datei
/var/log/wazuh-ai-alarms.log
wird möglicherweise recht groß. Eine Konfiguration mitlogrotate
ist unerlässlich, um den Speicherplatz unter Kontrolle zu halten. - Sicherheit: Der Zugriff auf die Ollama-API sollte auf den Wazuh-Server beschränkt werden. Zudem müssen die Berechtigungen für die Skripte und Log-Dateien restriktiv gesetzt sein.
- Ressourcen: Die Analyse von Log-Daten und die Ausführung von LLMs benötigen Rechenleistung. Die Auslastung des Systems sollte im Auge behalten werden. Mein KI-Server erreichte während der Tests Temperaturen über 80°C und erforderte eine stärkere Kühlung.
Fazit
Das Projekt ist zwar noch nicht abgeschlossen (wird es wohl auch nie sein 🫣), doch ist es bereits jetzt ein enormer Gewinn, wenn die KI im Description-Feld eine Einschätzung abgibt, wie groß der angerichtete Schaden ist und eine Handlungsempfehlung dabei unterstützt, die nächsten Schritte zu planen.