Add Arkime OT protocol field normalizations for Dashboards cross-filtering - #993
sercanokur wants to merge 2 commits into
Conversation
|
I think the Modbus normalization has a type mismatch that may only show up after the updated component template is applied to a fresh index. This change merges The mutate Could this map from an actual numeric Modbus function-code field instead, if one is available, or otherwise keep the symbolic Zeek value in a keyword-compatible field rather than |
|
Thanks @sylvesterkaczmarek, this is a solid catch. You're right that zeek.modbus.func is a symbolic value (function name), not numeric, while modbus.funccode is declared long to mirror Arkime's integer function-code field — and since mutate { merge => } boxes a scalar into an array when the destination field doesn't already exist, that mismatch would only surface once a fresh index is built from the updated component template. My testing ran against an already-existing arkime_sessions3-* index, so the old mapping was still in effect and masked exactly the failure mode you describe. I'll test this against a freshly created index (rollover/reindex from the updated template) to confirm the mapping/parsing failure, and look into whether there's an actual numeric Modbus function-code field available from Zeek to map instead — otherwise I'll move the symbolic value into a keyword-compatible field rather than modbus.funccode. Will report back here once I've dug into it. |
Mirror Arkime sessions3Update OT field mappings into Malcolm's composable template, Zeek Logstash mutations, and OT dashboards so Dashboards and Arkime share bacnet, c1222, dnp3, enip, modbus, opcua, s7comm, and synchrophasor field names for pivoting between views. Use distinct mutate filter IDs for DNP3 Arkime merges to avoid colliding with existing IDs in 1300_zeek_normalize.conf.
ffa9f04 to
1718b1d
Compare
|
Fixed in 1718b1d — you were right about the type mismatch. The original merge would have produced string/array values under a long mapping once the updated component template is applied to a fresh index. To resolve this:
Also rebased onto current upstream/main to resolve the dashboard export conflicts. Original zeek.modbus.* fields and the existing event.action/event.result normalization are unchanged. |
69c0fa8 to
a534849
Compare
Translate Zeek symbolic Modbus function and exception names to numeric Arkime funccode/exccode values, coerce transaction/unit IDs to integers, and centralize the mapping in 1300_zeek_normalize.conf. Add regression checks for the lookup tables and template contract.
a534849 to
627cbf6
Compare
|
I really do plan on getting to this for the september release. my tasking has been crazy the last few months, but I'm hoping to carve out time to review and merge this. thanks for your patience. |
sylvesterkaczmarek
left a comment
There was a problem hiding this comment.
Normalization converts Zeek Modbus function names into integer modbus.funccode values, but the updated dashboard still applies string wildcards such as *WRITE*/*EXCEPTION* and Vega indexof(..., "REG") checks to that field. Those expressions worked on zeek.modbus.func but cannot classify the numeric field, so the Modbus panels will filter or label traffic incorrectly. Retain/use a normalized function-name field (or map codes to labels in the dashboard) and add a dashboard regression.
Summary Feature Issue: normalize fields for OT protocols supported by Arkime #986
Malcolm Dashboards and Arkime use different field names for the same Zeek OT protocol attributes. Zeek logs are indexed under nested
zeek.*fields, while Arkime sessions use top-level protocol fields defined indb.pl(sessions3Update). This mismatch prevents reliable pivoting and cross-filtering between Dashboards visualizations and Arkime session views.This PR aligns Malcolm with Arkime's OT field naming for eight protocols: BACnet, C12.22, DNP3, EtherNet/IP (ENIP/CIP), Modbus, OPC UA, S7comm, and Synchrophasor. Changes are additive only: original
zeek.*fields are preserved; new top-level Arkime-style fields are merged alongside them.Motivation
Operators often start an investigation in Malcolm Dashboards (Zeek-indexed data) and pivot into Arkime for PCAP/session context, or vice versa. Without shared field names, filters and drill-downs do not carry across tools. Arkime already documents these mappings in
sessions3Update; this PR brings Malcolm's ingest template, Logstash pipeline, and OT dashboards in line with that reference.Changes
1. OpenSearch composable template (
dashboards/templates/composable/component/arkime.json)Added index mappings for OT protocol blocks mirroring Arkime
db.plsessions3Updatedefinitions, including:bacnet.*(function, apduType, service, objectName, …)c1222.*(calledAp*, callingAp*, securityMode, responseControl, …)dnp3.funcNameenip.*/cip.*(command, service, class, deviceType, product, status, vendor, …)modbus.*(funccode, exccode, transactionid, unitid)opcua.*(endpointUrl, securityPolicyUri)s7comm.*(errorClass, errorCode, func, funcName, opcode, pduref, rosctr)synchrophasor.*(cmd, dataRate, frameType, idcode, numPMU, station)2. Zeek Logstash pipeline (
logstash/pipelines/zeek/1200_zeek_mutate.conf)Within each protocol's existing
log_sourcebranch, addedmutatemerge filters that copy Zeek nested fields to Arkime top-level names, for example:zeek.bacnet.bvlc_functionbacnet.functionzeek.bacnet.pdu_typebacnet.apduTypezeek.bacnet.pdu_servicebacnet.servicezeek.c1222.mechanism_namec1222.securityModezeek.dnp3.fc_request/fc_replydnp3.funcNamezeek.enip.enip_commandenip.commandzeek.modbus.funcmodbus.funccodezeek.opcua_binary.endpoint_urlopcua.endpointUrlzeek.s7comm.funcs7comm.funczeek.synchrophasor.frame_typesynchrophasor.frameTypeDNP3 mutate ID fix: Arkime merge filters use IDs suffixed with
_arkime(mutate_merge_zeek_dnp3_fc_request_arkime,mutate_merge_zeek_dnp3_fc_reply_arkime) to avoid colliding with existing mutate IDs in1300_zeek_normalize.conf. Without distinct IDs, themalcolm-zeekpipeline fails to start (duplicate filter ID), blocking all Zeek ingest.No regressions to existing normalize logic:
1300_zeek_normalize.confis unchanged. DNP3 documents still receiveevent.result/event.actionfrom the existing normalize path while also gainingdnp3.funcNamefor Arkime alignment.3. OT dashboard JSON (7 dashboards)
Updated field references from
zeek.*to Arkime field names in Discover/visualization configs:2bec1490-eb94-11e9-a384-0fcf32210194.jsondb51fc00-673b-11f0-8230-37b935257dd0.json870a5862-6c26-4a08-99fd-0c06cda85ba3.json29a1b290-eb98-11e9-a384-0fcf32210194.json152f29dc-51a2-4f53-93e9-6e92765567b8.jsondd87edd0-796a-11ec-9ce6-b395c1ff58f4.jsone76d05c0-eb9f-11e9-a384-0fcf32210194.json2cc56240-e460-11ed-a9d5-9f591c284cb4.jsonNon-OT dashboards and other Logstash pipelines (Suricata, beats, filescan, enrichment, etc.) are not modified.
Testing performed
Local Malcolm stack (Docker Compose) with
docker-compose-dev.ymlto bind-mount the updated Logstash pipeline.Pipeline health
malcolm-zeekhealthy).1200_zeek_mutate.confand1300_zeek_normalize.conf.ERROR/ duplicate-ID failures after the DNP3_arkimesuffix fix.Ingest verification (OpenSearch
arkime_sessions3-*)Representative OT PCAPs processed via Zeek offline (
zeek-offline -r … local) and uploaded to/zeek/upload/:bacnet_example.pcapbacnet.service,bacnet.apduType,bacnet.function,bacnet.objectNamednp3_example.pcapdnp3.funcName(+ existingevent.result,zeek.dnp3.*)enip_cip_example.pcapenip.command,cip.service,cip.class, identity fieldsmodbus_example.pcapmodbus.funccode,modbus.unitid, …open62541_client-server_mainloop.pcapopcua.endpointUrl,opcua.securityPolicyUrisnap7.pcap,s7comm_plus.pcaps7comm.func,s7comm.funcName,s7comm.rosctr, …c1222.calledAp*,c1222.callingAp*,c1222.responseControlC37.118_1PMU_TCP.pcapsynchrophasor.cmd,frameType,idcode,numPMU,dataRate28 of 31 expected normalized fields populated across protocols.
Regression checks
event.dataset:alertdocuments unchanged.event.dataset:conndocuments with standardsource/destination/networkfields.zeek.modbus.funcandmodbus.funccode.dnp3.funcName,zeek.dnp3.fc_*, andevent.result/event.actionpresent on the same documents.Fields not observed (PCAP limitation, not pipeline failure)
These Arkime fields depend on Zeek log columns absent in our test captures:
c1222.securityMode(requiresmechanism_namein Zeek log)c1222.calledApInvocationIdsynchrophasor.station(may requireZEEK_SYNCHROPHASOR_DETAILED=true)Test plan for reviewers
malcolm-zeekpipeline starts with no duplicate mutate ID errors.zeek.*fields remain.Deployment notes
Out of scope
arkime/wise/source.zeeklogs.jsupdates (Wise field mapping) — can be a follow-up if desired.