Skip to content

Enrolling a host

Enrollment is the single highest-consequence action in Etminan: it establishes trust-on-first-use for both a host's attestation key and its TLS certificate, proves that attestation key actually lives in a real TPM, and seeds the baseline every later cycle is judged against. This chapter walks the op enroll command end to end — the EK credential-activation challenge, the AK fingerprint you confirm out of band, and the first baseline approval with op approve.

Run it from the verifier, once per monitored host, after mTLS is set up on both ends (see Mutual TLS).

Enrollment is the highest-consequence daemon action

Because it is the trust-on-first-use moment, enrollment is the most consequential thing an operator does — but it is still a normal daemon action: etminan-verifier op enroll, authenticated by kernel peer-UID and authorised by RBAC (an operator may enrol hosts within its own group; an admin anywhere). The daemon signs the enrollment record on your behalf and flags it in the audit log. There is no --key and no root break-glass — that path was removed in 0.10.2; op is the only way to enrol. Everything after enrollment — starting with the first baseline approval — is the same daily daemon flow.

The command

etminan-verifier op enroll web-01 --addr 10.0.0.5:7620 \
  --reason "onboarding web-01"

You hold no signing key — the daemon authenticates you by UID, checks your role and scope, then signs and audits the enrollment on your behalf.

Flag Required Purpose
<host> (positional) yes The identifier this host is known by from now on.
--addr <ip:port> yes Where the agent is listening for quote requests.
--reason <text> yes Folded into the signed enrollment record the daemon writes; tamper-evident, not just a log string.
--ek-roots <dir> no Additionally require a manufacturer EK certificate chaining to a root CA in <dir> (hardware-only mode).
--force no Re-enroll a host that is already enrolled, discarding its pinned AK/TLS identity. Only after re-confirming the AK fingerprint out of band.

enroll refuses to silently re-enroll

Without --force, enroll refuses a host that is already enrolled. Re-running it — a fat-fingered command, a re-run provisioning script — would otherwise discard the pinned AK fingerprint, TLS cert, cumulative PCR 10, and log offset and re-establish trust-on-first-use, accepting whatever key the host now presents: exactly first contact, the highest-risk moment, on a host that may since have been compromised. Use --force only when you are deliberately re-provisioning and have re-confirmed the new AK fingerprint out of band, exactly as for a first enrollment.

What enroll actually does

Enrollment is not just "take a quote and trust it." It runs the full verify::check validation on that first quote, then adds a residency proof (EK credential activation) that the AK lives in a genuine TPM, and only then pins anything.

sequenceDiagram
    autonumber
    participant Op as Operator
    participant V as etminan-verifier
    participant A as etminan-agent
    participant TPM as Host TPM 2.0

    Op->>V: op enroll <host> --addr --reason (via daemon)
    Note over V: RBAC — operator (in-scope) or admin · daemon signs + audits
    V->>A: Quote request (nonce), TLS trust-on-first-use
    A->>TPM: TPM2_Quote (fixed AK template)
    TPM-->>A: signed attest + signature
    A-->>V: quote + AK public + IMA log · capture agent TLS cert fingerprint
    Note over V: verify::check — signature, nonce, PCR10, replay<br/>(Genuine or CatchingUp accepted · anything else refuses)
    V->>A: EK request (pinned to captured TLS cert)
    A->>TPM: read EK public (+ EK cert from NV, if any)
    A-->>V: EK public (+ EK cert DER, or none)
    Note over V: MakeCredential: seal random challenge to (EK public, AK Name)<br/>— pure software, no TPM on the verifier
    V->>A: ActivateCredential(credential_blob, secret)
    A->>TPM: TPM2_ActivateCredential (needs both EK and AK in this TPM)
    TPM-->>A: recovered secret
    A-->>V: recovered secret
    Note over V: recovered == challenge? if not, REFUSE (software AK)
    V->>V: pin AK fingerprint + EK fingerprint + TLS fingerprint<br/>sign + audit the enrollment record
    V-->>Op: prints AK fingerprint → confirm OUT OF BAND
    Op->>V: baseline review / op approve host (first baseline, daemon)

1. First quote, fully validated

Enroll takes a first quote and runs it through the exact same signature / nonce / PCR-selection / IMA-replay validation as a normal check, but with an all-zero starting PCR 10 (this quote establishes the baseline; it isn't compared to a prior one). A malformed or self-inconsistent first quote refuses enrollment rather than seeding a bad baseline. Only Genuine or CatchingUp is accepted — CatchingUp is legitimate here because a host that has been up a while has a boot-to-now IMA log far larger than one delta, so the first replay from offset 0 can't reach the signed PCR in a single chunk; it settles over the next few cycles.

The agent's TLS certificate fingerprint is captured on this very first (trust-on-first-use) connection and pinned; every follow-up connection in the ceremony is pinned to it, binding the whole thing to one agent identity.

2. EK credential activation — proving it's a real TPM

The quote above proves someone holds the AK's private key and that its public matches Etminan's fixed AK template. It does not prove that key lives in a real TPM — a compromised host could sign the attest bytes in software with a key of the right shape. Credential activation closes that gap at TOFU's weakest moment:

  1. The verifier fetches the host's EK public (and its manufacturer EK certificate from TPM NV, if provisioned — usually absent on vTPM/swtpm).
  2. The verifier seals a random 32-byte challenge to (EK public, AK Name) via software MakeCredential — pure public-key math, no TPM needed on the verifier.
  3. The agent runs TPM2_ActivateCredential. Only a TPM that holds both that EK and an AK of exactly that Name can recover the secret. It recreates the AK from the same fixed template (quote::ak_public_template) so the key it proves residency of is byte-identical to the one that signs quotes.
  4. If the recovered secret doesn't equal the challenge, enrollment is refused — the AK is not TPM-resident.

The EK's SHA-256 fingerprint is recorded as the host's stable per-TPM continuity anchor. It is what makes rotate-ak possible later: a new AK inside the same EK is a rotation; a different EK is a different TPM and a deliberate re-enroll.

The fixed AK template matters

The AK is created via TPM2_CreatePrimary from a fixed, never-changing template — not the non-deterministic EK-child pattern. The template is what makes the AK reproducible across reboots with no persistent key storage, and it is why the fingerprint the verifier pins at enrollment keeps matching every cycle afterward. Changing the template would change the derived key and break the enrollment fingerprint match.

3. Optional: require genuine manufacturer hardware

Credential activation proves the AK and EK share a TPM, but not that that TPM is real silicon rather than an emulator. On discrete hardware, add --ek-roots <dir> to additionally require a manufacturer EK certificate (read from TPM NV) whose key matches the activated EK and which chains, by signature, to a self-signed manufacturer root CA in <dir>:

etminan-verifier op enroll web-01 --addr 10.0.0.5:7620 \
  --reason "onboarding web-01" \
  --ek-roots /etc/etminan-verifier/ek-roots/

Put the vendor's root and intermediate CA certs (PEM or DER) in that directory. With the flag, a host whose TPM ships no EK certificate (typical for vTPMs and swtpm) is refused — it is a deliberate hardware-only mode. The verified certificate's fingerprint is folded into the signed enrollment record. Honest scope: RSA manufacturer CAs only (an ECDSA issuer is rejected with a clear error), and there is no CRL/OCSP revocation checking yet.

4. Confirm the fingerprint out of band

Enroll prints the AK fingerprint it pinned. Confirm it out of band — read it off the host's console, compare it to what your provisioning system recorded — before trusting the enrollment. The residency proof establishes it's a genuine TPM; this human step confirms it's the right host's TPM, exactly as you would confirm an SSH host key on first connect.

Seeding the first baseline

Every measurement from that first quote is recorded as a pending candidate, not auto-trusted. The first approval is already the operator's normal daily action — the daemon signs it on your behalf; no root, no key file:

etminan-verifier baseline review --host web-01
etminan-verifier op approve web-01

Everything shows as new — that's expected

Right after enrollment, every entry in baseline review shows (new file, no prior baseline). There is no baseline yet, so nothing can look like a modification. This is the one moment a single bulk op approve web-01 covering everything is normal. From the next hourly run onward, approvals should be small and specific to what actually changed — see Baseline review.

  • The attestation loop — what happens every cycle after enrollment.
  • Baseline review — approving the first baseline and every change after.
  • Rotating a host's AK — re-binding the AK inside the same TPM without a full re-enroll.
  • RBAC — the daemon roles that gate the daily flow enrollment hands off to.
  • Mutual TLS — the pinning enrollment relies on.