Trishula

An eBPF-native, developer-first Web Application and API Firewall for Kubernetes

License Project board

Status: research / pre-alpha. Design is specified in the PRD (v4) and the research paper; implementation starts from zero, tracked as TR-01 … TR-36. Nothing here should be presumed working yet. This is research for adoption — not a product pitch.

Intro

Trishula is an open Web Application and API Firewall for Kubernetes that operates at kernel altitude while preserving the full userspace detection stack. One sentence: the WAF is the last security control that never crossed to developer ubiquity — Trishula brings it across. Three components, two planes, one decision record per request.

flowchart LR
    subgraph KERNEL["kernel plane"]
        xdp["eBPF shield<br/>XDP + TC"]
        maps["maps<br/>ACL · verdict cache · ban table"]
    end
    subgraph USER["userspace plane"]
        lad["detection ladder<br/>S0-S6"]
    end
    gw["Gateway API<br/>(NGF reference)"] --> lad
    lad --> app["app pods"]
    xdp --- maps
    lad -- verdicts --> otel[("OTLP<br/>trishula.verdict.v1")]

Objectives

  1. Adoptability as a first-class feature — CRD-driven policy, per-route promotion gates (learn → shadow → enforce), verdict telemetry a developer can actually read. The people who own the app own its protection.
  2. Full detection stack at kernel altitude — negative signatures, positive security, bot mechanisms and behaviour bans, backed by an eBPF enforcement point no middleware chain can offer.
  3. Parity before novelty — OWASP CRS runs via embedded Coraza as the reference evaluator; a CI-blocking differential suite proves the engine matches it, always.
  4. Honest engineering — fail-open defaults, evidence records for every ban, exit criteria that report pass/fail as measured.

Why this project

Three curves converge, and each alone is an optimization. Together they are an opening:

  • Gateway API consolidation — Kubernetes ingress is standardising on the Gateway API; the edge is being re-plumbed right now, and the WAF’s integration point is up for grabs.
  • eBPF maturity — kernel-altitude packet processing is dependable, inspectable and CO-RE portable; enforcement does not need to live in a middleware hop.
  • AI traffic at the WAF’s front door — agents, scrapers and automated abuse hit exactly the layer the WAF inspects; they mint fingerprints machines cannot hide behind, and they arrive faster than hand-written signatures can follow.

Negative signatures alone cannot carry a modern estate: too much good traffic to risk, too slow to maintain by hand. That is the reason for the project — and why the emphasis is positive security, fingerprinting and behaviour analysis with signatures as one (important) stage among several.

The WAF problem

A web application firewall inspects HTTP conversations and decides: allow, block, rate-suppress or tag. The classic estate runs it in three shapes — an appliance at the edge, a module inside the reverse proxy (ModSecurity-lineage), or a sidecar/car next to the app. Each shape keeps the decision point outside the packet path’s cheapest altitude, and each inherits the middleware’s latency, scaling and failure behaviour.

What a WAF must decide today:

  • known-bad requests — signature sets (OWASP CRS) remain the base layer;
  • policy violations — the request uses the API in ways its OpenAPI spec forbids (positive security);
  • automation posing as users — TLS/HTTP fingerprints (JA4), header order, value entropy, behavioural cadence;
  • abuse patterns — rate anomalies and repeat-offender behaviour needing temporary bans;
  • new attack classes — LLM/agent traffic shapes that no signature has seen yet.

Traditional deployments answer these with a negative-signature engine and hope. The cost is well known: false positives that block good users, rules maintained by specialists, and telemetry a developer cannot read. Trishula’s answer is structural: keep CRS as one stage, add the positive/fingerprint/behavioural stages, and move the cheapest decisions to the kernel — with every verdict emitted as OpenTelemetry.

Kubernetes deployment

flowchart TB
    subgraph cluster["Kubernetes cluster"]
        subgraph gwplane["gateway plane"]
            ngf["NGF (Gateway API)"]
        end
        subgraph wafplane["Trishula"]
            eng["engine deployment<br/>(plain backend Service)"]
            opr["operator<br/>(WAFPolicy / BanPolicy CRDs)"]
            sh["shield DaemonSet<br/>(XDP/TC eBPF)"]
        end
        app["application pods"]
    end
    clients["clients"] --> ngf
    ngf -- HTTPRoute --> eng
    eng --> sh
    eng --> app
    opr -- bundles + map pre-seed --> eng
    opr -- pinned maps --> sh

  • Install order: operator → shield (DaemonSet) → engine. The operator reconciles WAFPolicy / BanPolicy CRs into compiled engine bundles (double-buffered) and pre-seeds shield maps.
  • Gateway API integration: the gateway steers to the engine as a plain backend (HTTPRoute); NGF is the reference data plane — the whole reference stack is OSS. Conformant alternatives (Envoy Gateway, Istio, Traefik, Emissary, kgateway) attach the same way; an ext_proc wire-contract variant for Envoy-family estates is feature-gated for later.
  • Fail-open by default: an inline shaper must never become the outage; failureMode is explicit and audited per policy.
  • Rollback: a CRD-recorded re-pin of the previous bundle — never a hand-hack.
  • Node requirements: kernel ≥ 5.8; the shield is CO-RE and verifier-checked in CI.
  • Telemetry: every verdict is an OTLP span + metric + log on trishula.verdict.v1; dashboards ship in-repo.

Detection ladder (short-circuit ordered): S0 kernel pre-clear (ACL, verdict cache, ban table) → S1 cache re-check → S2 CEL rules (cost-budgeted) → S3 OWASP CRS via embedded Coraza → S4 OpenAPI positive security → S5 rate limits → S6 bot fingerprints and behavioural windows. ScoredWindowBan turns repeated abuse into kernel-enforced temporary bans, evidence-recorded, prefix escalation off by default.

Roadmap

Work is tracked on the Trishula — Roadmap & Build Board (org Project) as issues TR-01 … TR-36 in the trishula repo. Every issue lands a runnable artefact with an exit criterion — prove the ladder end-to-end, not slide-by-slide.

Milestone Items
v0.1 TR-01–TR-14: repo seed, CEL seed, shield PoC, ingest, ladder slice, NGF lab, CRS differential, operator/CRD, ban shadow + enforce, OTel, bots v0, positive v0, honest exit
v0.2 TR-15–TR-26: HTTP/2+gRPC, Vectorscan, CEL hot reload, OpenAPI learn, behavioural bots, rate-limit ladder, ONNX scorer, ext_proc, DX gate, bench, multi-tenancy, Envoy lane
v0.3 TR-27–TR-36: academy, HTTP/3 + PQ posture (evaluation only), behavioural DoS, DPU, multi-arch, residue gate, composition watch

Contributions welcome: pick an issue labeled complexity:starter or any area:* that suits you; the referenced PRD section in the issue body is the design source. Branch + PR against trishula-dev/trishula (Apache-2.0).

Reasoning: why these specific choices

  • eBPF (XDP first, TC alongside) — the only mechanism that gives kernel-altitude, programmable, verifiable packet policy on stock Kubernetes nodes; CO-RE keeps builds portable. The drop happens where the packet arrives; a middleware chain cannot offer that.
  • Gateway API + NGF as reference — Gateway API is where Kubernetes ingress is consolidating; NGF keeps the whole reference deployment OSS and mirrors the topology operators already run. Envoy-family estates get the feature-gated ext_proc variant later; lock-in to one data plane is not a goal.
  • Embedded Coraza, not a rule-engine rewrite — CRS compatibility is the adoption surface; embedding buys exact parity by construction (the same parser semantics), and the differential suite keeps a from-scratch fast path honest when it arrives (Vectorscan hot subset, behind a shadow gate).
  • CEL for the first-class DSL — typed, cost-budgeted evaluation, Kubernetes-native ergonomics, and a compile step the CRD pipeline can gate on cost before load; a general regex DSL alone cannot offer bounded evaluation cost.
  • OpenAPI positive security with promotion gates — the developer-first path: specs exist in repos already; learn → shadow → enforce makes adoption incremental instead of a big-bang policy cutover.
  • ScoredWindowBan over naive counters — fail2ban-style bans with an algorithmic scoring window, evidence per ban, prefix escalation off by default: shared-egress false positives are the practical ban killer.
  • OpenTelemetry as the verdict contract — every verdict a correlated span+metric+log; security that cannot show its work cannot be adopted by developers.
  • fail-open by default — an inline kernel shaper must never become the outage; failureMode is explicit and audited per policy.

Paper

The arXiv-style paper (“Trishula: An eBPF-Native, Developer-First Web Application and API Firewall for Kubernetes”) is the research companion to this site: the adoptability thesis, the honest field survey (Coraza, ModSecurity, SafeLine, open-appsec, CrowdSec, fail2ban, the eBPF cousins) with the feature-coverage matrix, and the adoption plan. A public link lands here when the paper is archived; until then it travels with the project docs.