Three features, all zero-toggle and principle-clean (single static musl
binary, container-first, no test certs, no client trust-store changes).
Secure Boot via signed shim+GRUB (automatic):
- The v0.6.1 escalation ladder gains a third rung: Firmware -> Builtin
-> Shim. Secure-Boot firmware downloads our unsigned iPXE but refuses
to execute it — indistinguishable from a failed chainload — so after
two unconfirmed attempts the MAC is offered Fedora's Microsoft-signed
shimx64.efi, which loads the signed GRUB, which fetches a
server-rendered grub.cfg. Fully signed chain, SB stays on.
- scripts/fetch-shim.sh pulls shim-x64/grub2-efi-x64 (+aa64 best-effort)
from the official Fedora 43 packages and ships the EFI binaries
byte-for-byte unmodified; Dockerfile fetch stage gained rpm2cpio/cpio.
- New grub_script renderer (Linux kernel entries only — signed GRUB only
boots signed kernels; sanboot/wimboot have no signed equivalent and
are omitted with an explanatory menu line).
- TFTP server gains a DynamicAsset hook for server-rendered names
(grub.cfg); HTTP serves the same config under /ipxe/grub.cfg for
native UEFI HTTP Boot chains. Arch-aware fallback walks back down the
ladder where no shim exists (BIOS, IA32).
Boot rules + decision webhook (open 'Matrix Boot'):
- Ordered first-match-wins rules over MAC prefix + client arch (the DHCP
proxy now bakes arch into the boot.ipxe chain URL), generalizing
per-MAC pins. Persisted to boot_rules.json; GET/PUT /api/boot-rules;
rules editor + webhook field on the Hosts tab.
- Optional pixiecore-style webhook: unmatched boots GET
<url>?mac=&arch= and 200 {"target":"id"} chains to it. Fail-open
with a 2s budget — a dead endpoint can never block PXE.
- Decision order: exact pin -> rules -> webhook -> menu. Empty config
is byte-for-byte the previous behavior.
Tokenized answer files (the post-WDS/CVE-2026-0386 hardening):
- Every generated unattended URL (inst.ks / preseed url / autoinstall
seed) now carries a 4h boot-scoped token; /unattended/{id} and the
cloud-init seed routes require it (or an operator session) once an
admin exists. Stops answer-file credential harvesting by anything
else on the network. No toggle; setup-mode installs stay open.
Validation: clippy clean, fmt clean, 290 workspace tests green
(+18 new across boot_tokens, boot_rules, arch ladder, escalation,
grub renderer, and four new full-flow integration tests).
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
97 lines
3.9 KiB
Bash
Executable File
97 lines
3.9 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Fetch Fedora's Microsoft-signed Secure Boot chain — shim + GRUB — and
|
|
# place the EFI binaries under assets/ipxe/ with the filenames OpenPXE's
|
|
# DriverMode::Shim mapping expects:
|
|
#
|
|
# shimx64.efi x86_64: Microsoft-signed shim (first stage)
|
|
# grubx64.efi x86_64: Fedora-signed GRUB (loaded by shim, fetches
|
|
# the server-rendered grub.cfg over TFTP/HTTP)
|
|
# shimaa64.efi arm64 equivalents (best-effort — see below)
|
|
# grubaa64.efi
|
|
#
|
|
# Why Fedora: a supply-chain decision made deliberately (v0.7.0) — one
|
|
# vendor, fast security turnaround, and the same chain most netboot
|
|
# projects redistribute. The binaries are extracted from the official
|
|
# distro RPMs and shipped BYTE-FOR-BYTE UNMODIFIED; their signatures are
|
|
# what make the chain work, and modifying them would break it. This is
|
|
# the standard documented netboot path for Secure Boot (Red Hat
|
|
# Satellite, SUSE HTTPBoot) and involves no test certificates and no
|
|
# client trust-store changes.
|
|
#
|
|
# Trust model matches fetch-ipxe.sh: HTTPS to the official distribution
|
|
# point, no sha pinning because we track the latest signed build (which
|
|
# rotates on SBAT revocations — pinning would mean shipping revoked
|
|
# shims). Mirror to your own artifact store for deterministic builds.
|
|
|
|
set -euo pipefail
|
|
|
|
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
|
DEST="${1:-$ROOT/assets/ipxe}"
|
|
mkdir -p "$DEST"
|
|
|
|
FEDORA_RELEASE="${FEDORA_RELEASE:-43}"
|
|
BASE="${FEDORA_MIRROR:-https://dl.fedoraproject.org/pub/fedora/linux/releases/$FEDORA_RELEASE/Everything}"
|
|
|
|
WORK="$(mktemp -d)"
|
|
trap 'rm -rf "$WORK"' EXIT
|
|
|
|
# Find the newest RPM in a repo directory whose name starts with
|
|
# `$pattern` followed by a version digit (anchoring on the digit keeps
|
|
# `grub2-efi-x64` from matching `grub2-efi-x64-cdboot`).
|
|
latest_rpm() {
|
|
local dir_url="$1" pattern="$2"
|
|
curl -fsSL "$dir_url/" \
|
|
| grep -oE "href=\"${pattern}-[0-9][^\"]*\.rpm\"" \
|
|
| sed 's/^href="//; s/"$//' \
|
|
| sort -V | tail -1
|
|
}
|
|
|
|
# fetch_chain <repo-arch> <shim-pkg> <grub-pkg> <shim-out> <grub-out> <hard|soft>
|
|
fetch_chain() {
|
|
local arch="$1" shim_pkg="$2" grub_pkg="$3" shim_out="$4" grub_out="$5" mode="$6"
|
|
local pkg_base="$BASE/$arch/os/Packages"
|
|
local sdir="$pkg_base/${shim_pkg:0:1}" gdir="$pkg_base/${grub_pkg:0:1}"
|
|
|
|
local shim_rpm grub_rpm
|
|
shim_rpm="$(latest_rpm "$sdir" "$shim_pkg" || true)"
|
|
grub_rpm="$(latest_rpm "$gdir" "$grub_pkg" || true)"
|
|
if [ -z "$shim_rpm" ] || [ -z "$grub_rpm" ]; then
|
|
echo "!! could not locate $shim_pkg/$grub_pkg RPMs under $pkg_base"
|
|
[ "$mode" = "hard" ] && exit 2
|
|
echo " skipping $arch Secure Boot chain (best-effort)"
|
|
return 0
|
|
fi
|
|
|
|
echo ">> $arch: $shim_rpm + $grub_rpm"
|
|
local exdir="$WORK/$arch"
|
|
mkdir -p "$exdir"
|
|
curl -fsSL -o "$exdir/shim.rpm" "$sdir/$shim_rpm"
|
|
curl -fsSL -o "$exdir/grub.rpm" "$gdir/$grub_rpm"
|
|
( cd "$exdir" \
|
|
&& rpm2cpio shim.rpm | cpio -idm --quiet "./boot/efi/EFI/*/$shim_out" \
|
|
&& rpm2cpio grub.rpm | cpio -idm --quiet "./boot/efi/EFI/*/$grub_out" )
|
|
|
|
local shim_path grub_path
|
|
shim_path="$(find "$exdir/boot" -name "$shim_out" | head -1)"
|
|
grub_path="$(find "$exdir/boot" -name "$grub_out" | head -1)"
|
|
if [ -z "$shim_path" ] || [ -z "$grub_path" ]; then
|
|
echo "!! RPM layout changed — $shim_out/$grub_out not found inside the packages"
|
|
[ "$mode" = "hard" ] && exit 2
|
|
return 0
|
|
fi
|
|
cp "$shim_path" "$DEST/$shim_out"
|
|
cp "$grub_path" "$DEST/$grub_out"
|
|
echo " installed $shim_out + $grub_out"
|
|
}
|
|
|
|
# x86_64 is the headline Secure Boot audience — fail the build if it
|
|
# can't be assembled so a regression is loud, not silent.
|
|
fetch_chain x86_64 shim-x64 grub2-efi-x64 shimx64.efi grubx64.efi hard
|
|
# arm64 is best-effort: skipping just means no Shim escalation rung for
|
|
# that arch (logged at startup by ipxe-assets::log_availability).
|
|
fetch_chain aarch64 shim-aa64 grub2-efi-aa64 shimaa64.efi grubaa64.efi soft
|
|
|
|
echo
|
|
echo "Secure Boot chain assets now in $DEST:"
|
|
ls -lh "$DEST"/shim*.efi "$DEST"/grub*.efi 2>/dev/null || true
|