Skip to content

azurebeard/harbinger

Repository files navigation

Harbinger

An AI-powered log pre-classifier for Microsoft Sentinel.

Apache 2.0 Python 3.11+ Release CI

Harbinger sits alongside your existing log path to Microsoft Sentinel. It listens to a copy of your syslog feed, classifies each event with a local Ollama model, and produces a profile report showing which sources are signal, which are noise, what tier they belong on, and how much you could save by re-tiering. The traffic actually reaching Sentinel is untouched.


Contents


Why Harbinger exists

Microsoft Sentinel charges by ingested gigabyte. A typical SOC pipes everything into the Analytics tier "just in case", which means a non-trivial slice of the bill is funding storage for liveness probes, cron ticks, and routine kernel messages that no analyst will ever query. Sentinel offers a Basic tier and an Auxiliary tier specifically for these — Basic at roughly 1/5 the cost, Auxiliary at roughly 1/100 — but figuring out which sources should land where is a manual review job that operators rarely have time to do.

Harbinger is the answer to "what would happen if we automated that first pass". It reads a copy of the traffic, classifies each event with a small local LLM, and tells you per source:

  • Is this high-signal, medium-signal, low-signal, or noise?
  • Which Sentinel tier (Analytics / Basic / Auxiliary) belongs to this source?
  • How many GB/day is this source contributing?
  • What does the current spend look like and how much could you save by adopting the recommendation?

The output is a report. Not a routing decision, not a DCR change, not a Slack message — a JSON + Markdown report you read, evaluate, and act on yourself.


What it does

Capability Detail
Ingest Listens on UDP/TCP for syslog (RFC 3164 + RFC 5424). Also detects NXLog and Winlogbeat JSON-over-syslog for Windows event semantics.
Classify Local Ollama model (phi4-mini recommended). Returns log_type, signal_grade, tier_recommendation, confidence.
Aggregate SQLite (WAL) rollups by (source, log_type, 5-minute window). Bounded retention.
Report JSON (schema-pinned) + Markdown + HTML. Per-source breakdown, Windows EventID histograms, anomalies, top-10 noise sources, monthly cost projections in your chosen region and currency.
Cost projection Live Azure Retail Prices API integration. Multi-region. Multi-currency via either operator-pinned rates or an optional Frankfurter (ECB) FX cache.
Run One-shot installer, repo-root launcher (./harbingerctl), hardened systemd unit. Air-gapped supported. Release CI gated on pip-audit + pytest.

A complete example of the JSON report shape is at docs/sample-profile.json.


Why observe-only matters

Harbinger never modifies, filters, or routes traffic going to Sentinel. The traffic that reaches your existing ingestion pipeline is untouched — Harbinger only sees a fan-out copy.

This is a permanent design property, not a v1 limitation. There is no code path that could suppress an event before it leaves the relay. The reasoning:

  • Blast radius. Anything that modifies live security telemetry needs an approval workflow, a threat model, a roll-back path, and a different posture toward false positives. Bundling that with a profiler doubles the surface area for a marginal benefit.
  • Trust. Operators evaluating Harbinger should never have to wonder whether it might quietly drop a critical event. The answer is "no — by construction".
  • Composability. If you want routing, you build it downstream of Harbinger's report — rsyslog and syslog-ng already do this well using filters keyed on programname or content. Harbinger's job is to tell you what to filter; your existing tooling does the filtering.

See docs/architecture.md §6 for the full list of non-goals and the rationale for each.


How it works

flowchart LR
    A[Linux syslog]      --> R[rsyslog / syslog-ng]
    B[Windows hosts<br/>via NXLog / Winlogbeat] --> R
    R -- original copy --> S[Microsoft Sentinel<br/>untouched]
    R -- fan-out copy --> H[Harbinger]
    H --> O[profile.json<br/>profile.md<br/>profile.html]
    E[.evtx files] -.->|harbinger replay-evtx| H
Loading

Internally Harbinger is a 5-stage asyncio pipeline with bounded queues. Full architecture, including trust boundaries and failure modes, is in docs/architecture.md.


Installation

git clone https://github.com/azurebeard/harbinger.git
cd harbinger
./scripts/install.sh

install.sh checks Python ≥ 3.11, creates a venv, installs Harbinger and its dependencies, and copies the example config into place. The script is idempotent — re-running is a no-op.

For Windows event ingestion via .evtx replay, install the optional extra:

.venv/bin/pip install -e ".[evtx]"

For deployment under systemd (auto-restart, hardened sandbox), see the recipe at the top of scripts/harbinger.service and docs/live-test.md § 7b.


Quick start

# 1. Pull a local model
ollama pull phi4-mini

# 2. Start the listener (defaults to 127.0.0.1:1514 — needs no root)
./harbingerctl run --config config/harbinger.yaml --heartbeat 5

# 3. Send 200 synthetic events from a second shell to validate the install
./harbingerctl smoketest --count 200

# 4. Render a profile report
./harbingerctl report --since 5m --output-dir ./reports

For an rsyslog fan-out example, see docs/quickstart.md. For the 30-minute end-to-end VM playbook including real syslog forwarding and systemd deployment, see docs/live-test.md.


Example output

Excerpt from a 24-hour profile report rendered by harbinger report. Full example: docs/sample-profile.json.

Harbinger Profile Report
========================
Window:     2026-07-14 09:00:00Z → 2026-07-15 09:00:00Z (24 h)
Events:     412,857 across 9 (source, log_type) pairs
Region:     uksouth      Currency: GBP

Top sources by volume
─────────────────────
source                         log_type                events     GB/day  signal  recommend     £/month
web-01.example.local           nginx-access           198,432   0.0897  noise    auxiliary       16.98
dc-01.example.local            windows-security-logon  84,561   0.0532  high     analytics      863.91
fw-edge-01.example.local       firewall-deny           56,298   0.0225  medium   basic           76.80
app-batch-03.example.local     ssh-auth                32,487   0.0117  high     analytics      189.93
dc-01.example.local            windows-sysmon-process  26,041   0.0089  high     analytics      143.81
app-batch-03.example.local     cron                     8,642   0.0014  noise    auxiliary        0.26
…

If every source were placed on its recommended tier, projected savings vs an
Analytics-everywhere baseline: £1,284.42 / month.

Anomalies (across all sources): future_timestamp=12, oversized_message=3

Per-source Windows breakdowns (top EventIDs, channels, providers) and parser-side anomaly flags are surfaced inline. See docs/schema.md for the full output contract.


Requirements

Component Minimum Notes
Python 3.11+ 3.12 recommended; 3.13 supported
Ollama Latest stable One supported model pulled — phi4-mini is the default recommendation
OS Linux Tested on Ubuntu 22.04 and 24.04. Any Debian or RHEL family should work. macOS works for development but not the documented systemd path.
vCPU 4 For sub-second classification on CPU. Fewer is workable but cold-starts are slower.
RAM 8 GB Smaller is OK for short captures; 4 GB will OOM under sustained load with phi4-mini resident.
Disk 20 GB ~3 GB for Ollama + model; remainder for SQLite retention and reports.

Air-gapped operators: see config/harbinger.example.yaml for the pricing.offline and pricing.fx_offline knobs and the configurable pricing.fx_api_url for mirroring Frankfurter internally.

Model sizing trade-offs (CPU latency, JSON conformance, memory footprint) are in docs/benchmark.md.


Security considerations

Property Implementation
Event content stays local Classification runs against a loopback Ollama endpoint by default. No cloud inference path exists.
Outbound network limited and disable-able Only two outbound HTTPS endpoints (prices.azure.com, api.frankfurter.app), both for cost projections, both off-switchable.
Unprivileged by default Binds port 1514 (no CAP_NET_BIND_SERVICE needed). Loopback bind by default.
No back-pressure on upstream Bounded queues + drop-on-overflow. Harbinger being slow never stalls the operator's syslog forwarder.
Per-source rate limiting Token-bucket cap stops one bad sender starving others.
Hardened systemd unit NoNewPrivileges, ProtectSystem=strict, ProtectHome, PrivateTmp, MemoryDenyWriteExecute, RestrictAddressFamilies.
Release CI gated on pip-audit Every tag-push runs pip-audit against the runtime dependency closure. CVEs in any direct or transitive dep block the release.
No telemetry, no phone-home Harbinger collects no usage data. The only outbound calls are the documented two above.

Full security posture and disclosure process: SECURITY.md.


Limitations

Harbinger is honest about what it can and can't do. The full document is LIMITATIONS.md; the high-level summary:

  • Classifier accuracy depends on the model. Small CPU models (1–4 GB) handle the common patterns well but can be confidently wrong on rare or vendor-specific log shapes. The confidence floor (default 0.6) catches the worst cases by downgrading them to unknown; tune via classifier.confidence_floor.
  • Recommendations are advisory. The reports tell you what looks like noise; the operator confirms and acts.
  • Single-host design. No clustering, no shared state between instances. For estates above ~1000 events/s sustained, shard by source.
  • Linux-only deployment surface. Windows event ingestion works fine (via JSON-over-syslog or .evtx replay) but Harbinger itself runs on Linux.
  • No real-time alerting. Reports are batch-rendered on demand; Harbinger is a profiling tool, not a SIEM.

Roadmap

There is no committed roadmap beyond v1.x. The pre-1.0 backlog has all shipped (Windows event ingestion, FX cache, multi-region pricing, multi-currency conversion). Future direction will be issue-driven.

Permanently out of scope (with rationale in docs/roadmap.md):

  • Active tier routing — by design.
  • Native WEC/WEF endpoint — wrong shape for an observe-only tool.
  • Cloud inference — event content never leaves the host.
  • Hosted dashboard — Harbinger is a CLI tool; the JSON output is consumable by any external visualisation.

Documentation index

Document Purpose
README.md You are here.
docs/architecture.md Full runtime architecture, trust boundaries, failure modes, non-goals.
docs/schema.md Public stability contract — JSON output, CLI, config file.
docs/sample-profile.json Complete realistic example of the JSON output.
docs/quickstart.md 5-minute syslog fan-out example with rsyslog / syslog-ng / journald.
docs/live-test.md 30-minute end-to-end VM playbook with real syslog forwarding.
docs/benchmark.md Sizing and tuning. Model comparison, worker-count guidance.
docs/windows-events.md NXLog, Winlogbeat, and .evtx recipes.
docs/roadmap.md Release history and permanently-out-of-scope items.
SECURITY.md Security posture and disclosure process.
LIMITATIONS.md Known limitations of v1.x.
CONTRIBUTING.md Development workflow, testing, coding standards.
FAQ.md Frequently asked questions.
CHANGELOG.md Release notes.

About

AI-powered log pre-classifier for Microsoft Sentinel — observe-only profiler

Topics

Resources

License

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors