Rendered from innerwall v0.4.1ADR-0004

Token-gated enrollment, URI SAN identity, embedded CA behind an interface

Status
Accepted

Context

The only hard identity problem is the first certificate. Trust-on-first-use (accept whoever connects first, alert on change) has no trust story at registration: during the open window, anyone reachable can enroll as anything, receive policy, and learn topology — unacceptable for a system that enforces and whose policy discloses network structure. Long-lived baked-in secrets are worse. After first issuance, everything is routine mTLS rotation.

Decision

  • Enrollment policies define constraints (allowed labels, expiry, revocation); join tokens (provisioning tokens) are minted from them and passed to the installer. A token may enroll many workloads within its scope.
  • Bootstrap: agent generates its keypair locally (private key never leaves the host) → CSR + token + host metadata over server-authenticated TLS → control plane validates, signs with short TTL, returns cert + chain → the token's use is recorded.
  • Certificates carry exactly one URI SAN, innerwall://workload/<uuid>, with the UUID assigned by the control plane (form fixed by ADR-0016). Mutable attributes (hostname, labels) stay in the registry. Cert = authentication; registry = authorization.
  • Short TTLs (24h by default), renewal in the last third of lifetime, jittered, by authenticated re-CSR. Revocation machinery is replaced by short TTLs and token revocation: a credential lapses within a day, and a revoked token enrolls nothing further. Missed renewal ⇒ a late renewal, renewal only, within a bounded grace after expiry; beyond the grace ⇒ re-enrollment with a new token (ADR-0016 as amended). (Amended 2026-10-06 and 2026-10-14; see Amendments.)
  • The CA is embedded in the control plane for v1, behind a CertificateAuthority interface so external issuers (secret-management or CA services, KMS/HSM-backed signing) can replace it without touching enrollment.
  • Designed-for edge cases: clock skew (bounded notBefore backdating). Two further controls are named for version 2 and are not in version 1: a control-plane deny-list of workload identities, for locking out an enrolled workload before its credential expires, and duplicate-identity detection on connect with forced re-enrollment, for cloned images. Until they land, a second stream for one identity supersedes the first on the replica that holds it. (Amended 2026-10-06; see Amendments.)

Consequences

  • Enrollment trust anchors in an operator-generated, scoped, expiring secret — auditable and revocable pre-use.
  • Short TTLs make agent renewal a hot path; the CA endpoint is availability-critical for renewals (fail-static covers enforcement regardless — ADR-0011).
  • The interface commits us to keeping enrollment logic CA-agnostic.

Amendments

Amendment2026-09-13

(PR #5). ADR-0016 implements this record's identity semantics at the signing boundary (the exact URI form, the signing-request rule, the listener boundary, and the token as the carrier of enrollment-policy constraints); it does not supersede this record, and the earlier Superseded by ADR-0016 status line is corrected.

Amendment2026-09-13

(PR #5): body corrected to ADR-0016's forms. Three decision bullets stated details that the implementation fixed differently and that ADR-0016 records: the URI SAN is innerwall://workload/<uuid>, one per certificate, and the other project's naming that the original bullet and title borrowed is removed outright per the vocabulary rule; renewal happens in the last third of lifetime, jittered, not at half; tokens are reusable within their scope with a use recorded, not burned or decremented, and enrollment policy constraints are labels, expiry, and revocation. The core decision, token-gated enrollment with no trust-on-first-use window, a control-plane-assigned identity in a URI SAN, short-lived credentials, and a signing authority behind an interface, stands. Prior text is in git history.

Amendment2026-10-06

(PR #25, conformance-audit absorption). The core decision stands: token-gated enrollment with no trust-on-first-use window, a control-plane-assigned identity in a URI SAN, short-lived credentials, a signing authority behind an interface. Two controls the decision described as present were never built and are corrected in place to say what ships: the revocation story in version 1 is short-lived credentials and token revocation, and the deny-list of workload identities and duplicate-identity detection with forced re-enrollment are named version 2 controls. A missed renewal re-enrolls with a new token; the "configurable" automatic re-enrollment never existed. ADR-0016, ARCHITECTURE.md, and SECURITY.md say the same.

Amendment2026-10-14

(PR #102, issue #93). The short-TTL bullet said a missed renewal means re-enrollment with a new token; that is now true only beyond a bounded renewal grace. Within the grace an expired credential may renew, and do nothing else, so an outage of the control plane spanning the renewal window no longer strands the fleet. The bullet is corrected in place. The core decision stands, short-lived credentials included: the lifetime is unchanged, and a credential that has lapsed authenticates nothing but its own renewal. ADR-0016 as amended carries the detail.