enodia-sentinal/docs/COMMAND_REFERENCE.md

508 lines
16 KiB
Markdown

# Enodia Sentinel Command Reference
Applies to package version: `0.7.0`
Docs version: `0.7`
Schema generation: `v1`
This is the operator-facing command contract for the current local agent. Commands
are intentionally plain: they either inspect state, manage baselines, run the
daemon, or expose existing evidence.
Global options:
```bash
enodia-sentinel --version
enodia-sentinel -c /path/to/config.toml <command>
```
If no command is provided, `run` is used.
## Service Commands
### `run`
```bash
enodia-sentinel run
```
Starts the daemon loop. This is the command used by the systemd service. It
builds or loads baselines, starts optional exec/syscall event monitoring, writes
heartbeats, runs detector sweeps, captures snapshots, and sends notifications.
Expected use: systemd, not an interactive shell.
### `check`
```bash
enodia-sentinel check
enodia-sentinel check --json
```
Runs the enabled detector set once and prints alerts. This forces the SUID scan
and arms baseline-gated detectors immediately, so it is useful for health checks
and debugging. `--json` emits the alerts as a JSON array of alert dicts
(severity-ordered) instead of text, for scripts and the tray applet.
Exit code:
- `0`: no alerts.
- `0`: alerts may still print today; this command is currently human-oriented,
not a strict CI gate.
### `baseline`
```bash
enodia-sentinel baseline
```
Rebuilds listener and SUID baselines under `log_dir`. Use after installing on a
known-good host or after intentionally adding persistent services or privileged
helpers.
Do not run this to silence unexplained findings.
### `baseline accept` / `revoke` / `list`
```bash
enodia-sentinel baseline accept <kind> <target> --reason "..." [--expires 7d] [--force]
enodia-sentinel baseline revoke <kind> <target>
enodia-sentinel baseline list [--stale] [--json]
```
Baseline *reconciliation*: accept a specific, identified drift item with a
mandatory reason instead of silently folding it into a baseline. `<kind>` is one
of `fim`, `pkgfile`, `listener`, or `suid`; `<target>` is a path (FIM/package/
SUID) or a `port/comm` key (listener).
An acknowledgement suppresses that one alert **only while the live state still
matches the accepted fingerprint**. `fim` and `pkgfile` acks are content-bound:
when the file changes again the ack goes *stale* and the alert returns. `listener`
and `suid` acks are identity-bound, so only `--expires` (TTL) or an explicit
`revoke` retires them. Each record stores who accepted it, when, why, and the
fingerprint, in `log_dir/reconciliation.json` (override with `reconcile_store`).
- `accept` refuses to record drift it cannot observe live (e.g. a listener not
currently bound); pass `--force` to accept anyway — required for accepting a
*removed* file. Omitting `--reason` is a hard error.
- `--expires` accepts `Nd` / `Nh` / `Nm` (days/hours/minutes).
- `revoke` exits `1` if the target isn't present.
- `list` shows every ack; `--stale` filters to stale/expired ones. It exits `1`
whenever any acknowledgement is stale (a scriptable drift check) and re-derives
FIM staleness against live files.
Reconciled drift is dropped at the daemon detection chokepoint, hidden from
`fim-check`, and summarised in the dashboard integrity view, so an acknowledged
item stops alerting everywhere until its fingerprint changes or its TTL lapses.
## Detection and Integrity Commands
### `list-detectors`
```bash
enodia-sentinel list-detectors
```
Prints the poll detectors and whether each is enabled by config.
### `rules`
```bash
enodia-sentinel rules list
enodia-sentinel rules list --json
enodia-sentinel rules show <sid>
enodia-sentinel rules show <sid> --json
enodia-sentinel rules test <event-json>
enodia-sentinel rules test <event-json> --json
enodia-sentinel rules docs
```
Inspects and tests event-driven detection rules without reading source code.
`rules list` includes built-in exec/syscall rules plus configured exec rules
from `exec_rules_file`. `rules show <sid>` prints the rule metadata and match
conditions. `rules test <event-json>` loads an exec or syscall event JSON file,
runs the matching rule engine, and prints any alerts that would fire. Use `-`
instead of a path to read the event JSON from stdin. `rules docs` emits Markdown
rule documentation from the active rule metadata; the built-in snapshot lives in
[RULES.md](RULES.md).
Exec event JSON shape:
```json
{
"pid": 42,
"ppid": 1,
"uid": 1000,
"parent_comm": "nginx",
"filename": "/bin/sh",
"argv": ["-c", "id"]
}
```
Syscall event JSON shape:
```json
{
"pid": 42,
"ppid": 1,
"uid": 1000,
"comm": "payload",
"syscall": "mprotect",
"args": [0, 4096, 6, 0, 0, 0]
}
```
Exit code:
- `0`: list/show succeeded, or `rules test` matched at least one rule.
- `1`: unknown sid for `show`, or no rule matched for `test`.
- `2`: malformed sid, missing target, unreadable JSON, or unsupported event
shape.
### `rootcheck`
```bash
enodia-sentinel rootcheck
```
Runs anti-rootkit cross-view checks once:
- PIDs alive via `kill(pid, 0)` but missing from `/proc`.
- PIDs visible in `/proc` but missing from `ps`.
- Live modules in `/sys/module` but missing from `/proc/modules`.
- Listening TCP ports in `/proc/net/tcp*` but missing from `ss`.
- UDP ports in `/proc/net/udp*` but missing from `ss -u`.
- Raw and special-protocol sockets in `/proc/net` but missing from `ss`.
- Network interfaces in promiscuous mode.
- Known rootkit module names.
- Tainted loaded modules (`/sys/module/*/taint`) and global kernel taint
(`/proc/sys/kernel/tainted`).
Exit code:
- `0`: no rootcheck findings.
- `1`: one or more rootcheck alerts.
### `fim-baseline`
```bash
enodia-sentinel fim-baseline
```
Builds the SHA-256 file integrity baseline for configured critical paths plus
Sentinel's own footprint.
Use on a known-good host. The package hook also calls `fim-update` after normal
package transactions.
### `fim-update`
```bash
enodia-sentinel fim-update
```
Refreshes the FIM baseline. This exists primarily for the package manager hook.
Manual use should be treated as an acknowledgement that the current file state
is legitimate.
### `fim-check`
```bash
enodia-sentinel fim-check
enodia-sentinel fim-check --packages
```
Diffs current file state against the FIM baseline. With `--packages`, also runs
package-owned file verification through the package manager (`pacman -Qkk` on
Arch).
Exit code:
- `0`: no baseline changes.
- `1`: one or more added, removed, or modified files.
### `pkgdb-check`
```bash
enodia-sentinel pkgdb-check
```
Checks whether the local package database fingerprint changed outside a logged
package transaction. This catches an attacker rewriting stored package checksums
to hide a modified binary.
Exit code:
- `0`: package DB matches the anchor or was legitimately re-anchored.
- `1`: out-of-band DB tampering suspected.
### `pkgdb-verify`
```bash
enodia-sentinel pkgdb-verify
enodia-sentinel pkgdb-verify --sample 200
```
Compares on-disk package-owned files to SHA-256 hashes from `.MTREE` manifests
inside cached signed packages. This is independent of the mutable local package
database.
The command also flags insecure global `SigLevel` settings and warns if the
pacman keyring is missing.
Exit code:
- `0`: sampled files match and signature policy is not downgraded.
- `1`: a signed-package mismatch or insecure signature setting was found.
### `incident`
```bash
enodia-sentinel incident list [--json]
enodia-sentinel incident show <incident-id> [--json]
enodia-sentinel incident export <incident-id>
```
Groups related alerts into incidents so one intrusion reads as one story instead
of several disconnected alerts. Grouping is **process-lineage first** (alerts
sharing a PID or a common ancestor — the web server or SSH session they descend
from), with a **time-window fallback** for alerts that carry no live PID (FIM
drift, package tamper, hidden modules). Each captured snapshot records an
`incident_id`; the index lives in `incidents.json` under `log_dir`.
- `list` — incidents newest-first: id, last seen, severity, alert count, and the
signatures involved.
- `show <id>` — incident summary plus a time-ordered timeline of its member
snapshots (time, severity, signatures, PIDs, and the snapshot file to open).
- `export <id>` — a single JSON bundle of the incident record with every member
snapshot report inlined, suitable for handoff or offline analysis.
Tuning lives in config: `incident_window` (how long an incident stays open for
new alerts) and `incident_lineage_depth` (ancestors walked when correlating).
Exit code: `0` on success; `1` if the incident id is unknown; `2` if `show`/
`export` is called without an id.
### `posture check`
```bash
enodia-sentinel posture check
enodia-sentinel posture check --json
```
Audits host configuration hygiene — the conditions that make a host *easy* to
attack, as opposed to an attack in progress:
- SSH: root login, password authentication, and empty-password logins.
- sudo: passwordless (`NOPASSWD`) rules, disabled authentication, and
group/world-writable sudoers files.
- World-writable or non-root-owned `PATH` directories (binary-hijack vectors).
- Loose permissions on sensitive files (`/etc/shadow`, `/etc/passwd`, ...).
- Enabled systemd units with group/world-writable unit files, or whose
`ExecStart` binary runs from a writable/unsafe path (`/tmp`, `/dev/shm`,
`/var/tmp`, `/home`, `/run/user`) — a common persistence/hijack vector.
Shells out to `systemctl` with timeouts and fails closed on non-systemd
hosts; disable with `posture_systemd = false`.
- Downgraded package-signature policy (`SigLevel`).
Findings are advisory and reuse the standard alert JSON shape (`--json`). This
command does not run inside the daemon and never blocks startup.
Exit code:
- `0`: no posture findings.
- `1`: one or more findings.
## Evidence and Operator Commands
### `respond`
```bash
enodia-sentinel respond plan <incident-id>
enodia-sentinel respond plan <incident-id> --json
```
Builds a dry-run response plan from an incident's retained JSON snapshots. The
plan may include evidence preservation, process freeze/terminate candidates,
outbound IP blocks, systemd unit disablement, suspicious-file quarantine,
package-restore planning, and follow-up verification checks. Package restore
guidance stays explicit: identify the owner with `pacman -Qo`, verify signed
package-cache metadata with `pkgdb-verify`, reinstall the owner from trusted
package media, then re-run `fim-check --packages` and `fim-update` only after
operator review. Recovery checks stay read-only too: plans can ask the operator
to re-run `rootcheck`, confirm persistence alerts are gone with `check --json`,
and run `watchdog` from another host to prove the heartbeat/dashboard path is
visible.
This command is intentionally read-only: it prints commands for operator review
and never executes them. Each CLI-generated plan is also saved under
`<log_dir>/response-plans/`, and a compact JSONL audit record is appended to
`<log_dir>/response-audit.log` with the plan id, incident id, action count, and
saved path. The JSON schema is `enodia.response.plan.v1` and marks
`apply_supported: false` until an audited apply workflow exists. Dashboard/API
plan previews remain read-only and do not create new artifacts.
Exit code:
- `0`: plan generated.
- `1`: unknown incident id.
- `2`: missing incident id.
### `status`
```bash
enodia-sentinel status
enodia-sentinel status --json
```
Prints a local health and alert summary: daemon running state, heartbeat age and
staleness, total alerts with per-severity counts, last alert time, and eBPF
monitor state. `--json` emits the same data as the dashboard `/api/status`
endpoint, for cron/monitoring.
Stable JSON contracts are documented in [SCHEMAS.md](SCHEMAS.md). Current v1
IDs cover alert objects/snapshots, incident records/views/exports, status,
response plans, and response audit JSONL records.
Exit code:
- `0`: daemon is running and the heartbeat is fresh.
- `1`: daemon is down or the heartbeat is stale.
### `tui` / `enodia-sentinel-tui`
```bash
enodia-sentinel tui
enodia-sentinel-tui
```
Opens the stdlib curses terminal dashboard for SSH/tmux operators. It does not
require the optional tray dependencies and reads the same local state as the CLI:
daemon status, recent alert snapshots, incident index and timelines, posture
findings, integrity/watchdog state, event-rule metadata, event tail, and
read-only response-plan previews.
Keys:
- `1` / `2` / `3` / `4`: status, alerts, incidents, timelines.
- `5` / `6` / `7` / `8` / `9`: posture, integrity, rules, events, response plans.
- `j` / `k` or arrows: scroll.
- `r`: refresh.
- `/`: filter the current view.
- `:`: command mode.
- `Tab`: complete command names in command mode.
- `Ctrl-L`: redraw.
- `q`: quit.
Command mode supports `status`, `alerts`, `incidents`, `timeline`, `posture`,
`integrity`, `rules`, `events`, `response`, `help`, `refresh`,
`filter <text>`, `clear`, and `quit`.
### `web`
```bash
enodia-sentinel web
```
Starts the read-only dashboard. By default it binds to the Tailscale interface
when available and uses bearer-token authentication for non-loopback binds.
HTTPS is mandatory. If `web_tls_cert` / `web_tls_key` are not configured,
Sentinel creates a self-signed pair under `log_dir`; add a browser exception for
that certificate or replace it with a private/local CA certificate.
The console exposes incidents, alert snapshots, posture findings,
integrity/watchdog state, event-rule metadata, event tail, and dry-run response
plans. It remains read-only; response commands are displayed for review but not
executed from the browser. Dashboard settings are local to the browser and
include persistent themes: Console, Paper, Contrast, LGBTQ, Trans, Dracula,
Solarized Dark, Solarized Light, and Twilight. The theme registry and core
text/status contrast pairs are covered by the web test suite.
Expected use: `enodia-sentinel-web.service`.
### `enodia-sentinel-tray`
```bash
enodia-sentinel-tray
```
Launches the optional desktop system-tray applet (no subcommands). It is a GUI
frontend over the commands above: the menu opens the dashboard (starting
`enodia-sentinel-web.service` if needed), starts/stops/restarts
`enodia-sentinel.service` via `systemctl`, shows daemon status and alert counts
from `status --json`, and runs `check --json` on demand with the result shown
as a desktop notification. Requires the `[tray]` extra (`pystray`, `Pillow`);
the core agent stays dependency-free without it.
### `completion`
```bash
enodia-sentinel completion bash
enodia-sentinel completion zsh
```
Prints a shell completion script for the CLI. Example installs:
```bash
mkdir -p ~/.local/share/bash-completion/completions
enodia-sentinel completion bash > ~/.local/share/bash-completion/completions/enodia-sentinel
mkdir -p ~/.zfunc
enodia-sentinel completion zsh > ~/.zfunc/_enodia-sentinel
```
For zsh, ensure `~/.zfunc` is in `fpath` before `compinit`.
### `triage`
```bash
enodia-sentinel triage
```
Reads captured alert JSON snapshots and classifies distinct findings as likely
false positive or review-needed. It suggests config snippets for known benign
noise but never edits config automatically. Suggestions are TOML snippets and
include the source alert `sid` and `classtype` in comments for review/audit
context.
### `watchdog`
```bash
enodia-sentinel watchdog --url https://100.x.y.z:8787 --token <token> --max-age 120
enodia-sentinel watchdog --url https://100.x.y.z:8787 --token <token> --insecure-tls
```
Polls a remote dashboard and alerts if the sensor is down, unreachable, or has a
stale heartbeat. Run this from a separate host. Use `--insecure-tls` only for
the built-in self-signed certificate while you have no local/private CA trust
path. A watchdog on the same machine does not prove the protected host is alive.
Exit code:
- `0`: remote sensor is reachable and fresh.
- `1`: remote sensor is stale, down, or unreachable.
## Development Shortcuts
The Makefile wraps common local tasks:
```bash
make test
make check
make baseline
make web
make drill
```
`make install` installs a plain package directory plus a launcher wrapper. It
does not require pip or a virtualenv.
## Future Command Contracts
The roadmap reserves these command shapes:
```bash
enodia-sentinel respond apply <plan-id>
```
State-changing response commands should be introduced with stable JSON schemas,
audit logs, and tests before they are documented as supported.