docs: document disk images, installer, vendor packaging, and secure boot

- docs/secureboot.md: MOK workflow (generate, build, enroll).
- docs/building.md: image + install quickstart, new outputs, ARCLINE_SIGN.
- docs/observability.md: vendor .debs are now the primary packaging path.
- docs/editions.md: cloud ships a qcow2; qemu test command.
- docs/architecture.md: full pipeline table incl. deploy/install; the
  four follow-up items are now implemented; new "on the horizon" list.
- README: updated feature list, quickstart, and status.
This commit is contained in:
Blake Ridgway
2026-08-21 13:33:17 -05:00
parent 3a17504dd0
commit a27d3fb313
6 changed files with 155 additions and 31 deletions

View File

@@ -35,16 +35,20 @@ Pipeline stages live in `scripts/`:
| overlay | `apply-overlays.sh` | copies `overlays/base` + `overlays/<edition>` into the rootfs |
| configure | `configure-system.sh` | runs *in the chroot*: hostname, locale, kernel cmdline, services, live-boot, toolchain |
| package | `build-iso.sh` | kernel + initramfs + squashfs → hybrid BIOS/UEFI ISO |
| image | `build-image.sh` | rootfs → bootable qcow2/raw disk image (via `deploy-disk.sh`) |
| deploy | `deploy-disk.sh` | partition → btrfs layout → copy rootfs → GRUB + fstab (shared by image + installer) |
| install | `install.sh` | scripted installer for a real disk (confirmation-gated) |
| orchestrate | `build-edition.sh` / `Makefile` | wire the above to `make iso-<edition>` |
## The four source trees
## The source trees
| Path | Role |
|------|------|
| `editions/` | per-edition **manifests**: package lists, kernel cmdline, fstab, metadata |
| `overlays/` | **files that land in the image**, organised as layered rootfs trees |
| `scripts/` | the **build pipeline** (all plain bash, readable top to bottom) |
| `btrfs/`, `toolchain/`, `observability/`, `tests/`, `ci/` | supporting subsystems |
| `btrfs/`, `toolchain/`, `tests/`, `ci/` | supporting subsystems |
| `scripts/secureboot/` | MOK key generation + boot-chain signing (optional) |
There is no hidden magic: the Makefile is a thin wrapper, `versions.mk` /
`scripts/common.sh` hold the single source of truth for versions and paths.
@@ -59,10 +63,23 @@ There is no hidden magic: the Makefile is a thin wrapper, `versions.mk` /
- The smoke tests (`tests/smoke/verify-rootfs.sh`) fail the build if telemetry
artifacts are found.
## Follow-up work (explicitly out of scope for "the wires")
## What "the wires" now covers
- Partitioning/installer that runs `btrfs/init.sh` on a target disk.
- Cloud images (qcow2/raw) for the `cloud` edition — the ISO path is wired,
a disk-image path is the next step.
- Grafana/Loki packaged as `.deb`s rather than fetched from upstream.
- A signed (secure-boot) kernel for official releases.
The four original follow-up items are implemented:
1. **Disk images**`make image-<edition>` produces bootable qcow2/raw images;
the cloud edition ships as a qcow2 by default.
2. **Installer**`scripts/install.sh <device>` installs to a real disk
(explicit confirmation, reuses the deploy module).
3. **Grafana/Loki/Promtail `.debs`**`make vendor` packages them so the full
observability stack installs without upstream repos.
4. **Secure boot** — MOK-based signing (`scripts/secureboot/`), off by
default, enabled with `ARCLINE_SIGN=1`.
## Still on the horizon
- A signed Microsoft-KEK boot chain (only relevant for commercial
distribution; the MOK path covers self-hosted use).
- ARM64 (`arm64`) as a first-class arch (one-line change in `versions.mk`).
- Boot-time verification tests for installed systems (the smoke tests cover
the image contents, not a booted VM yet).

View File

@@ -27,7 +27,9 @@ make check # validate the tree (fast, offline, safe)
make rootfs-server # build just the server rootfs
make iso-server # build a bootable server ISO
make iso # build all three editions
make image-cloud # build the cloud edition as a qcow2 disk image
make toolchain # build the 11 Go tools into .deb
make vendor # build Grafana/Loki/Promtail .debs
make test # run smoke tests against built rootfs(es)
```
@@ -40,10 +42,30 @@ Everything lands under `build/`:
| `build/rootfs/<edition>/` | extracted rootfs (from `make rootfs-*`) |
| `build/artifacts/arcline-<edition>-<version>-<arch>.tar.xz` | archived rootfs |
| `build/artifacts/arcline-<edition>-<version>-<arch>.iso` | bootable live ISO |
| `build/debs/*.deb` | Arcline toolchain packages (from `make toolchain`) |
| `build/artifacts/arcline-<edition>-<version>-<arch>.qcow2` | bootable disk image |
| `build/debs/*.deb` | Arcline toolchain + vendor packages |
Each artifact ships with a `.sha256` checksum file.
## Disk images & installing
- `make image-<edition>` builds a bootable **qcow2** disk image (the cloud
edition's primary output; also handy for VM-testing server/workstation).
Options: `--format raw`, `--size 4G`, `--boot efi`.
- `scripts/install.sh /dev/sdX --edition server` installs a built rootfs onto
a real disk (asks for explicit confirmation, then partitions, lays out
btrfs subvolumes, installs GRUB, and writes a real fstab). Both reuse the
shared `scripts/deploy-disk.sh`.
## Secure boot
Optional, MOK-based. See [secureboot](secureboot.md):
```bash
scripts/secureboot/gen-keys.sh
ARCLINE_SIGN=1 make iso-server
```
## Reproducibility knobs
Set these as environment variables or edit `versions.mk`:
@@ -58,6 +80,7 @@ Set these as environment variables or edit `versions.mk`:
| `ARCLINE_LOCK_ROOT` | lock root account (`passwd -l root`) | `0` |
| `ARCLINE_EXTRA_REPOS` | fetch grafana/loki upstream repos | `0` |
| `ARCLINE_TOOLCHAIN` | toolchain in image builds | `auto` |
| `ARCLINE_SIGN` | sign boot chain with the MOK (secure boot) | `0` |
## Building without the Arcline toolchain

View File

@@ -3,11 +3,11 @@
Three flavours, one hardened base. Each is defined entirely by its manifest
under `editions/<name>/`.
| Edition | Codename | Purpose | Kernel | Notes |
|---------|----------|---------|--------|-------|
| `server` | bastion | production server | generic (`linux-image-amd64`) | full observability stack, containers |
| `workstation` | forge | hardened daily driver | generic | KDE Plasma, dev toolchains |
| `cloud` | nimbus | cloud images | cloud (`linux-image-cloud-amd64`) | cloud-init, guest agents |
| Edition | Codename | Purpose | Kernel | Output |
|---------|----------|---------|--------|--------|
| `server` | bastion | production server | generic (`linux-image-amd64`) | ISO (and qcow2 for VM testing) |
| `workstation` | forge | hardened daily driver | generic | ISO |
| `cloud` | nimbus | cloud images | cloud (`linux-image-cloud-amd64`) | **qcow2/raw disk image** (`make image-cloud`)
## What an edition manifest contains
@@ -39,6 +39,10 @@ and privacy-oriented defaults.
Minimal footprint: cloud kernel, cloud-init (NoCloud/ConfigDrive/EC2/GCE/
Azure), guest agents (qemu/vmware), NVMe + iSCSI + multipath tooling.
`net.ifnames=0` for predictable, provider-friendly interface naming. The
disk-image (qcow2) output path is the next milestone — the manifest is ready,
the ISO path is wired today.
`net.ifnames=0` for predictable, provider-friendly interface naming. Ships as
a bootable **qcow2** disk image (`make image-cloud`) — BIOS boot by default,
UEFI via `--boot efi`; upload to your provider or test with qemu:
```
qemu-system-x86_64 -m 2G -drive file=build/artifacts/arcline-cloud-0.1.0-amd64.qcow2,format=qcow2 -nographic
```

View File

@@ -32,16 +32,26 @@ service.
## Packaging note
Prometheus + node_exporter + alertmanager are in Debian main and install with
the edition packages. **Grafana** and **Loki** are not:
the edition packages. **Grafana**, **Loki**, and **Promtail** are not — but
they're now packaged as `.debs` by `toolchain/build-vendor.sh`:
- Grafana is available via the official `apt.grafana.com` repo — add it by
setting `ARCLINE_EXTRA_REPOS=1` during the build
(`configure-system.sh` adds the repo + key).
- Loki ships as a static binary tarball; the packaging (a `.deb` in
`toolchain/`) is follow-up work.
```bash
make vendor # → build/debs/grafana_<v>_amd64.deb, arcline-loki_<v>.deb, arcline-promtail_<v>.deb
make iso-server
```
Until then, the Grafana/Loki configs ship dormant in the image, ready for when
the binaries are installed — the `overlays/server` configs are the contract.
The debs land in `build/debs/` alongside the toolchain, so the next rootfs
build picks them up automatically and the configure hook enables
`grafana-server` / `loki` / `promtail` when their binaries are present.
- `grafana` — the official OSS `.deb` from `dl.grafana.com`, vendored as-is.
- `arcline-loki` / `arcline-promtail` — static binaries from the Loki GitHub
release, wrapped in minimal debs that install the configs from
`overlays/server/etc/` and systemd units from `toolchain/vendor/`.
If the downloads fail (no network / version bumped), the build skips them with
a warning — the old `ARCLINE_EXTRA_REPOS=1` path (apt.grafana.com) remains as
a fallback.
## Access

61
docs/secureboot.md Normal file
View File

@@ -0,0 +1,61 @@
# Secure boot (MOK-based)
Arcline can ship **self-signed** boot chains verified by your machine's own
secure-boot firmware. We use a **Machine Owner Key (MOK)** — the same approach
used to load custom kernels on Windows-certified laptops — rather than paying
for a Microsoft KEK signing cert. You own the key, you own the trust anchor.
```
MOK.priv ──(sbsign)──► vmlinuz, grubx64.efi, shimx64.efi
MOK.der ──(mokutil)──► enrolled into firmware MOK list (one-time prompt)
```
## Workflow
1. **Generate the key** (once, keep it secret):
```bash
scripts/secureboot/gen-keys.sh # → build/keys/{MOK.priv,MOK.pem,MOK.der}
```
2. **Build a signed image** (ISO or disk image):
```bash
ARCLINE_SIGN=1 make iso-server
ARCLINE_SIGN=1 make image-cloud
```
The build signs every kernel + EFI binary in the boot chain with the MOK
and ships the *public* `MOK.der` into the image at `/etc/arcline/MOK.der`.
3. **Enroll on first boot** — the `arcline-mok-enroll.service` unit imports the
key automatically the first time the system boots with secure boot enabled.
The firmware shows a one-time "Enroll MOK" prompt; confirm it, reboot, done.
The unit disables itself afterwards (and no-ops entirely when no key was
shipped — secure boot is off by default).
Manual alternative:
```bash
sudo mokutil --import /etc/arcline/MOK.der
sudo reboot # then confirm at the blue MOK manager screen
```
## What gets signed
- kernels (`vmlinuz*`) — in `/boot` for installed systems, `/live` for ISOs
- EFI binaries (`*.efi`) — grubx64, shimx64, mmx64, fbx64
GRUB `.mod` modules are not PE binaries and are not individually signed (GRUB
has its own module-signature mechanism, out of scope here). If you use the
shim-provided fallback loader, the Microsoft-signed shim validates grubx64.efi
against your MOK.
## Notes
- Requires `sbsigntool` on the build host and `mokutil` in the image
(`mokutil` is pulled in by the `shim-signed` package already in the package
lists).
- Losing `MOK.priv` means you cannot sign future updates — back it up.
- Full vendor CA / Microsoft KEK signing is intentionally not used; revisit
only if a commercial distribution is ever pursued.