12 KiB
Enodia Sentinel Specification
This document defines Enodia Sentinel as an IDS, IPS, and EDR system, not only a signature IDS. The current implementation is a local Linux sensor with evidence capture, integrity monitoring, anti-rootkit checks, a dashboard, alert delivery, and dry-run prevention/response planning. The intended product is a defensive control plane for a host or small fleet: detect compromise, prevent or contain known-bad behavior through explicit operator workflows, prove what changed, preserve useful evidence, guide response, and make sensor tampering visible.
Product Definition
Enodia Sentinel is a zero-runtime-dependency Linux host security agent. It runs as a local daemon, observes high-signal host behavior, records forensic context when something suspicious happens, and exposes the result through local files, JSON, a read-only dashboard, push notifications, and command-line tools.
The long-term product should combine six functions:
| Function | Purpose |
|---|---|
| Detection | Find active compromise behavior: reverse shells, fileless execution, new listeners, suspicious egress, persistence edits, and privilege-escalation artifacts. |
| Prevention | Recommend and, after explicit review, apply containment actions such as stopping malicious processes, blocking C2 peers, disabling persistence, or quarantining files. |
| Integrity | Prove whether important files, packages, baselines, and Sentinel's own footprint changed. |
| Evidence | Capture enough context for incident response without forcing the operator to reproduce a live state after the attacker is gone. |
| Response | Provide safe, explicit operator workflows for triage, containment, and recovery. |
| Assurance | Make the agent itself measurable: heartbeat, dead-man's switch, tamper-evidence, and future remote attestation. |
Design Principles
- High-signal first. Prefer detections that are cheap to observe and costly for attackers to avoid, even if that means a smaller rule set.
- Evidence over noise. Every alert should carry enough context to answer "what happened, where, and what should I inspect next?"
- Zero dependency core. The base daemon must run with the Python standard library only. Optional layers such as bcc/eBPF may degrade cleanly.
- One local trust boundary is not enough. On-box checks are useful but root can tamper with them. Important anchors should move to signed package metadata, immutable filesystem controls, external watchers, or future remote attestation.
- Operator control. Sentinel should recommend response actions before it takes them. Destructive containment must be opt-in and auditable.
- Bash prototype remains the oracle. The original shell implementation and red-team harness preserve behavioral compatibility for core signatures.
Current Scope: Local IDS/IPS/EDR
Poll Detectors
The daemon builds one SystemState per sweep and runs pure detector functions
against cached process and socket data:
| Detector | Signal |
|---|---|
reverse_shell |
Interpreter with a network socket on fd 0/1/2. |
ld_preload |
Non-empty /etc/ld.so.preload or writable-path LD_PRELOAD. |
deleted_exe |
Process executing from a deleted file or memfd: image. |
input_snooper |
Non-allowlisted process holding keyboard/input/HID devices open. |
credential_access |
Non-allowlisted process reading credential databases, private keys, browser stores, or secret profiles. |
stealth_network |
Non-allowlisted raw, SCTP, DCCP, packet, MPTCP, TIPC, XDP, or vsock activity. |
memory_obfuscation |
Non-allowlisted executable anonymous/memfd/deleted mappings, RWX memory, or mapped process-hiding libraries. |
new_listener |
Listening socket absent from the startup baseline. |
new_suid |
New SUID/SGID binary, critical in writable locations. |
persistence |
Changes to cron, systemd units, SSH keys, shell rc files, and similar persistence locations. |
egress |
Interpreter with an established connection to a public IP. |
Event Detection
Optional bcc eBPF monitors feed event rule engines. The execve stream closes
the polling gap for short-lived commands and supports custom TOML rules without
code changes. The syscall stream watches short-lived memory and anti-analysis
behavior: RWX mprotect/mmap, memfd_create, sensitive ptrace, seccomp,
cross-process memory access, and memory locking. Typed host-event rules can be
tested from JSON fixtures before live sources exist; tcp_connect currently
covers interpreter egress to unusual public ports. Failure is fail-safe: if a
probe cannot load, polling continues.
Integrity and Tamper-Evidence
Sentinel includes several integrity layers:
| Layer | Current behavior |
|---|---|
| FIM baseline | SHA-256 baseline for critical files and Sentinel's own footprint. |
| Package verification | Optional pacman -Qkk verification for package-owned files. |
| Package DB anchor | Detects out-of-band edits to /var/lib/pacman/local. |
| Signed-package anchor | Compares on-disk files to .MTREE hashes from cached signed packages. |
| Heartbeat | Writes daemon liveness for local dashboard and external watchdog use. |
| Rootcheck | Cross-view checks for hidden processes, processes hidden from ps, hidden modules, hidden TCP/UDP/raw/special-protocol sockets, promiscuous interfaces, known rootkit modules, raw ICMP/SCTP-style channels, and kernel/module taint. |
Evidence Capture
When a fresh alert survives cooldown, Sentinel writes:
- A human-readable snapshot.
- A JSON snapshot suitable for automation and SIEM import.
- Relevant process tree, sockets, environment hints, file descriptors, and response guidance.
- Event log entries and dashboard-visible status.
Operator Interfaces
| Interface | Role |
|---|---|
| CLI | Run daemon, one-shot checks, baseline management, FIM checks, package DB checks, rootcheck, posture audit, incident review/export, triage, status/watchdog, and response planning. |
| Logs | Durable local evidence under /var/log/enodia-sentinel. |
| Dashboard | HTTPS-only read-only web view for status, incidents, timelines, alert browsing, posture findings, integrity/watchdog state, event-rule metadata, event tail, and response-plan previews. |
| Push | ntfy, Pushover, and generic webhook notifications. |
| Red-team harness | Safe drills for testing signatures and demos. |
CLI-generated response plans are durable artifacts: respond plan writes the
reviewed dry-run plan under response-plans/ and appends a JSONL
response-audit.log record. Dashboard/API previews remain read-only and do not
create artifacts. respond apply <plan-ref> --dry-run reloads a saved plan and
appends an apply-rehearsal audit record with executed: false; it does not run
commands.
Current IPS scope is explicit prevention workflow, not transparent inline
enforcement. Sentinel can recommend evidence preservation, process
freeze/termination, outbound IP blocks, systemd unit disablement, suspicious-file
quarantine, pacman package-owner lookup, signed-cache verification, trusted
package reinstall, FIM re-anchoring, and follow-up verification. It does not
execute those commands until a future audited --apply workflow is designed,
tested, and documented.
Target Scope: Host Security Platform
The next product shape should make Enodia useful before, during, and after an incident.
Prevent
- Configuration posture checks for risky SSH, sudo, systemd, cron, kernel, package manager, firewall, and service settings.
- Baseline drift reports for newly exposed services, new SUID files, new autostarts, new users/groups, and sensitive permission changes.
- A policy mode that can fail CI or package build checks for unsafe host images.
Detect
- More live event sources:
tcp_connect,bind,accept, file-write events for persistence paths, module loading, privilege transitions, and LSM hooks. - Correlation across signals: "web service spawned shell" + "new listener" + "persistence write" should become one incident, not three unrelated alerts.
- Optional YARA-style and Sigma-like local rules if they can stay dependency light and operator-readable.
Investigate
- Incident timeline files derived from event log, snapshots, FIM diffs, package transactions, process lineage, and network observations.
- Stable incident IDs that group related alerts over time.
enodia-sentinel incident show <id>andincident export <id>workflows.
Respond
- Safe containment actions behind explicit flags: stop a process, disable a systemd unit, remove a persistence entry, block an IP with nftables, quarantine a file, or freeze evidence.
- Dry-run by default, with JSON plans that can be reviewed before execution.
- Response playbooks that are code-reviewed data files, not shell snippets pasted into documentation.
Recover
- Package restore guidance: identify owning package, verify cache signature, reinstall package, and re-run integrity checks.
- Baseline reconciliation workflow after confirmed legitimate changes.
- Post-incident report generation from captured evidence.
Assure
- External anchor storage for baselines and package DB fingerprints.
- Signed snapshots or hash-chained event logs.
- Remote watchdog improvements and eventually fleet controller support.
- Optional TPM/IMA integration for machines that can support measured boot.
Data Model
The current Alert object is the public detection unit:
| Field | Meaning |
|---|---|
sid |
Stable signature ID for tuning, documentation, and downstream rules. |
severity |
MEDIUM, HIGH, or CRITICAL. |
signature |
Stable machine-readable detection name. |
classtype |
Snort/Suricata-style category. |
key |
Cooldown and deduplication identity. |
detail |
Human-readable explanation. |
pids |
Process IDs for snapshot deep dives. |
Incident grouping adds an incident_id at the snapshot-report level (not inside
each Alert), so it groups one or more alerts without changing the alert JSON
schema. Grouping is process-lineage first, with a time-window fallback for
PID-less alerts; see the command reference and
roadmap.
Operator-facing JSON contracts carry stable v1 schema IDs for alert snapshots, incident records/views/exports, status, response plans, and response audit records. The schema reference is SCHEMAS.md; compatibility tests pin required v1 fields and allow additive evolution.
Configuration Model
Configuration is a TOML file loaded at startup. Unknown keys are ignored so newer config templates remain tolerable on older agents, but documentation should clearly mark version-specific fields. Existing defaults should prefer detection correctness over suppression. Convenience suppression knobs should remain explicit and reviewable.
Security Model
Sentinel runs as root because it must inspect root-owned files, process state, file descriptors, and sockets. The systemd unit should continue to keep the root process narrow: read-mostly, constrained writable paths, no new privileges, restricted namespaces, and only the capabilities needed for the enabled layers.
Local root can eventually defeat any purely local sensor. Sentinel's answer is layering: signed package metadata, immutable files, off-box watchdogs, external anchors, and future kernel/attestation features.
Non-Goals
- Replacing a full enterprise SIEM.
- Silent self-hiding or rootkit-like persistence.
- Automatic destructive remediation without explicit operator approval.
- Shipping a broad dependency tree in the default agent.
- Claiming complete protection against a custom kernel implant.
Acceptance Criteria For New Platform Features
A feature is ready when it has:
- A stable
sid/signature or documented command contract. - Unit tests for pure logic and a safe integration path where practical.
- JSON output or a durable artifact suitable for automation.
- Configuration documented in the sample TOML and README or relevant docs.
- Failure behavior that does not take down the daemon.
- Clear operator guidance for false positives, limitations, and response.