327 lines
9.2 KiB
Markdown
327 lines
9.2 KiB
Markdown
# Enodia Sentinel Command Reference
|
|
|
|
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 event monitoring, writes heartbeats,
|
|
runs detector sweeps, captures snapshots, and sends notifications.
|
|
|
|
Expected use: systemd, not an interactive shell.
|
|
|
|
### `check`
|
|
|
|
```bash
|
|
enodia-sentinel check
|
|
```
|
|
|
|
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.
|
|
|
|
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.
|
|
|
|
## Detection and Integrity Commands
|
|
|
|
### `list-detectors`
|
|
|
|
```bash
|
|
enodia-sentinel list-detectors
|
|
```
|
|
|
|
Prints the poll detectors and whether each is enabled by config.
|
|
|
|
### `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`, ...).
|
|
- 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 lookup, and follow-up verification checks.
|
|
|
|
This command is intentionally read-only: it prints commands for operator review
|
|
and never executes them. The JSON schema is `enodia.response.plan.v1` and marks
|
|
`apply_supported: false` until an audited apply workflow exists.
|
|
|
|
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.
|
|
|
|
Exit code:
|
|
|
|
- `0`: daemon is running and the heartbeat is fresh.
|
|
- `1`: daemon is down or the heartbeat is stale.
|
|
|
|
### `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, event tail,
|
|
and dry-run response plans. It remains read-only; response commands are displayed
|
|
for review but not executed from the browser.
|
|
|
|
Expected use: `enodia-sentinel-web.service`.
|
|
|
|
### `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.
|
|
|
|
### `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.
|