Große JSON-Scanergebnisse in Wazuh ingestieren: Warum NDJSON besser ist als ein verschachteltes Gesamtobjekt

Einleitung

Scan-Tools erzeugen häufig umfangreiche JSON-Dateien mit Metadaten, Assets, Findings, DNS-Daten, HTTP-Ergebnissen oder Geolocation-Informationen. Für Wazuh ist dabei nicht nur entscheidend, ob die Daten syntaktisch korrektes JSON sind, sondern auch, wie sie strukturiert sind. Ein einzelnes großes JSON-Objekt mit verschachtelten Arrays ist für die Logverarbeitung deutlich schlechter geeignet als einzelne, zeilenbasierte Events.

Ausgangslage / Problemstellung

Ein Scan erzeugt eine große JSON-Datei mit mehreren tausend Zeilen. Darin befinden sich Scan-Metadaten und viele Assets beziehungsweise Findings in verschachtelten Arrays. Die zentrale Frage lautet: Soll dieses große JSON-Objekt direkt an Wazuh übergeben werden, oder sollte es vorab in einzelne Events aufgeteilt werden?

Die empfohlene Antwort ist eindeutig: Die Daten sollten vor dem Wazuh-Ingest in einzelne JSON-Events umgewandelt werden, idealerweise im NDJSON-Format.

NDJSON bedeutet: eine vollständige JSON-Struktur pro Zeile, ohne äußeres Array und ohne Kommas zwischen den Objekten. Dieses Format ist für Log-Streaming und Event-basierte Verarbeitung ausgelegt.

Technische Analyse

Wazuh Logcollector verarbeitet bei log_format json jede Zeile als eigenes Event. Ein mehrzeiliges JSON-Objekt wird daher nicht als ein zusammenhängender JSON-Datensatz behandelt, sondern zeilenweise gelesen. Das führt bei großen, formatierten JSON-Dateien zu unvollständigen oder nicht parsebaren Fragmenten. Die localfile-Konfiguration ist der richtige Mechanismus zur Dateiüberwachung, erwartet aber ein geeignetes Logformat pro Event.

Zusätzlich gibt es technische Grenzen bei der Eventgröße. Sehr große Einzelereignisse sind für Wazuh riskant, weil sie interne Größenlimits erreichen können. In der Praxis sollte ein Scanergebnis deshalb nicht als ein einziges Event behandelt werden, sondern in logisch kleine, eigenständige Events zerlegt werden.

Ein weiteres wichtiges Limit betrifft den dynamischen JSON-Decoder. Wazuh kann verschachtelte Objekte und Arrays einfacher Werte verarbeiten, unterstützt aber keine Arrays von Objekten als sauber aufgelöste dynamische Felder. Die Wazuh-Dokumentation nennt ausdrücklich, dass ein Array von Objekten nicht unterstützt wird.

Problematisch ist also insbesondere dieses Muster:

{
"scan_id": "scan_alpha",
"assets": [
{
"host": "example.org",
"ip": "1.1.1.1"
},
{
"host": "example.net",
"ip": "2.2.2.2"
}
]
}

Für Wazuh ist besser:

{"scan_id":"scan_alpha","host":"example.org","ip":"1.1.1.1"}
{"scan_id":"scan_alpha","host":"example.net","ip":"2.2.2.2"}

Lösung / Best Practices

Die robuste Architektur besteht aus einem Preprocessing-Schritt vor dem Wazuh Agent. Das Scanergebnis wird dabei in NDJSON umgewandelt: ein Asset, ein Finding oder ein technischer Befund pro Zeile.

Beispiel:

{"scan_id":"abc123","timestamp":"2026-03-04T10:00:00Z","scan_type":"http","asset":{"host":"10.0.0.1","port":80,"status":"open"}}
{"scan_id":"abc123","timestamp":"2026-03-04T10:00:00Z","scan_type":"http","asset":{"host":"10.0.0.2","port":443,"status":"open"}}

Die Wazuh-Agent-Konfiguration sieht dann schlicht aus:

<localfile>
<log_format>json</log_format>
<location>/var/log/scans/scan-output.ndjson</location>
</localfile>

Wichtig: Zwischen den JSON-Objekten stehen keine Kommas. Es gibt auch kein äußeres Array.

Richtig:

{"some":"thing"}
{"foo":17,"bar":false}
{"may":{"include":"nested","objects":["and","arrays"]}}

Falsch:

[
{"some":"thing"},
{"foo":17}
]

Arrays mit einfachen Werten sind unkritischer:

{
"host": "example.org",
"tags": ["external", "http", "production"]
}

Arrays von Objekten sollten dagegen vermieden oder umgewandelt werden:

{
"records": [
{"type":"a","value":"1.1.1.1"},
{"type":"mx","value":"mail.example.org"}
]
}

Besser als nummerierte Objekte:

{
"records": {
"001": {"type":"a","value":"1.1.1.1"},
"002": {"type":"mx","value":"mail.example.org"}
}
}

Damit entstehen sauber adressierbare Felder wie:

records.001.type
records.001.value
records.002.type
records.002.value

Für die Suche im Wazuh Dashboard beziehungsweise per DQL kann bei nummerierten Objekten mit Wildcards gearbeitet werden:

data.asset.geolocations.*.country:DE

Für die Umwandlung eignet sich jq. Ein typischer Preprocessing-Ansatz ist:

jq -c '.assets[] as $asset | {
scan_id: .scan_id,
timestamp: .timestamp,
scan_type: .scan_type,
asset: $asset
}' scan-output.json > scan-output.ndjson

Wenn Arrays von Objekten an beliebigen Stellen rekursiv in nummerierte Objekte umgewandelt werden sollen, kann ein spezieller jq-Filter genutzt werden. Ein entsprechender Ansatz wurde im Thread über einen veröffentlichten Filter referenziert.

Lessons Learned / Best Practices

Große JSON-Dateien sollten nicht direkt an Wazuh übergeben werden, wenn sie aus einem großen Root-Objekt mit tief verschachtelten Arrays bestehen. Wazuh arbeitet eventbasiert; deshalb sollte auch das Inputformat eventbasiert sein.

Die wichtigsten Betriebsregeln:

  • ein JSON-Objekt pro Zeile
  • keine mehrzeiligen JSON-Events
  • keine äußeren Arrays
  • keine Kommas zwischen Events
  • Scan-Metadaten in jedes Event kopieren
  • Arrays von Objekten vermeiden
  • Assets und Findings möglichst vor dem Agent splitten
  • jq oder ein eigenes Preprocessing-Skript vor Wazuh einsetzen
  • Eventgröße klein und vorhersehbar halten

Besonders wichtig ist die Modellierungsentscheidung: Ein Asset, ein Finding oder ein DNS-Record sollte ein eigenes SIEM-Event sein. Dadurch lassen sich Regeln, Korrelationen, Dashboards und Suchen deutlich einfacher bauen.

Fazit

Für Scanergebnisse ist NDJSON das passende Format für Wazuh. Ein großes, verschachteltes JSON-Objekt führt zu Parsing-Problemen, Eventgrößenrisiken und Einschränkungen durch den dynamischen JSON-Decoder. Die beste Lösung ist ein Preprocessing vor dem Wazuh Agent: große Scanoutputs werden in einzelne, vollständige JSON-Zeilen transformiert, Metadaten werden pro Event ergänzt und Arrays von Objekten werden entweder aufgelöst oder in nummerierte Objekte umgewandelt. So entsteht ein stabiler, suchbarer und regelbarer Datenstrom für Wazuh.

Quellen

https://documentation.wazuh.com/current/user-manual/reference/ossec-conf/localfile.html
https://documentation.wazuh.com/current/user-manual/ruleset/decoders/json-decoder.html
https://github.com/ndjson/ndjson-spec
https://github.com/BlueWolfNinja/wazuh-resources/blob/main/jq-filters/transform-arrays-of-objects-to-numbered-objects.jq

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/p1772622213057589