Add tamper-evidence: package-DB integrity, self-integrity, dead-man's switch

Answers two hard questions: "what guards the hashes FIM trusts?" and "how do we
make the sensor itself hard to silently disable?" — within the honest limit that
a root attacker who shares your privileges can't be fully stopped on-box, only
made loud.

- pkgdb.py: guards the package DB that `pacman -Qkk` trusts. Anchors a
  fingerprint of /var/lib/pacman/local (refreshed ONLY by the pacman hook) and
  cross-checks pacman.log; a DB change with no logged transaction is flagged
  pkgdb_tamper (CRITICAL, sid 100021) — catches an attacker rewriting a stored
  checksum to mask a modified binary. Verified end-to-end against a simulated
  hash-overwrite.
- selfprotect.py: Sentinel's own binaries/config/units/hook are always in the
  FIM watch set (self-integrity); a heartbeat is written each loop; an external
  `watchdog` command polls a remote dashboard and pushes if the sensor goes
  silent or unreachable — silence becomes the alarm.
- daemon: heartbeat + slow-cadence pkgdb check; DB anchor re-anchored in
  build_fim_baseline so the pacman hook refreshes it after each transaction
- web: /api/status now reports heartbeat_age/stale; dashboard shows it
- cli: pkgdb-check, watchdog (--url/--token/--max-age, bypasses min-severity)
- config: pkgdb_verify/_interval, heartbeat_max_age
- README: threat model (trust-anchor problem) + hardening layers (immutability,
  signed-package + external anchor); reframes "anti-rootkit" as tamper-evidence
- tests: +8 (DB fingerprint, anchor/transaction logic, pacman.log parse,
  heartbeat + watchdog verdicts). 80/80 pass

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Luna 2026-05-31 22:27:50 -07:00
parent 5d577b624f
commit 34bc09041a
13 changed files with 465 additions and 9 deletions

View file

@ -239,6 +239,52 @@ notify_ntfy_url = "https://ntfy.sh"
notify_ntfy_topic = "enodia-7Hq2x" # keep this secret — it's the access control
```
## Tamper-evidence & self-protection
An attacker's first move against a sensor is to disable or blind it — and on a
box where they have root, *any* purely-local defense is ultimately defeatable
(they share your privileges). Sentinel doesn't pretend otherwise. The goal is to
make tampering **evident** by anchoring trust where the attacker has less
control, and to make going silent *loud*.
**Package-DB integrity.** `pacman -Qkk` trusts the local package database — so a
root attacker can modify `/usr/bin/ssh` *and* rewrite its stored checksum, and
verification passes. Sentinel guards the DB itself: a legitimate change only
happens during a logged transaction, so it anchors a fingerprint of
`/var/lib/pacman/local` (refreshed *only* by the pacman hook) and cross-checks
`pacman.log`. A DB change with **no corresponding transaction** is flagged
`pkgdb_tamper` (CRITICAL, `sid 100021`) — directly catching the "overwrite the
hashes" attack.
**Self-integrity.** Sentinel's own binaries, config, systemd units, and pacman
hook are always in the FIM watch set, so tampering with the watchdog trips the
watchdog.
**Dead-man's switch.** The daemon writes a heartbeat every loop; the dashboard
exposes its age. Run an external watcher on another host (over Tailscale) and
*silence becomes the alarm*:
```bash
# on a SEPARATE machine — alerts you if the sensor or the whole box goes dark
enodia-sentinel watchdog --url http://100.x.x.x:8787 --token <T> --max-age 120
```
**Hardening (the layers beyond on-box detection):**
1. **Immutability**`chattr +i` Sentinel's binaries, config, baselines, and
the pacman hook so even root must visibly clear the flag first.
2. **Cryptographic anchor (next)** — verify files against the *signed* package
in the cache rather than the mutable DB; a maintainer's PGP signature is a
root of trust the attacker doesn't hold.
3. **External anchor (next)** — mirror the DB/FIM fingerprints off-box so a
local attacker can't refresh the anchor to cover their tracks.
> On "anti-rootkit": the robust version isn't stealth (fragile, and a genuine
> dual-use rootkit technique) — it's tamper-*evidence*. Don't hide; be
> un-hideable. The durable defenses move the trust anchor below or outside the
> attacker: signatures, external monitors, and ultimately the kernel (the eBPF
> roadmap) rather than userland the attacker can rewrite.
## File integrity monitoring (Tripwire-style)
Detects tampering with binaries and critical configs by **content hash**, so it
@ -349,6 +395,10 @@ regression suite for both.
## Project status
v0.6 — adds **tamper-evidence**: out-of-band package-DB integrity
(catches rewritten checksums), self-integrity of Sentinel's own footprint, and a
dead-man's-switch heartbeat with an external watchdog.
v0.5 — adds **file integrity monitoring** (SHA-256 baseline + `pacman -Qkk`
verification, auto-refreshed by a pacman hook) and **false-positive triage**
via package-ownership provenance.