Every design decision below follows from one constraint: the monitored host must never be trusted to grade its own homework. This page walks through the trust boundary, the exact data that crosses it, the baseline/approval workflow, and the security properties that hold even if root on the monitored host is fully compromised. For full narrative detail and the phase-by-phase validation record, see the full design record.
A single host is never both agent and verifier. The verifier's entire trust value comes from being something the monitored host cannot reach, patch, or silence.
The verifier can be a laptop in a locked drawer. It never listens for inbound connections
from anything but its own enrolled agents (pinned by certificate fingerprint), and its own
identity is pinned back at the agent the moment enroll runs — a single
trust-on-first-use ceremony, confirmed out-of-band by a human, exactly like an SSH host key.
After that, a compromised host can go silent or refuse to answer, but it cannot forge a
validly signed quote, and it cannot reach the machine that would fire an alarm about it.
One quote cycle, initiated by the verifier on its own schedule (hourly by default) or on
demand via etminan-verifier check.
The prefix-matching replay (step 7–8) tolerates a log that grew slightly between the quote being taken and the log being read — background activity on a busy host, not tampering. Only the byte range that actually reproduces the signed digest is trusted; anything appended after that point reappears, correctly, in the next cycle's delta.
Nothing becomes trusted without an explicit, signed, reasoned operator action — including the very first baseline for a newly enrolled host.
--reason text is folded into the signed payload itself — it's tamper-evident, not a comment stored alongside an unrelated signature.
A first-time enrollment's initial measurements go through the same pipeline — they land as
pending candidates for a bulk, single signed approve, never auto-trusted. Every
approve/reject/exclude action, plus enroll and assign-profile,
is recorded in a self-contained, hash-chained audit log inside the baseline store: each
entry's hash covers the previous entry's hash, so altering, deleting, or reordering any past
row breaks every hash after it. baseline verify-signatures re-checks the whole
chain plus every operator signature on demand.
etminan-common is the only code shared by both binaries — deliberately
small, so the trust-sensitive parts of each binary stay easy to audit independently.
Listens for mTLS-authenticated requests from its verifier. Sweeps, quotes, relays — never judges.
No TPM, no inbound listener, and — as of tpm_wire.rs — no
TPM library dependency at all in the shipped binary. Polls, verifies, diffs, and is the
only place an alarm can fire from.
TPMS_ATTEST/TPMT_PUBLIC marshaling, replacing tss-esapi
as a build dependency (kept dev-only, for differential testing against the real
library) — restores clean musl cross-compilation.Shared by both binaries — nothing in here trusts the process it's linked into.
rustls, no CA chain.enroll's single
trust-on-first-use moment, confirmed out-of-band by a human, same model as an SSH host
key.TPM2_CreatePrimary —
deterministic from the TPM's own hierarchy seed, so no persistent key storage is needed
and the derived key never changes across reboots.--key and --reason, both folded
into the signed payload — a stored reason string with no signature over it would not be
tamper-evident.baseline.db — no
external tool, key, or network dependency required just to record that something
happened.plugin_exec.rs, never from a directory scan. Before every single
execution — never cached — the verifier confirms the plugin is listed by name in an
operator-maintained allowlist, is root-owned and not group/world-writable, and hashes to
the pinned SHA-256 on file, then executes that exact already-verified file descriptor via
/proc/self/fd/<n> rather than re-resolving the path a second time. A
broken plugin is never a silent failure — it surfaces as an ordinary warning-severity
finding through the same path as any other.Not every extension point should have the same cost to add — but every extension point should be honest about what it costs to add safely.
Package-ownership checks run inside etminan-agent itself.
Adding apk/pacman support is a new Rust impl plus one line in
a registry — no new trust boundary, since the agent already runs local, read-only
queries against package-manager state it already has access to.
Ticket-system correlation and alarm/notification channels are both a genuinely higher
trust decision — a plugin's output shapes what an operator believes, or where an alert
goes. Both are external, allowlisted, hash-pinned executables (any language) under one
shared contract (see the Plugin API doc): adding Request
Tracker, a ServiceNow-style system, or a new alert channel needs zero Rust code and no
verifier rebuild — just a script matching its category's input/output shape (argv for
change-source, JSON over stdin for notify) and an allowlist entry with its pinned hash.
One security core, plugin_exec.rs, backs every category.
This is the condensed version of the full narrative validation record, including the real-TPM/real-host Phase 0 findings.
| Area | State | Detail |
|---|---|---|
| Core attestation loop | validated | Signature, nonce, and PCR-replay checks proven against a real TPM and a real host across 30+ consecutive requests; tampered/replayed/unenrolled cases all correctly rejected. |
| Transport | shipped | Mandatory mutual TLS, pinned by fingerprint, live on every agent↔verifier connection. |
| Watched-path profiles | shipped | Named profiles plus a centralized, verifier-pushed profile registry — no hardcoded default for any deployment. |
| Change-source correlation | shipped | External plugin-process model; Request Tracker ships as the reference plugin. |
| Security hardening pass | shipped | A project-wide code audit closed a pre-auth denial-of-service in the agent's connection handling and added real test coverage to every previously-untested security-critical module. |
| Alarm channels | shipped | Email + the hash-chained audit log, plus PagerDuty/Slack/generic-webhook via the Etminan Plugin API; a broken plugin is checked every cycle rather than failing silently. |
| verifier cross-compilation | shipped | tpm_wire.rs replaced tss-esapi as a build dependency —
the verifier now cross-compiles cleanly to a static musl binary, with the real library
kept dev-only for differential testing. |
| mTLS key rotation | shipped | rotate-tls re-pins a host's TLS cert fingerprint after agent re-keying,
without a full re-enrollment, as long as the AK fingerprint still matches. |
| Production pilot | not started | Not yet run in parallel with a real host fleet through a full patch cycle. |