Rotating a host's AK¶
A host's attestation key (AK) is derived from a fixed TPM template, so it is normally stable across reboots for the life of the host. But a TPM owner-clear, a firmware change that re-derives the AK, or a precautionary rotation will change it — and once the AK changes, every attestation fails as UnenrolledOrMismatchedAk. rotate-ak re-binds the host to its new AK without a full re-enrollment, preserving the baseline you have painstakingly reviewed, the TLS pin, and the PCR replay state.
The Endorsement Key is what makes this safe: it does not change, so it is the continuity anchor that proves the new AK still lives in the same TPM you already trust.
rotate-ak is a high-consequence daemon action
Like enrollment, re-binding a host's attestation key is a normal daemon action: etminan-verifier op rotate-ak, authenticated by kernel peer-UID and authorised by RBAC (an operator within its host-group, or an admin). The daemon signs the rotation 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 rotate.
When to rotate vs. re-enroll¶
| Situation | Action |
|---|---|
| TPM owner-cleared; firmware update re-derived the AK; precautionary rotation | rotate-ak — same TPM, new AK, baseline preserved |
| The host's EK changed (TPM physically replaced, motherboard swap with a new TPM) | Full re-enroll — a different EK means a different TPM, no cryptographic continuity |
Only the agent's TLS keypair was regenerated (etminan-agent keygen-tls) |
rotate-tls — the transport cert, not the AK |
The dividing line is the EK. A different EK has no cryptographic continuity with the trust you established at enrollment, so it is a deliberate, human-confirmed re-enroll by design — rotate-ak refuses it rather than silently accepting a new TPM.
The command¶
You hold no signing key — the daemon authenticates you by UID, checks your role and scope, then signs and audits the rotation on your behalf.
| Flag | Required | Purpose |
|---|---|---|
<host> (positional) |
yes | The enrolled host whose AK changed. |
--reason <text> |
yes | Mandatory justification, folded into the signed rotation record the daemon writes. |
--ek-roots <dir> |
no | Also re-verify the manufacturer EK-cert chain, same as op enroll --ek-roots. |
No unsigned, unreasoned rotation is possible
op rotate-ak refuses without --reason, and the daemon refuses a caller whose UID is not an authorised operator/admin in scope. There is no code path that performs a rotation without a signature and a reason — this is a hard invariant across every rotation kind (op rotate-ak, op rotate-tls).
How it works¶
rotate-ak re-runs the same EK credential-activation ceremony as enrollment, but against the already-pinned EK. The EK fingerprint must still match; the new AK must prove it resides in that same TPM. Only then is the pinned AK replaced.
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 rotate-ak <host> --reason (via daemon)
Note over V: RBAC — operator (in-scope) or admin · daemon signs + audits
V->>A: Quote request (nonce) over pinned mTLS
A->>TPM: TPM2_Quote (new AK, fixed template)
TPM-->>A: signed attest + signature
A-->>V: quote + NEW AK public
V->>A: EK request
A->>TPM: read EK public
A-->>V: EK public
Note over V: EK fingerprint == the one pinned at enrollment?
alt EK differs
V-->>Op: REFUSE — different TPM, do a full re-enroll
else EK matches
Note over V: MakeCredential → challenge sealed to (EK, new AK Name)
V->>A: ActivateCredential(blob, secret)
A->>TPM: TPM2_ActivateCredential (needs EK + new AK in this TPM)
TPM-->>A: recovered secret
A-->>V: recovered secret
Note over V: recovered == challenge? else REFUSE (software AK)
V->>V: replace AK public + AK fingerprint<br/>PRESERVE baseline, TLS pin, cumulative PCR10, log offset
V->>V: sign canonical_ak_rotation_payload<br/>append action=ak_rotated to audit_log
V-->>Op: prints old + new AK fingerprint → confirm out of band
end
What changes and what is preserved¶
On success, rotate-ak replaces the host's ak_public_marshaled_hex and ak_fingerprint_sha256_hex, and advances the cumulative PCR 10 and log offset in lockstep with the fresh quote (exactly as a normal cycle does). It preserves:
- the approved baseline — you do not re-review anything,
- the TLS pin,
- the pinned EK (the continuity anchor, unchanged by definition).
The rotation is signed with canonical_ak_rotation_payload(host_id, old_fingerprint, new_fingerprint, reason) and appended to the hash-chained audit log as action="ak_rotated", recording both the old and new fingerprints, the signer, and the reason — so the full history of the rotation is immutable and independently verifiable by baseline verify-signatures.
What you see¶
Rotated attestation key for host 'web-01':
Old AK fingerprint (sha256): a1b2c3...
New AK fingerprint (sha256): 9f8e7d...
Proven to reside in the same TPM as the pinned EK (<ek-fingerprint>). TLS pin,
baseline, and PCR replay state are unchanged.
Signed by the daemon on behalf of operator:<label>. Reason: TPM cleared during motherboard swap
Confirm the new AK fingerprint out of band, the same discipline as enrollment — the residency proof establishes it's the same genuine TPM; the human step confirms nothing unexpected happened to the host in between.
Related¶
- Enrolling a host — the credential-activation ceremony
op rotate-akre-runs, and the EK that anchors it. - RBAC — the daemon roles that authorise
op rotate-ak. - Mutual TLS —
op rotate-tls, the transport-cert analogue. - Troubleshooting — diagnosing an
AK fingerprint mismatchfinding before deciding to rotate.