ESC
> PressHaven alpha
Home › Docs › Architecture

Architecture

System architecture, request pipeline and the pure/adapter split

Architecture Overview

The honeypot system is built on a layered architecture following a pure/adapter split pattern. All core logic lives in *_rules.lua modules with zero ngx.* dependencies, making them unit-testable under a plain Lua interpreter. Adapters do the I/O — Redis, Nginx, the file system, AbuseIPDB — and delegate every decision back to a pure rule module.

The system can run as two hosts (edge and SIEM, the production shape) or as one host for evaluation. Topology does not change the detection logic; it only changes where telemetry is stored.

Layers and Responsibilities

Request Pipeline

Client Request → Nginx access_by_lua_block → pattern_analyzer.analyze_request()
  → router.decide_route() (12 stages) → pool_router.get_or_assign_pool()
  → session_handler.update_session() → Redis session_store
  → Suricata eve.json → init_worker.lua → threat_intel shared dict
  → abuseipdb_client.report_ip_async() → AbuseIPDB

The pipeline is deliberately synchronous in the decision path. Configured work that must not block the response — AbuseIPDB reporting, pool provisioning, content sync — is queued or handled by a worker.

Routing stages

The twelve stages are ordered from cheapest and most certain to most heuristic. A static asset is released immediately; a session already bound to a pool never has to be evaluated again for stickiness.

StageConditionRouteReason
1Static assetProductionNo attack surface
1aConsent-gated gdpr_signature match (returning honeypot visitor)HoneypotKnown-bad browser re-consented
1binstall.php on uninstalled WordPressProductionLegitimate setup wizard
2Session already honeypot-boundHoneypotSticky binding
3Risk score ≥ thresholdHoneypotHigh risk
4CVE pattern matchedHoneypotKnown exploit attempt
5Vulnerable plugin URIHoneypotDirect plugin endpoint access
6Bad IP reputation (> 50)HoneypotFlagged source
7Multiple admin attempts (≥ 3)HoneypotWSTG-ATHN-04
8Accumulated suspicious activity (≥ 5)HoneypotCumulative signals
9Rapid automation (score ≥ 40)HoneypotWSTG-INFO-02
10Suspicious file uploadHoneypotWSTG-INPV-10
11DefaultProductionNo rule fired

Lua Modules

The system uses 18 pure modules and their adapter counterparts. Pure modules contain no ngx.* dependency and are unit-testable under a plain lua interpreter.

Pure ModuleAdapterPurpose
pattern_rules.luapattern_analyzer.luaURI/header/CVE pattern scoring
prompt_injection_filter.luapattern_analyzer.luaLLM prompt-injection pattern probe
vulnerability_rules.luavulnerability_handler.luaCVE/exploit-kit pattern matching
suricata_rules.luainit_worker.luaeve.json alert parsing/scoring
abuseipdb_rules.luaabuseipdb_client.luaReport eligibility logic
router_rules.luarouter.luaRouting predicates
upload_rules.luaupload_handler.luaFile-upload pattern analysis
admin_rules.luaadmin_handler.luaAdmin-access decision logic
session_rules.luasession_handler.luaSession anomaly detection
decay_policy.luarouter_rules/suricata_rulesEscalation-aware decay
lua_pattern_utils.lua—Shared string helpers
ip_rules.luainit.lua (utils)IPv4/IPv6 CIDR matching
honeytoken_rules.luahoneytoken_handler.luaToken-in-corpus matching
gdpr_rules.luagdpr_handler.luaConsent-gated identity
shared_ip_rules.luapattern_analyzer.luaShared-address policy
pool_router_rules.luapool_router.luaPool routing logic
session_identity_rules.luasession_handler.luaSession cookie identity
maintenance.luanginx.confScheduled-maintenance gate

Run-time details collected from the modules' comments — shared dicts, background timers, the Redis key schema, tuned constants and the bugs behind them — are in Lua Internals.

Pooling System

Each user session is permanently assigned to a specific honeypot pool instance (honeypot_eshop_N + honeypot_database_N). Pools are cloned from a pre-built template. Assignment is atomic via Redis EVAL. Scale-up and scale-down are managed by pool_manager.

  • Exclusive first. A free ready pool is claimed atomically, so two sessions cannot share an exclusive assignment.
  • Spare provisioning. Every assignment queues a wake-up, and the manager builds the next pool pair in parallel.
  • Borrow, then move. A waiting session borrows a ready pool and is moved when its own pool finishes building.
  • Bounded reuse. At the resource ceiling, sessions share ready pools round-robin instead of failing.
  • Idle retirement. Assignments expire after 24 hours; pools above the spare count are removed after the idle timeout.
  • Health fallback. If the assigned pool is unhealthy, the router serves the next healthy pool without changing the stored assignment.

See Honeypot Engine for the pool lifecycle, configuration knobs and isolation model.

State and Failure Modes

Redis holds the state that makes sessions sticky: session blobs, accumulated risk, offense counters and pool assignments. Nginx also keeps 10 MB shared dictionaries for sessions and threat intelligence — shared across all worker processes of the Nginx instance, not per-worker — so hot paths avoid a round-trip when possible.

  • Redis unavailable. Session stickiness degrades; the router must prefer a safe production fallback rather than blocking the shop.
  • Pool unhealthy. The router falls back to the next healthy pool without changing the stored assignment.
  • Suricata silent. Application-layer scoring continues; only the network signal is lost.
  • SIEM unreachable. The edge keeps serving. Vector buffers and retries; detection is never coupled to Kibana availability.
  • Signing key unset. A random key is generated at startup; cookies from the previous process no longer verify. Set SESSION_SIGNING_KEY explicitly in production.

GDPR Identity

A second, consent-gated identifier runs alongside the signed SERVERID cookie. Only after the visitor agrees does the browser RSA-OAEP-encrypt a few characteristics and a timestamp into a gdpr_token; the proxy decrypts it in memory, checks freshness and hashes it into a one-way gdpr_signature. Only the signature is stored, and only while bound to a honeypot. It recovers a returning adversary's session (routing stage 1a); it is not a tracking identifier for legitimate visitors. The full flow and settings are on Device & GDPR Signature.