Initial commit
This commit is contained in:
@@ -0,0 +1,204 @@
|
||||
# =============================================================================
|
||||
# Diskless fleet image build
|
||||
#
|
||||
# Builds a RHEL9-family root filesystem + fleet-generic initramfs for
|
||||
# PXE/HTTP-booted diskless hosts authenticating with 802.1X EAP-TLS
|
||||
# (TPM-held key, cert in TPM NV) and MACsec link encryption.
|
||||
# Root filesystem: erofs + dm-verity over a shared read-only NVMe/TCP
|
||||
# namespace, with a tmpfs overlay for runtime state.
|
||||
#
|
||||
# Outputs:
|
||||
# ${var.artifact_dir}/${var.image_version}/
|
||||
# vmlinuz, initramfs.img - intermediate (consumed by ukify)
|
||||
# fleet-<version>.efi - signed UKI (kernel+initramfs+cmdline+roothash)
|
||||
# rootfs.erofs - erofs + appended verity tree -> nvmet RO namespace
|
||||
# verity.json, cmdline.txt, SHA256SUMS
|
||||
# OCI image ${var.oci_image}:${var.image_version} (FROM scratch)
|
||||
# /artifacts/{fleet-<version>.efi, rootfs.erofs, verity.json, SHA256SUMS}
|
||||
# = the atomic fleet release unit; deploy as initContainer / image volume
|
||||
# feeding the SPDK + HTTPS serving containers, pinned by digest.
|
||||
#
|
||||
# Usage:
|
||||
# packer init .
|
||||
# packer build -var iso_url=... -var iso_checksum=... .
|
||||
# =============================================================================
|
||||
|
||||
packer {
|
||||
required_version = ">= 1.10.0"
|
||||
required_plugins {
|
||||
qemu = {
|
||||
source = "github.com/hashicorp/qemu"
|
||||
version = ">= 1.1.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------ variables
|
||||
|
||||
variable "iso_url" {
|
||||
type = string
|
||||
description = "RHEL 9 / Rocky 9 / Alma 9 DVD ISO URL or local path"
|
||||
default = "https://download.rockylinux.org/pub/rocky/9/isos/x86_64/Rocky-9-latest-x86_64-dvd.iso"
|
||||
}
|
||||
|
||||
variable "iso_checksum" {
|
||||
type = string
|
||||
description = "ISO checksum, e.g. file:.../CHECKSUM or sha256:<hex>"
|
||||
default = "file:https://download.rockylinux.org/pub/rocky/9/isos/x86_64/CHECKSUM"
|
||||
}
|
||||
|
||||
variable "image_version" {
|
||||
type = string
|
||||
description = "Version stamp for the published artifact directory"
|
||||
default = "0.1.0"
|
||||
}
|
||||
|
||||
variable "artifact_dir" {
|
||||
type = string
|
||||
description = "Where extracted boot artifacts and rootfs tar are written"
|
||||
default = "artifacts"
|
||||
}
|
||||
|
||||
variable "nic_drivers" {
|
||||
type = string
|
||||
description = "Kernel modules for the fleet's real NICs (build VM only has virtio!)"
|
||||
default = "igb igc ixgbe i40e ice mlx5_core"
|
||||
}
|
||||
|
||||
variable "build_password" {
|
||||
type = string
|
||||
description = "Throwaway root password used only during the Packer build (must match http/ks.cfg)"
|
||||
default = "packer-build-only"
|
||||
sensitive = true
|
||||
}
|
||||
|
||||
variable "oci_image" {
|
||||
type = string
|
||||
description = "OCI image ref for the release-artifact image (FROM scratch, holds UKI + rootfs.erofs)"
|
||||
default = "registry.example.org/fleet-boot"
|
||||
}
|
||||
|
||||
variable "oci_push" {
|
||||
type = bool
|
||||
description = "Push the release-artifact image to the registry after building"
|
||||
default = false
|
||||
}
|
||||
|
||||
variable "disable_dot1x" {
|
||||
type = bool
|
||||
description = "TEST ONLY: bake rd.dot1x=0 into the UKI cmdline so the host boots with 802.1X + MACsec disabled (open-port NVMe-oF boot test). Leave false for any real/secure build."
|
||||
default = false
|
||||
}
|
||||
|
||||
variable "sb_key" {
|
||||
type = string
|
||||
description = "Secure Boot signing key (PEM) for the UKI. Empty = unsigned lab build. Production: CI/HSM-held; never enters the build VM."
|
||||
default = ""
|
||||
sensitive = true
|
||||
}
|
||||
|
||||
variable "sb_cert" {
|
||||
type = string
|
||||
description = "Secure Boot signing certificate (PEM) matching sb_key"
|
||||
default = ""
|
||||
}
|
||||
|
||||
# --------------------------------------------------------------------- source
|
||||
|
||||
source "qemu" "diskless" {
|
||||
iso_url = var.iso_url
|
||||
iso_checksum = var.iso_checksum
|
||||
|
||||
output_directory = "output-qemu"
|
||||
vm_name = "diskless-build.qcow2"
|
||||
disk_size = "12G"
|
||||
format = "qcow2"
|
||||
accelerator = "kvm"
|
||||
memory = 4096
|
||||
cpus = 2
|
||||
headless = true
|
||||
|
||||
http_directory = "http"
|
||||
|
||||
# BIOS/isolinux boot. For an OVMF/UEFI build VM, replace with the grub
|
||||
# variant: ["c<wait>", "linuxefi /images/pxeboot/vmlinuz inst.text ",
|
||||
# "inst.ks=http://{{ .HTTPIP }}:{{ .HTTPPort }}/ks.cfg<enter>",
|
||||
# "initrdefi /images/pxeboot/initrd.img<enter>", "boot<enter>"]
|
||||
boot_wait = "5s"
|
||||
boot_command = [
|
||||
"<up><wait><tab>",
|
||||
" inst.text inst.ks=http://{{ .HTTPIP }}:{{ .HTTPPort }}/ks.cfg",
|
||||
"<enter><wait>",
|
||||
]
|
||||
|
||||
ssh_username = "root"
|
||||
ssh_password = var.build_password
|
||||
ssh_timeout = "60m"
|
||||
shutdown_command = "shutdown -P now"
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------- build
|
||||
|
||||
build {
|
||||
sources = ["source.qemu.diskless"]
|
||||
|
||||
# --- 1. Stage the dracut module, configs, and CA placeholder -------------
|
||||
provisioner "file" {
|
||||
source = "files/dracut/95dot1x-macsec"
|
||||
destination = "/usr/lib/dracut/modules.d/"
|
||||
}
|
||||
|
||||
provisioner "file" {
|
||||
source = "files/etc/"
|
||||
destination = "/tmp/etc-stage/"
|
||||
}
|
||||
|
||||
# --- 2. Packages, configs, diskless adaptations --------------------------
|
||||
provisioner "shell" {
|
||||
inline = [
|
||||
"set -euxo pipefail",
|
||||
|
||||
"dnf -y install wpa_supplicant tpm2-tools tpm2-tss nvme-cli cryptsetup dracut-network openssl",
|
||||
|
||||
# Stage etc files into place
|
||||
"install -D -m0644 /tmp/etc-stage/dot1x/radius-ca.pem /etc/dot1x/radius-ca.pem",
|
||||
"install -D -m0644 /tmp/etc-stage/dot1x/wpa_supplicant-dot1x.conf /etc/dot1x/wpa_supplicant-dot1x.conf",
|
||||
"install -D -m0644 /tmp/etc-stage/dracut.conf.d/90-diskless.conf /etc/dracut.conf.d/90-diskless.conf",
|
||||
"install -D -m0644 /tmp/etc-stage/NetworkManager/99-dot1x-unmanaged.conf /etc/NetworkManager/conf.d/99-dot1x-unmanaged.conf",
|
||||
"chmod 0755 /usr/lib/dracut/modules.d/95dot1x-macsec/*.sh",
|
||||
|
||||
# Inject the fleet NIC drivers into the dracut config
|
||||
"sed -i 's/@NIC_DRIVERS@/${var.nic_drivers}/' /etc/dracut.conf.d/90-diskless.conf",
|
||||
|
||||
# ---- Diskless adaptations ------------------------------------------
|
||||
# Per-host machine-id is generated at boot into the overlay
|
||||
"truncate -s 0 /etc/machine-id",
|
||||
# Read-only NFS root; runtime state on tmpfs/overlay (rootovl via the
|
||||
# dracut 'overlayfs' module is pulled in by 90-diskless.conf)
|
||||
"printf '%s\\n' '# diskless: root is provided by netroot; no local mounts' > /etc/fstab",
|
||||
# No local bootloader regeneration wanted on kernel updates inside CI
|
||||
"command -v grub2-mkconfig >/dev/null && echo 'GRUB updates not used on diskless hosts' || true",
|
||||
|
||||
# ---- Build the fleet-generic initramfs ------------------------------
|
||||
# %%{ escapes the rpm query tags so Packer's HCL template engine treats
|
||||
# them as literals (a bare %{...} is parsed as a template directive).
|
||||
"KVER=$(rpm -q --qf '%%{VERSION}-%%{RELEASE}.%%{ARCH}\\n' kernel | sort -V | tail -1)",
|
||||
"dracut -f --no-hostonly --kver \"$KVER\" /boot/initramfs-generic.img",
|
||||
"lsinitrd /boot/initramfs-generic.img | grep -E 'macsec|wpa_supplicant|tpm2_nvread|nvme.tcp|erofs|veritysetup' ",
|
||||
|
||||
# ---- Build hygiene ---------------------------------------------------
|
||||
"dnf clean all",
|
||||
"rm -rf /tmp/etc-stage /var/log/anaconda /root/anaconda-ks.cfg",
|
||||
"truncate -s 0 /var/log/messages /var/log/secure 2>/dev/null || true",
|
||||
]
|
||||
}
|
||||
|
||||
# --- 3. Extract kernel, initramfs, rootfs from the built disk ------------
|
||||
# --- 4. Assemble + sign the UKI; build the OCI release-artifact image ----
|
||||
post-processor "shell-local" {
|
||||
inline = [
|
||||
"bash scripts/extract-artifacts.sh output-qemu/diskless-build.qcow2 ${var.artifact_dir}/${var.image_version} ${var.disable_dot1x}",
|
||||
"bash scripts/build-oci.sh ${var.artifact_dir}/${var.image_version} ${var.oci_image} ${var.image_version} '${var.sb_key}' '${var.sb_cert}' ${var.oci_push}",
|
||||
]
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user