Wazuh zeigt Alerts in alerts.json, aber nicht im Dashboard: Filebeat-Indexing scheitert an Mapping-Konflikten durch JSON-Felder wie user und program


Einleitung (Einordnung, Relevanz für Security/SIEM/Wazuh)

Ein klassischer „SIEM-Albtraum“ im Wazuh-Betrieb: Ereignisse werden korrekt dekodiert, Regeln feuern, Alerts werden sauber nach alerts.json geschrieben – aber im Dashboard ist nichts zu sehen. In fast allen Fällen ist das kein UI-Problem, sondern ein Indexing-Problem: Filebeat versucht Alerts in den Wazuh Indexer zu schreiben, wird aber wegen Mapping-Konflikten (Field-Typen) mit HTTP 400 zurückgewiesen. Wazuh funktioniert dabei scheinbar „halb“, bis man die Filebeat-Logs prüft.

Dieser Beitrag zeigt, wie dieser Fehlerfall entsteht (typisch bei selbst gebautem JSON aus rsyslog), wie man ihn eindeutig diagnostiziert und wie man ihn stabil behebt – ohne die eigene Pipeline wegzuwerfen.


Ausgangslage / Problemstellung (Zusammenfassung, Symptome, Umgebung)

  • Logs werden per rsyslog gesammelt und in JSON transformiert, um sie leichter ingestierbar zu machen.
  • Wazuh dekodiert die Events mit dem JSON-Decoder; wazuh-logtest zeigt: Felder werden extrahiert, Regeln matchen, Alerts werden erzeugt.
  • Die Alerts erscheinen in /var/ossec/logs/alerts/alerts.json, aber nicht im Dashboard.
  • Zunächst wirken Indexer-Logs unauffällig; später zeigt sich: Filebeat kann Events nicht indexieren.

Im Beispiel enthielt das erzeugte JSON u. a. diese Felder:

  • user (Top-Level String, inkl. führendem Leerzeichen)
  • program (Top-Level String, z. B. mojo_server.pl)

Technische Analyse (Ursachen, betroffene Komponenten, Architekturbezug, Stolpersteine)

1) Datenfluss: alerts.json ≠ „im Index“

Wazuh Manager schreibt Alerts lokal nach alerts.json. Für die Sichtbarkeit im Dashboard müssen sie danach von Filebeat an den Wazuh Indexer weitergeleitet und dort erfolgreich indexiert werden. Wenn das Indexing fehlschlägt, bleibt alerts.json korrekt gefüllt – das Dashboard bleibt leer.

2) Der harte Beweis steht in Filebeat: mapper_parsing_exception

Im Thread wurde der entscheidende Hinweis erst gefunden, nachdem gezielt in Filebeat nach Warnungen gesucht wurde. Der Fehler sah sinngemäß so aus:

status=400 ... mapper_parsing_exception ... object mapping for [data.program] tried to parse field [program] as object, but found a concrete value

Das bedeutet: In deinem Index existiert bereits ein Mapping, in dem data.program als Object definiert/“gelernt“ wurde (z. B. data.program.name, data.program.version). Jetzt kommt ein Event, in dem data.program ein String ist ("mojo_server.pl"). Elasticsearch/OpenSearch kann einen Feldpfad nicht gleichzeitig als Object und String führen – der Event wird abgelehnt.

3) Warum JSON-Keys wie user und program besonders gefährlich sind

Zwei typische Konfliktquellen:

  • user: In vielen Schemas (u. a. ECS) ist user ein Objekt, das Unterfelder trägt (user.name, user.id, …). Ein Top-Level user: "internaladmin" kann daher mit bestehenden Mappings kollidieren.
  • program: Je nach vorhandenen Templates/Events kann program bzw. data.program bereits als Objekt oder anders typisiert sein. Sobald du einmal einen „anderen“ Typ schickst, schlägt das Indexing fehl.

Wichtig: Im Wazuh Alert-Dokument landen dekodierte Felder oft in einer strukturierten Sektion (z. B. data.*). Wenn du per JSON-Decoder beliebige Keys extrahierst, können sie genau dort landen – und damit in Konflikt mit bereits etablierten Mappings geraten.

4) Nebenkriegsschauplatz: „No data in current window…“

Die Indexer-Meldungen „No data in current window…“ sind meist Task/Job-Logs (z. B. Detector/Monitoring) und nicht zwingend der Kernfehler. Entscheidend ist: 400er in Filebeat sind ein K.O.-Kriterium für die Sichtbarkeit im Dashboard.


Lösung / Best Practices (konkrete Schritte, Konfigurationen, Reihenfolge, Side-Effects)

Schritt 1: Fehler eindeutig nachweisen

Auf dem Wazuh-Server (bzw. Filebeat-Node):

grep -Ei "warn|error|Cannot index event|mapper_parsing_exception" /var/log/filebeat/filebeat*

Wenn du dort mapper_parsing_exception + status=400 siehst, ist die Ursache praktisch bewiesen: Indexing wird abgelehnt.

Schritt 2: Problemfelder „entschärfen“ durch Umbenennung

Im Thread war die wirksame Korrektur:

  • programprogram_name
  • user → z. B. fmc_user oder src_user (oder sauber in ein Objekt user.name, falls du wirklich ECS-konform sein willst)

Warum das hilft: Du vermeidest Kollisionen mit bereits typisierten Feldern (Object vs. String) und mit verbreiteten Schema-Objekten wie user.

Beispiel: Statt

{"program":"mojo_server.pl","user":"internaladmin", ...}

besser:

{"program_name":"mojo_server.pl","fmc_user":"internaladmin", ...}

Zusätzlich empfehlenswert:

  • Führende Leerzeichen aus Werten entfernen (" internaladmin""internaladmin"), damit Regeln/Visualisierungen konsistent sind.

Schritt 3: Konsistente Typen erzwingen (auch in Nested Feldern)

Achte darauf, dass Felder wie changes nicht einmal null und später "" (String) sind. Solche Typwechsel sind ebenfalls klassische Mapping-Killer. Wenn du „kein Wert“ meinst, bleib konsequent (z. B. immer null oder immer String). Das gilt besonders für Felder, die du aus rsyslog erzeugst.

Schritt 4: Nach Fix: neue Indizes oder Reindex einplanen

Wenn ein Index bereits ein „falsches“ Mapping hat, wird er nicht „automatisch“ korrigiert. In der Praxis hast du zwei Optionen:

  • Abwarten bis der nächste Tagesindex entsteht (typisch bei wazuh-alerts-4.x-YYYY.MM.DD) und dann prüfen, ob neue Events sauber reingehen.
  • Oder: Reindex/Neuanlage, wenn du historische Daten retten willst (in vielen Umgebungen ist das optional, aber bei Audit-Quellen oft relevant).

Schritt 5: Alternativstrategie: Wazuh-nativ dekodieren statt externes JSON „erzwingen“

Der JSON-Decoder ist mächtig und eliminiert die Notwendigkeit, für jedes Feld XML-Decoders zu schreiben – aber er bringt dir auch das Risiko, beliebige Keys direkt in den Index zu drücken. Wazuh dokumentiert beide Wege: JSON-Decoder sowie klassische Custom-Decoders.

Pragmatische Empfehlung:

  • Wenn du bei rsyslog bleiben willst: Schema definieren (Whitelisted Keys, konsistente Typen, sichere Feldnamen).
  • Wenn du langfristig weniger Mapping-Risiko willst: Log möglichst roh liefern und in Wazuh über Decoder/Rules strukturieren.

Lessons Learned / Best Practices (präventive Maßnahmen, Betrieb, Skalierung)

  • Immer zuerst Filebeat prüfen, wenn alerts.json gefüllt ist, aber das Dashboard leer bleibt. Der Manager-Write ist nicht der Index-Beweis.
  • Vermeide Top-Level-Felder, die in gängigen Schemas objektartig belegt sind (z. B. user). Nutze lieber explizite Namen (fmc_user, src_user, username) oder nutze Unterfelder (user.name).
  • Halte Feldtypen stabil: Ein Feld darf nicht mal Object und mal String sein; auch null vs. "" kann problematisch werden.
  • Baue dir ein „Schema-Contract“ für externe JSON-Generatoren (rsyslog): erlaubte Keys, Typen, Defaults.
  • Wenn du neue Felder einführst: zuerst in einer Testumgebung prüfen, ob Indexing sauber bleibt (Filebeat-Logs sind dabei die schnellste Wahrheit).

Fazit (knappe Zusammenfassung mit Mehrwert)

Wenn Wazuh Alerts erzeugt und in alerts.json schreibt, aber im Dashboard nichts auftaucht, ist die Ursache sehr häufig ein stilles Scheitern beim Indexing. Der Thread zeigt das Muster deutlich: Der JSON-Decoder funktioniert, Regeln feuern – aber Filebeat wird vom Indexer wegen Mapping-Konflikten abgewiesen (mapper_parsing_exception). Mit einem konsequenten Field-Naming (z. B. program_name statt program, fmc_user statt user) und stabilen Datentypen lässt sich das zuverlässig beheben. Entscheidend ist, den Datenpfad als Ganzes zu betrachten: erst wenn Filebeat ohne 400er schreibt, ist der Alert „im SIEM“ angekommen.


Mehr zu Wazuh …
https://wazuh.com/?utm_source=ambassadors&utm_medium=referral&utm_campaign=ambassadors+program

Mehr zum Wazuh Ambassador Program …
https://wazuh.com/ambassadors-program/?utm_source=ambassadors&utm_medium=referral&utm_campaign=ambassadors+program

https://wazuh.slack.com/archives/C0A933R8E/p1769016114491779