Add `enodia-sentinel posture check` — a config-hygiene audit that finds the conditions making a host easy to attack, complementing the live detectors. Checks: SSH root/password/empty-password login (Include-aware, first-wins sshd resolution), passwordless and group/world-writable sudoers, world-writable or non-root PATH directories, loose permissions on sensitive files (/etc/shadow, /etc/passwd, ...), and downgraded package-signature policy (reusing pkgdb.siglevel_alert). Findings reuse the Alert type, so they serialize through the existing JSON/triage pipeline (`posture check --json`). Each check is a pure evaluator over injected content/stat facts plus a thin system reader, so the 18 new tests need no root or live /etc. Posture is command-driven and never runs in the daemon loop, per the v0.8 exit criterion. SIDs 100040-100047 (classtype host-posture). Sample config and docs (COMMAND_REFERENCE, OPERATIONS, ROADMAP, SPECIFICATION) updated. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
206 lines
9.2 KiB
Markdown
206 lines
9.2 KiB
Markdown
# Enodia Sentinel Specification
|
|
|
|
This document defines Enodia Sentinel as a host security platform, not only a
|
|
signature IDS. The current implementation is a local Linux sensor with evidence
|
|
capture, integrity monitoring, anti-rootkit checks, a dashboard, and alert
|
|
delivery. The intended product is a defensive control plane for a host or small
|
|
fleet: detect compromise, 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 five functions:
|
|
|
|
| Function | Purpose |
|
|
|---|---|
|
|
| Detection | Find active compromise behavior: reverse shells, fileless execution, new listeners, suspicious egress, persistence edits, and privilege-escalation artifacts. |
|
|
| 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
|
|
|
|
1. **High-signal first.** Prefer detections that are cheap to observe and costly
|
|
for attackers to avoid, even if that means a smaller rule set.
|
|
2. **Evidence over noise.** Every alert should carry enough context to answer
|
|
"what happened, where, and what should I inspect next?"
|
|
3. **Zero dependency core.** The base daemon must run with the Python standard
|
|
library only. Optional layers such as bcc/eBPF may degrade cleanly.
|
|
4. **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.
|
|
5. **Operator control.** Sentinel should recommend response actions before it
|
|
takes them. Destructive containment must be opt-in and auditable.
|
|
6. **Bash prototype remains the oracle.** The original shell implementation and
|
|
red-team harness preserve behavioral compatibility for core signatures.
|
|
|
|
## Current Scope: v0.7
|
|
|
|
### 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. |
|
|
| `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
|
|
|
|
An optional bcc eBPF `execve` monitor feeds a declarative rule engine. This
|
|
closes the polling gap for short-lived commands and supports custom TOML rules
|
|
without code changes. Failure is fail-safe: if the 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, hidden modules, hidden ports, and promiscuous interfaces. |
|
|
|
|
### 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, triage, watchdog. |
|
|
| Logs | Durable local evidence under `/var/log/enodia-sentinel`. |
|
|
| Dashboard | Read-only web view for status, alert browsing, and snapshot inspection. |
|
|
| Push | ntfy, Pushover, and generic webhook notifications. |
|
|
| Red-team harness | Safe drills for testing signatures and demos. |
|
|
|
|
## 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 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>` and `incident 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. |
|
|
|
|
Future incident grouping should add an `incident_id` around one or more alerts,
|
|
without breaking the alert JSON schema.
|
|
|
|
## 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.
|