Skip to content

feat(ids): label Suricata alerts by interface, and write the Degens runbook (#89) - #242

Merged
Gerrrt merged 3 commits into
mainfrom
gerrrt/suricata-degens-vlan-4e42c2
Sep 2, 2026
Merged

Gerrrt merged 3 commits into
mainfrom
gerrrt/suricata-degens-vlan-4e42c2

Conversation

@Gerrrt

@Gerrrt Gerrrt commented Sep 2, 2026

Copy link
Copy Markdown
Owner

What changed

Part one of two for #89 — everything that has to be live before Degens (VLAN 10) is enabled.

  • syslog.alloy: Suricata alerts get an interface label derived from the syslog facility (local1 → igc0.20, local2 → igc0.10). Same name and vocabulary as filterlog's. Unmapped facility → no label, visibly absent.
  • security.rules.yaml: SuricataHighPriorityAlert and SuricataAlertStorm aggregate by interface and name it in the summary. Thresholds unchanged; rule count unchanged (13).
  • security-overview.json: the five Suricata panels honour $interface; the variable's query widens to {source="network"}; the text panel explains the label's two provenances. Panel count unchanged (140).
  • enable-suricata.md: §2's facility note is rewritten (it said facility was harmless; it is now load-bearing), §5 records the signature that is 79% of Skids' first fortnight, and a new §6 is the Degens procedure. Two stale config.alloy references fixed (here and in observability.md).

Why

The alert line carries no interface and pfSense hardcodes the syslog identity to suricata for every interface, so two interfaces on today's pipeline would be indistinguishable — every rule and panel would merge them, which is precisely what the issue's "one interface at a time" is meant to prevent. The facility is the only per-interface setting that reaches the wire.

Measured before designing (Loki, 14 days): Skids at 190–357 alerts/day, all priority 3, none priority 1 or 2, 2200121 gone, and 2,337 of 2,949 are sid 2210044 from a spread of devices to :443. Recorded in §5, not suppressed: at two per ten minutes it buries nothing, and whether Degens shows the same share is the question the second interface answers.

Verified from pfSense source, not assumed: the remote System Events selector drops local0, local3, local4 and local7, so an interface on one of those would alert locally and never reach Loki. §6 says which facilities are safe.

Two costs, stated: the dashboard's .+ all-value drops the pre-label Skids history, so the 24h stats read low for a day after the Alloy restart (30-day retention ages it out); and a ruleset update matching ordinary traffic on both segments at ~101 each no longer fires the storm rule where a global sum would have.

Two things found on the way, neither fixed here: two of the top sources for 2210044 (10.0.20.110, 10.0.20.105) are not in network.md; and the Suricata engine-log checkbox, if ever ticked, would arrive as app="suricata" with no classification (§6 says leave it off).

Blast radius

  • No segmentation change
  • No new published port
  • No credential outside secrets/*.sops.yaml

Verification

  • make validate passes — 13 Loki rules and 28 dashboard expressions evaluated by the ruler, 140 panels, docs counts agree
  • Deployed and confirmed — after merge, from the main checkout: make up, wait ten minutes, then sum by (interface) (count_over_time({app="suricata"}[10m])) must return exactly one row, igc0.20. Degens is not enabled until that passes. Part two (present-tense docs, roadmap Done entry) follows after several days of Degens.
  • Docs updated

🤖 Generated with Claude Code

…nterface's runbook (#89)

Suricata's syslog line does not say which interface saw the alert, and
pfSense sends every interface's alerts under the same tag. With a second
interface, every rule and panel would have merged them silently — the exact
thing the issue says must not happen. The one per-interface setting that
reaches the wire is the interface's Log Facility, so syslog.alloy now maps
it to the same `interface` label filterlog carries: local1 → igc0.20 (the
package default, Skids), local2 → igc0.10 (Degens, set when it is added).
An unmapped facility gets no label rather than a wrong one.

Verified from pfSense source rather than assumed: the remote System Events
selector drops local0/3/4/7, so an interface on one of those would alert on
the box and never reach Loki. The runbook says which facilities are safe.

Both Loki rules now aggregate by interface and name it in the summary;
thresholds unchanged. The five Suricata panels honour the $interface picker,
whose query widens from filterlog to the whole network source.

The runbook gains §6 for Degens, and §5 records the signature that is 79%
of Skids' first fortnight (sid 2210044, stream-events, a spread of devices
to :443) — measured, and deliberately not suppressed until the second
interface can say whether it is the Wi-Fi or the devices.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Copilot AI lite review requested due to automatic review settings September 2, 2026 05:33

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The dashboard’s explanatory text contradicts the new $interface filtering behavior (unlabeled Suricata streams would be hidden), and alert summaries should explicitly handle missing interface to avoid ambiguous notifications.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

This PR prepares the observability and runbook plumbing needed to enable Suricata on a second pfSense interface (Degens/VLAN 10) without merging alerts/panels across interfaces, by deriving a consistent interface label for Suricata alerts and propagating it through Loki rules, Grafana, and docs.

Changes:

  • Add interface labeling for Suricata alerts in syslog.alloy (facility → interface mapping).
  • Update Loki alerting rules and Grafana Suricata panels to aggregate/filter by interface.
  • Expand the Suricata enablement runbook with a Degens (VLAN 10) procedure and clarify facility/priority implications.
File summaries
File Description
stacks/observability/alloy/syslog.alloy Derives interface for Suricata alerts from syslog facility before parsing stages.
stacks/observability/loki/rules/security.rules.yaml Aggregates Suricata alerts by interface and includes interface in summaries.
stacks/observability/grafana/dashboards/security-overview.json Updates interface variable query and makes Suricata panels honor $interface; expands explanatory text.
docs/runbooks/enable-suricata.md Updates facility guidance and adds a detailed Degens enablement/verification section.
docs/observability.md Fixes doc reference from config.alloy to syslog.alloy.
Review details

Suppressed comments (1)

stacks/observability/loki/rules/security.rules.yaml:311

  • Same as above: if interface is unset, the storm alert summary becomes hard to interpret. Default to an explicit placeholder so that an unlabeled Suricata stream is immediately obvious from the alert notification.
          summary: "{{ $value }} Suricata alerts on {{ $labels.interface }} in 10 minutes"
  • Files reviewed: 5/5 changed files
  • Comments generated: 2
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Gerrrt and others added 2 commits September 2, 2026 13:33
…nd stop claiming hidden streams are visible

Review on #242. An unmapped facility leaves `interface` unset on purpose, but
an alert summary that then reads "Suricata priority-1 on : ..." hides the
very fault it should point at. Both summaries now name the case. And the
dashboard text said such a stream would show up with an empty `interface`,
when every Suricata panel filters on `$interface` with `.+` for All — it is
hidden, not mislabelled, and the runbook's unfiltered query is what shows it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@Gerrrt
Gerrrt merged commit 027fc3a into main Sep 2, 2026
3 checks passed
@Gerrrt
Gerrrt deleted the gerrrt/suricata-degens-vlan-4e42c2 branch September 2, 2026 13:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants