supply chain: verify signatures and pins across image + kernel builds
Three independent hardenings, addressing a review finding that the kernel and image build pipelines were relying on HTTPS alone for artifact integrity. scripts/make-generic-kernel.sh - Fetch the detached PGP signature (linux-<ver>.tar.sign) alongside the tarball and verify it with gpg before extraction. An isolated $GNUPGHOME under the tempdir keeps the kernel signers out of the invoking user's keyring. - Import the three kernel.org release signing keys (Greg KH / Linus / Sasha Levin) from keyserver.ubuntu.com, falling back to keys.openpgp.org. Ubuntu comes first because keys.openpgp.org strips unverified UIDs on upload, leaving gpg with UID-less keys it refuses to trust. - Require VALIDSIG (cryptographic proof) rather than GOODSIG (printed even for expired keys) before proceeding. Verified end-to-end against a clean tarball (accepts) and a byte-flipped tampered copy (rejects with BADSIG). - gpg + gpgv + xz added to the required-tools check. images/golden/Dockerfile - Pin Docker's apt signing key by fingerprint. After downloading /etc/apt/keyrings/docker.asc we gpg --show-keys --with-colons it, extract the fpr, and compare against the expected 9DC858229FC7DD38854AE2D88D81803C0EBFCD88. A tampered or swapped key aborts the build before any apt repo metadata is fetched. - Replace `curl https://mise.run | sh` with a pinned GitHub release binary (mise v2026.4.18, linux-x64) verified against its published sha256. Refuses to build on unknown architectures rather than silently installing a binary we have no hash for. - Add gnupg to the ESSENTIAL apt-get install so the fingerprint check has gpg available. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
011b59a72f
commit
25a1466947
2 changed files with 109 additions and 23 deletions
|
|
@ -44,18 +44,70 @@ while [[ $# -gt 0 ]]; do
|
|||
esac
|
||||
done
|
||||
|
||||
for tool in curl tar make gcc; do
|
||||
for tool in curl tar xz make gcc gpg gpgv; do
|
||||
command -v "$tool" >/dev/null 2>&1 || { log "missing required tool: $tool"; exit 1; }
|
||||
done
|
||||
[[ -f "$CONFIG" ]] || { log "config not found: $CONFIG"; exit 1; }
|
||||
|
||||
# kernel.org release signing keys. Stable (Greg KH) signs most point
|
||||
# releases; mainline (Linus) signs .0 drops; Sasha Levin sometimes
|
||||
# signs longterm backports. Listing all three keeps the script
|
||||
# working across every release channel the user might pick. Rotations
|
||||
# are rare and announced; update this list if gpg complains.
|
||||
#
|
||||
# Fingerprints verified against kernel.org:
|
||||
# https://www.kernel.org/signature.html
|
||||
KERNEL_SIGNING_KEYS=(
|
||||
647F28654894E3BD457199BE38DBBDC86092693E # Greg Kroah-Hartman
|
||||
ABAF11C65A2970B130ABE3C479BE3E4300411886 # Linus Torvalds
|
||||
E27E5D8A3403A2EF66873BBCDEA66FF797772CDC # Sasha Levin
|
||||
)
|
||||
|
||||
TARBALL="linux-${KERNEL_VERSION}.tar.xz"
|
||||
URL="https://cdn.kernel.org/pub/linux/kernel/v${KERNEL_MAJOR}.x/$TARBALL"
|
||||
SIGNATURE="linux-${KERNEL_VERSION}.tar.sign"
|
||||
BASE_URL="https://cdn.kernel.org/pub/linux/kernel/v${KERNEL_MAJOR}.x"
|
||||
SRC_DIR="$(mktemp -d)"
|
||||
trap 'rm -rf "$SRC_DIR"' EXIT
|
||||
|
||||
log "downloading kernel $KERNEL_VERSION from $URL"
|
||||
curl -fSL --progress-bar -o "$SRC_DIR/$TARBALL" "$URL"
|
||||
# Isolated GNUPGHOME so the verification step can't accidentally
|
||||
# trust whatever the invoking user already has in their keyring. The
|
||||
# trap above cleans the whole SRC_DIR, including this.
|
||||
GPG_HOME="$SRC_DIR/gnupg"
|
||||
install -d -m 0700 "$GPG_HOME"
|
||||
export GNUPGHOME="$GPG_HOME"
|
||||
|
||||
log "importing kernel.org signing keys"
|
||||
# keyserver.ubuntu.com first: it returns keys with user IDs intact,
|
||||
# which gpg needs to mark the key as usable. keys.openpgp.org (the
|
||||
# current SKS successor) strips unverified UIDs on upload, and the
|
||||
# kernel.org devs haven't all completed its email verification flow,
|
||||
# so pulling from there returns UID-less keys that gpg then refuses
|
||||
# to trust. We fall back to it anyway in case ubuntu is unreachable.
|
||||
if ! gpg --batch --keyserver hkps://keyserver.ubuntu.com --recv-keys "${KERNEL_SIGNING_KEYS[@]}" 2>/dev/null; then
|
||||
log "key fetch from keyserver.ubuntu.com failed; trying keys.openpgp.org"
|
||||
gpg --batch --keyserver hkps://keys.openpgp.org --recv-keys "${KERNEL_SIGNING_KEYS[@]}"
|
||||
fi
|
||||
|
||||
log "downloading kernel $KERNEL_VERSION from $BASE_URL/$TARBALL"
|
||||
curl -fSL --progress-bar -o "$SRC_DIR/$TARBALL" "$BASE_URL/$TARBALL"
|
||||
curl -fSL --progress-bar -o "$SRC_DIR/$SIGNATURE" "$BASE_URL/$SIGNATURE"
|
||||
|
||||
log "verifying signature"
|
||||
# The .tar.sign is a detached signature over the *uncompressed* tar,
|
||||
# per kernel.org convention. Pipe the xz-decompressed stream into
|
||||
# gpg --verify so we never materialise an unverified tarball on disk.
|
||||
# Require VALIDSIG (the cryptographic proof — GOODSIG alone is
|
||||
# printed even for expired/revoked keys, VALIDSIG requires a usable
|
||||
# key and a mathematically valid signature).
|
||||
VERIFY_STATUS="$SRC_DIR/verify.status"
|
||||
xz -cd "$SRC_DIR/$TARBALL" | gpg --batch --status-fd 3 --verify "$SRC_DIR/$SIGNATURE" - 3>"$VERIFY_STATUS" 2>/dev/null || true
|
||||
if ! grep -qE '^\[GNUPG:\] VALIDSIG' "$VERIFY_STATUS"; then
|
||||
log "signature verification FAILED — refusing to build"
|
||||
log "gpg status:"
|
||||
cat "$VERIFY_STATUS" >&2 || true
|
||||
exit 1
|
||||
fi
|
||||
log "signature OK (signed by $(awk '/^\[GNUPG:\] VALIDSIG/ {print $3}' "$VERIFY_STATUS"))"
|
||||
|
||||
log "extracting"
|
||||
tar -xf "$SRC_DIR/$TARBALL" -C "$SRC_DIR" --strip-components=1
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue