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:
21
README.md
21
README.md
@@ -12,6 +12,9 @@ manifests into hardened, bootable operating system images for three editions:
|
||||
|
||||
- A transparent, script-based build pipeline (no magic, everything auditable)
|
||||
- `debootstrap` → package install → overlay → in-chroot configure → live ISO
|
||||
- **Disk images + installer**: `make image-<edition>` builds bootable qcow2/raw
|
||||
images; `scripts/install.sh` installs to a real disk (both share the
|
||||
`deploy-disk.sh` core: partition → btrfs layout → GRUB → real fstab)
|
||||
- **Secure by default**: hardened kernel cmdline + sysctl, default-deny
|
||||
nftables, key-only ssh, AppArmor, no core dumps
|
||||
- **btrfs-native**: subvolume layout, scheduled read-only snapshots, and
|
||||
@@ -19,9 +22,12 @@ manifests into hardened, bootable operating system images for three editions:
|
||||
- **Zero telemetry**: enforced by package selection, masked apt timers, and
|
||||
smoke tests that fail the build if telemetry is found
|
||||
- **Pre-configured observability** (server): Prometheus + node_exporter +
|
||||
Grafana (auto-provisioned) + Loki + promtail, local-only
|
||||
Grafana (auto-provisioned) + Loki + promtail, local-only — Grafana/Loki/
|
||||
promtail packaged as `.debs` by `make vendor`
|
||||
- **The Arcline toolchain**: a harness that packages all 11 Go tools into
|
||||
`.deb`s and installs them into the image
|
||||
- **Optional secure boot**: MOK-based signing of the boot chain
|
||||
(`ARCLINE_SIGN=1`)
|
||||
- Smoke tests, GitLab CI, and docs that explain every decision
|
||||
|
||||
## Quickstart
|
||||
@@ -32,7 +38,9 @@ make deps # install host build dependencies
|
||||
make check # validate the tree (fast, offline)
|
||||
make iso-server # build a bootable server ISO
|
||||
make iso # build all three editions
|
||||
make image-cloud # cloud edition as a qcow2 disk image
|
||||
make toolchain # build the 11 Go tools into .deb
|
||||
make vendor # build grafana/loki/promtail .debs
|
||||
make iso-server-minimal # server ISO WITHOUT the Arcline toolchain
|
||||
make test # run smoke tests against built rootfs(es)
|
||||
```
|
||||
@@ -69,15 +77,16 @@ os-build/
|
||||
| [editions](docs/editions.md) | server / workstation / cloud manifests |
|
||||
| [observability](docs/observability.md) | the pre-configured monitoring stack |
|
||||
| [toolchain](docs/toolchain.md) | the 11 Go tools and their packaging |
|
||||
| [secureboot](docs/secureboot.md) | MOK key generation + signing workflow |
|
||||
| [btrfs](btrfs/README.md) | subvolume layout + snapshots + rollback |
|
||||
|
||||
## Status
|
||||
|
||||
This is the **foundation**: the build pipeline, edition manifests, hardening
|
||||
baseline, btrfs tooling, observability configs, tests, and CI are in place and
|
||||
runnable. The next milestones (installer that writes the btrfs layout to disk,
|
||||
cloud disk images, signed releases) are listed in
|
||||
[docs/architecture.md](docs/architecture.md#follow-up-work).
|
||||
The build pipeline, edition manifests, hardening baseline, btrfs tooling,
|
||||
observability packaging, disk images + installer, tests, CI, and optional
|
||||
secure boot are all in place and runnable. What's next: a Microsoft-KEK signed
|
||||
boot chain (only relevant for commercial distribution), `arm64` support, and
|
||||
booted-VM verification tests.
|
||||
|
||||
## License
|
||||
|
||||
|
||||
@@ -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).
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
```
|
||||
|
||||
@@ -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
61
docs/secureboot.md
Normal 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.
|
||||
Reference in New Issue
Block a user