tpm-enrol: pivot host enrolment to a Go binary, built out-of-VM

Replaces the shell/openssl-provider host enrolment (a35f2d6) with a static
Go + go-tpm binary, and moves BOTH host Go binaries out of the Packer VM.

fleet-enrol (files/enrol/, Go + go-tpm, no CGO):
  - talks to /dev/tpmrm0 DIRECTLY via transport.FromReadWriter(os.File) — no
    linuxtpm, so go-tpm is the only dep and there is NO tpm2-tools key-gen /
    openssl tpm2 provider / curl in the image (removes the biggest bench risk,
    the provider handle: key-ref).
  - ensures the ECDSA key @0x81010001, builds the CSR (crypto.Signer over the
    TPM key), POSTs CSR+context to the broker, shows the Plymouth fingerprint,
    polls /status, writes the leaf cert to NV 0x01800001.
  - tpmkey/ is an exported package so the TPM ceremony is tested against the
    go-tpm software simulator from a SEPARATE simtest/ module (CGO stays out of
    the shipped build). Transaction logic (mock broker) tested in-package.
  - deps pinned by go.sum (not vendored): the binary now builds on the CI
    runner, which has network — reproducible via pinned Go 1.26.4 + go.sum.

Out-of-VM build (decision): both fleet-enrol AND fleet-hostapi compile in the
CI "Build host Go binaries" step (Go 1.26.4, CGO off, -trimpath) and Packer
FILE-PROVISIONS the static binaries in. Dropped the in-VM `dnf install golang`
+ the 2d removal — the Rocky build image carries no Go toolchain / go-tpm tree.

Wiring:
  - tpm-enrol.sh: now a thin GATE (empty-NV check, pre-auth DHCP on en*,
    exec /usr/sbin/fleet-enrol, reboot-to-converge). module-setup.sh bundles the
    binary (asserted) + reverts the tpm2-openssl/curl installs.
  - diskless.pkr.hcl: file provisioners for both binaries; enrol installed to
    /usr/sbin before the initramfs build + fapolicyd-trusted; lsinitrd asserts
    fleet-enrol; dnf reverted to baseline (no tpm2-openssl/curl).
  - gitea-main-ci.yaml: Set up Go + build both binaries + run the simulator
    ceremony test, before packer validate.

TESTED here: transaction unit tests + the full TPM ceremony (key-gen -> persist
-> ECDSA sign -> CSR verify -> chunked NV write -> re-enrol) against the go-tpm
simulator. BENCH-VERIFY (real/swtpm, empty owner auth, pre-auth DHCP, Plymouth,
reboot-converge, prod HTTPS) tracked in docs/TODO.md #11.
This commit is contained in:
Audiobuzz
2026-07-02 09:55:54 +00:00
parent 8e1d40a30b
commit 6278f2847d
17 changed files with 1061 additions and 254 deletions
+16 -21
View File
@@ -7,12 +7,9 @@
check() {
require_binaries wpa_supplicant wpa_cli tpm2_nvread openssl || return 1
# Inline empty-NV enrolment (tpm-enrol.sh) needs the TPM key-gen + NV-write
# tools, curl (broker HTTP), and awk (JSON build). require them so a build
# that lacks tpm2-openssl / curl fails LOUDLY here rather than shipping a UKI
# that silently cannot enrol a fresh host.
require_binaries tpm2_createprimary tpm2_create tpm2_load tpm2_evictcontrol \
tpm2_nvdefine tpm2_nvwrite tpm2_readpublic curl awk || return 1
# First-boot ENROLMENT is the out-of-VM fleet-enrol Go binary (bundled in
# install()), which does key-gen/CSR/NV directly via go-tpm — so no tpm2-tools
# key-gen / openssl provider / curl are required in the initramfs here.
return 0
}
@@ -43,24 +40,22 @@ install() {
inst_multiple wpa_supplicant wpa_cli tpm2_nvread openssl ip setsid nmcli \
grep sed cut tr sha256sum sleep mkdir nvme
# Inline empty-NV enrolment (tpm-enrol.sh): TPM key-gen + NV-write tools, the
# EK read (device context), curl (broker HTTP), awk (JSON), wc, and reboot.
inst_multiple tpm2_createprimary tpm2_create tpm2_load tpm2_evictcontrol \
tpm2_nvdefine tpm2_nvundefine tpm2_nvwrite tpm2_readpublic \
tpm2_createek tpm2_flushcontext curl awk wc reboot systemctl
# TSS libraries that the tpm2 tools + the openssl tpm2 provider dlopen.
inst_libdir_file "libtss2-*"
# openssl tpm2 PROVIDER (tpm2-openssl): openssl req signs the CSR with the
# TPM key via `-provider tpm2 -key handle:0x…`. tpm2-tss alone is NOT enough
# — the provider .so is what exposes the handle: key ref. require_binaries
# can't see a provider, so assert the .so landed (else enrolment CSR fails).
inst_libdir_file "ossl-modules/tpm2.so"
if [ -z "$(find "${initdir}" -name 'tpm2.so' -path '*ossl-modules*' 2>/dev/null)" ]; then
derror "95dot1x-macsec: openssl tpm2 provider (ossl-modules/tpm2.so) missing — install tpm2-openssl"
# Inline empty-NV enrolment: the gate hook (tpm-enrol.sh) drives networking +
# reboot; the actual key-gen/CSR/broker/NV work is the out-of-VM fleet-enrol
# binary (Go + go-tpm, static — talks to /dev/tpmrm0 directly, no tpm2-tools /
# openssl provider / curl needed). reboot: the hook reboots to converge into
# the secure path after writing the cert to NV.
inst_multiple reboot
if [ -x /usr/sbin/fleet-enrol ]; then
inst_simple /usr/sbin/fleet-enrol /usr/sbin/fleet-enrol
else
derror "95dot1x-macsec: /usr/sbin/fleet-enrol missing — build it out-of-VM (CI 'Build host Go binaries') before the initramfs build"
return 1
fi
# TSS libraries that tpm2_nvread (secure-path NV read) dlopens.
inst_libdir_file "libtss2-*"
# Fleet-generic supplicant config + RADIUS CA
inst_simple /etc/dot1x/wpa_supplicant-dot1x.conf /etc/dot1x/wpa_supplicant-dot1x.conf
inst_simple /etc/dot1x/radius-ca.pem /etc/dot1x/radius-ca.pem