Skip to content

Commit 7ca5c94

Browse files
committed
fix(meraki): parse native events and scope security alerts
1 parent db4ae93 commit 7ca5c94

14 files changed

Lines changed: 3621 additions & 335 deletions

‎filters/audits/cisco-meraki.md‎

Lines changed: 138 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,151 @@
1-
# Cisco Meraki normalization and rule review
1+
# Cisco Meraki parsing and rule contracts
22

3-
Avoid fabricated success for observations/pending VPN; preserve rule input fields and handle retrospective AMP events without invented source IP.
3+
This source draft targets UTMStack v11 and revises one filter and its seven rules.
4+
The meeting follow-up is based on SDK v1.1.31, pinned by `plugins/alerts/go.mod`,
5+
and the official SDK field and filter/rule documentation. It preserves ingress
6+
`dataSource` and the physical source/destination roles in network events. It does
7+
not deploy configuration, generate customer telemetry or claim that an alert fired.
48

5-
This draft targets UTMStack `v11`. It contains 1 filter changes
6-
and 1 rule changes for this technology only. Review covered
7-
1 filter configurations and 7 matching shipped rule files.
8-
Unchanged rules are listed in the regression manifest; they are not duplicated in the diff.
9+
## Evidence and its limits
910

10-
## Contract and validation
11+
The current carrier investigation found nine distinct records without recognizable
12+
Meraki envelopes under `firewall-meraki`: five ISO syslog records from unrelated
13+
programs and four other unrecognized network/syslog records. They lack normalized Meraki fields. The deployed
14+
filter SHA-256 is
15+
`b39216313c9e141d7bb9aef93aafc97f044e482ea7a013bc62ea4bb4ecf64e18`.
16+
Bounded searches over the retained 30-day window found no strong documented
17+
Meraki class signatures. That search is not an exhaustive proof that Meraki
18+
telemetry never arrived. The routing mismatch is a separate ingress-classification issue with its upstream
19+
producer unresolved;
20+
this patch does not reinterpret unrelated syslog as Meraki data.
1121

12-
- Compared exact standard names/types with go-sdk v1.1.31 and the supplied UTMStack dictionaries.
13-
- Checked documented pipeline ordering, rename/move behavior, open vendor log fields,
14-
event-side versus alert-side fields, and surviving fields used by affected rule predicates/history/grouping.
15-
- Strict SDK configuration decoding and actual CEL compilation pass for this scope.
16-
- 6 synthetic normalization cases pass, including SDK Event conversion and any
17-
trigger predicate assertions recorded in the manifest.
18-
- The scoped alerts module tests and `git diff --check` pass with the shared contract runner applied.
22+
Private raw records, document IDs and instance provenance remain outside the
23+
repository. All public positive fixtures are fabricated from official Cisco
24+
examples, not customer records. Positive parsing and detection results below are
25+
therefore documented-format compatibility checks, not measured recovery of
26+
customer Meraki events. The reviewed prior source draft is
27+
`db4ae93a194009ca05631245a6316b6c87134f2c`.
1928

20-
The shared alert-contract PR supplies the reusable Go runner for the manifest in
21-
`plugins/alerts/testdata/filter-contracts/cisco-meraki.json`. Apply that support before running `go test ./...` in `plugins/alerts`.
29+
## Producer corrections
2230

23-
The changed rules also require the shared alert-grouping fix to resolve `lastEvent.*` values correctly at runtime.
31+
The old raw header paths require a Cisco calendar-time wrapper. The documented
32+
Meraki native envelope instead starts with fractional epoch, device name and
33+
an event group. The new anchored paths accept that envelope, a bounded RFC3164
34+
wrapper, and the documented standalone Air Marshal form. Group boundaries are
35+
explicit: device or message text cannot become part of a native event category.
36+
The old greedy group copy was not overwriting an existing subtype; it was the
37+
sole producer of `log.eventType`.
2438

25-
The model starts from synthetic extraction results. It does not run complex grok,
26-
JSON/KV/XML/CSV extraction, time conversion, dynamic plugins, historical OpenSearch
27-
queries, or the closed EventProcessor. Raw vendor logs and resulting alerts must
28-
still be checked in staging before rollout. No customer false-positive reduction
29-
has been measured and no production rollout is included.
39+
`log.merakiGroup` retains the outer event group and `log.merakiType` retains the
40+
header device name. `log.eventType` exposes the canonical category; nested Air
41+
Marshal messages use `airmarshal_events`. `log.type` holds the events/Air Marshal
42+
classification, while `log.alertType` holds the security-event class. These fields
43+
now match the rule consumers. Class-prefix recognizers are anchored, and quoted
44+
field recovery cannot treat message text as an independent identity or decision.
45+
The full body remains available as `log.message`.
3046

31-
Current Meraki security events retain their group/message for the AMP consumer. Retrospective malicious dispositions do not report a source IP, so the rule does not invent or require one; grouping includes dataSource. Source: https://documentation.meraki.com/General_Administration/Monitoring_and_Reporting/Syslog_Event_Types_and_Log_Samples
47+
Legacy body handlers remain for event families outside the bounded new handlers;
48+
legacy header/control-field rewrites cannot overwrite a recognized native header.
49+
Representative DHCP, VPN connectivity, cellular status, STP, disassociation and
50+
URL formats have regression fixtures. Not every historical vendor variant has
51+
been exercised, and the model's built-in legacy regex aliases are approximations
52+
of the closed executor's patterns. New native patterns are explicit in YAML.
53+
54+
Three review controls reproduced false fields before correction: a quoted VPN
55+
fragment produced a peer IP and success, quoted disassociation field names
56+
produced success, and an embedded legacy date header reclassified application
57+
text as a flow. Native VPN/disassociation now consume only their top-level
58+
tokens, and both legacy header patterns require the start of the raw record.
59+
Genuine VPN connectivity fields, full disassociation metadata and both leading
60+
legacy header forms have positive controls. Disassociation timing/radio fields
61+
remain metadata; their presence alone does not establish authentication success.
62+
63+
| Vendor information | Result |
64+
|---|---|
65+
| Source/destination addresses | Captured and cleaned under vendor fields, validated at promotion, then written to `origin.ip`/`target.ip`. Invalid/unspecified values stay under `log.sourceIp`/`log.destinationIp`; original native `log.src`/`log.dst` also remain. |
66+
| IPv6 and endpoint ports | Valid IPv6 ending in `::` is not truncated by colon cleanup. Semantic zero CIDRs cover alternate and IPv4-mapped unspecified forms. Ports retain numeric bounds before SDK conversion. |
67+
| Flow/firewall decision | Documented `flows`, `firewall`, `cellular_firewall`, `vpn_firewall` and `l7_firewall` groups are recognized. Explicit allow/deny/block becomes success/denied as a policy outcome, not proof a connection completed. |
68+
| IDS / AMP enforcement | IDS `decision=blocked` and AMP scan `action=block` produce denied. Mere IDS observation and retrospective AMP `action=allow` do not manufacture execution success. |
69+
| AnyConnect authentication | Only the documented auth-success/failure classes extract `Peer IP` from their structured message. Generic VPN negotiation or text mentioning failure does not become authentication evidence. |
70+
| AMP hash and URL | Valid 64-hex `log.sha256` is copied to `target.sha256`, describing the file offered by the remote download endpoint; vendor hash is retained. A full URL maps to `target.url`. Threat names such as EICAR classifications are not filenames. |
71+
| 802.1X identity | Documented identity maps to `origin.user`; physical switch interface numbers stay in `log.switchPort`, not transport `origin.port`. |
72+
| Wireless device | Packet-flood device and Air Marshal source/destination MACs retain their documented roles. The observing appliance name is not an attacker hostname. |
73+
| IDS `dhost` | Retained as `log.dhost`; it is no longer unconditionally assigned to the source MAC. Its all-direction endpoint semantics are not established by the available examples. |
74+
| Auxiliary geolocation | Hostnames and zero addresses never enter geolocation. Results use distinct `log.serverGeolocation` / `log.localGeolocation` fields rather than children of scalar address fields. `ip_resp` is response timing and is not geolocated. |
75+
76+
The SDK uses string fields for outcomes and protocol. This change preserves the
77+
existing protocol conversion policy and uses explicit outcome evidence. Fractional
78+
epoch values remain vendor time metadata; a verified conversion into `deviceTime`
79+
was not established here. Auxiliary geolocation field names and new consumer
80+
aliases require review of saved queries during staging; private dashboards were
81+
not enumerated.
82+
83+
## Consumers and identities
84+
85+
- AMP consumes exact documented scan/disposition-change classes and malicious
86+
disposition. Network source remains the downloading client; the rule's
87+
adversary side is the remote target serving the file. This is not proof that
88+
the client executed malware. Retrospective events remain eligible without IPs.
89+
- AMP groups valid hashes using a `hash` namespace. Missing or malformed hashes
90+
retain the vendor value and use the actual ingress `Event.id` in an `event`
91+
namespace, keeping distinct records separate. The filter does not create an
92+
event ID; the input producer supplies it. Neither a usable hash nor an ingress
93+
ID is an explicit completeness negative, not a fabricated file identity.
94+
- IDS accepts high/medium priorities 1 and 2, including documented legacy
95+
`ids-alerts` records containing only a source endpoint. A target IP is not
96+
invented to satisfy a rule.
97+
- Rogue SSID and Air Marshal rules consume the actual Air Marshal class. The
98+
Evil Twin rule requires `ssid_spoofing_detected`, not a generic rogue SSID.
99+
The two rogue rules retain overlapping coverage and the existing RSSI threshold
100+
for team review; primary syslog RSSI units were not established. Cisco documents
101+
removal of these legacy rogue/spoofing messages in MR29 and later.
102+
- Wireless intrusion consumes `device_packet_flood` with `state=start`; an end
103+
event or ordinary message containing attack words is not a new attack trigger.
104+
- VPN uses exact AnyConnect auth failure, valid produced origin IP, and meaningful
105+
ingress/device identities. Its 10-in-15-minute history counts only the filter's
106+
matching failure marker for that source, collector and device. Generic traffic
107+
from the same IP no longer satisfies the history. Input markers are cleared.
108+
109+
History windows use the SDK's processing-time lower bound on `@timestamp`, not
110+
strict event-time sequencing. Older indexed records have no new candidate marker;
111+
allow the 15-minute history window to warm up when staging the filter and rules
112+
together. Indexed `lastEvent.*` grouping requires the separate alert-foundation
113+
fix; this source draft does not duplicate it.
114+
115+
## Verification
116+
117+
`go test ./... -count=1 -v` passes in `plugins/alerts` with the optional private
118+
routing evidence enabled. `git diff --check` also passes.
119+
120+
- 85 fabricated raw cases exercise all seven rule predicates, native envelopes,
121+
quoted field/class injection, valid and unspecified addresses, documented
122+
legacy event families, decision semantics, hash/ID fallback and new mappings.
123+
- Fourteen isolated auxiliary-geolocation controls test both address fields with
124+
valid IPs, hostnames and alternate unspecified representations. These are
125+
source-step controls, not legacy-envelope parsing proofs.
126+
- Actual SDK CEL and Event/Alert serialization validate consumer identities,
127+
physical endpoint preservation, AMP actor direction and grouping separation.
128+
- Actual SDK history executes against a loopback HTTP mock for the VPN threshold,
129+
count-minus-one/count, inside/expired windows, source/device/collector isolation,
130+
benign raw classes and missing placeholders. It does not query a customer.
131+
- All nine private unrelated/unrecognized records pass as negative routing controls without
132+
invented Meraki identities, outcomes or candidates.
133+
- The shared manifest contains three explicitly isolated normalization/empty
134+
identity controls. It does not prove raw parsing; the standalone raw suite does
135+
that within its stated model boundary.
136+
- The final shared-runner overlay passes 121 test/subtest records, with the
137+
optional private replay skipped there and run separately with its evidence.
138+
139+
The closed EventProcessor, live OpenSearch, dynamic geolocation lookup and alert
140+
publication are not run by this harness. No production false-positive reduction
141+
has been measured. Before production approval, stage actual native Meraki payloads
142+
through the collector/engine, inspect produced alerts and grouping, check parsing
143+
cost at realistic event rates, and investigate the separate carrier-routing issue.
32144

33145
## References
34146

35-
- [SDK schema](https://github.com/threatwinds/go-sdk/blob/v1.1.31/plugins/plugins.proto)
147+
- [Official Meraki syslog formats and examples](https://documentation.meraki.com/Platform_Management/Dashboard_Administration/Operate_and_Maintain/Monitoring_and_Reporting/Syslog_Event_Types_and_Log_Samples)
148+
- [SDK v1.1.31 schema](https://github.com/threatwinds/go-sdk/blob/v1.1.31/plugins/plugins.proto)
149+
- [Standard event semantics](https://github.com/threatwinds/go-sdk/wiki/Standard-Event-Schema)
36150
- [Filter steps](https://github.com/threatwinds/go-sdk/wiki/Filter-Steps-Reference)
37-
- [Standard event schema](https://github.com/threatwinds/go-sdk/wiki/Standard-Event-Schema)
38151
- [Rule implementation](https://github.com/threatwinds/go-sdk/wiki/Implementing-Rules)
39-
40-
`afterEvents`, empty noncapturing grok names, supported numeric strings, and custom
41-
`log.*` fields are accepted. Existing textual protocol casing and vendor action names
42-
are preserved unless a concrete consumer mismatch requires correction.

0 commit comments

Comments
 (0)