Skip to content

Latest commit

 

History

History
33 lines (24 loc) · 7.46 KB

File metadata and controls

33 lines (24 loc) · 7.46 KB

Lean hosted cloud-image mkosi profile (hosted marker)

  • Status: done (build+boot proof deferred — see Verification)
  • Date: 2026-06-19
  • Specs realized (DECISIONS entry added): ENVIRONMENT.md # How the profile is realized ("A lean cloud image profile", "A runtime marker"), # Assumption inventory (the cut list), # Networking & discovery (no NM/Avahi), # Storage (no LUKS/TPM), # Public-by-default; BUILD.md # 1 (Debian Trixie base), # 2 (mkosi, disk images)
  • Closes: #203 (C1b — second of the C1 split, after #202/C1a and alongside #204/C1c; part of #196). Builds on #202/C1a (the /etc/malmo/profile marker the brain reads) and is the image the slim cloud host-agent (#204/C1c) gets compiled into; the boot proof is #205/C2.

What was done

The repo's first product image definition. Until now dev/test-qemu/ was the only mkosi tree, and it is a test lane (bookworm, LUKS+TPM, SSH, the full control-plane bundle baked in for an air-gapped QEMU boot). dev/cloud/ is a new, separate mkosi image — not the appliance rootfs with services disabled, but its own definition that installs only what a cloud VM needs (ENVIRONMENT.md # How the profile is realized — "absent, not disabled"). mkosi stays the single builder (BUILD.md # 2, DECISIONS.md 2026-06-16); this is a second image definition, not a second builder.

  • dev/cloud/mkosi.confDistribution=debian / Release=trixie (the locked product base, BUILD.md # 1 — not the test lane's bookworm), Format=disk, ImageId=malmo-cloud, ManifestFormat=json, ToolsTree=default (reused from the test lane so the build works on hosts with old systemd). Bootable=yes + Bootloader=systemd-boot. KernelCommandLine=console=tty0 console=ttyS0 psi=1 rwpsi=1 is required on the product image (BUILD.md # 1): Debian builds CONFIG_PSI=y but CONFIG_PSI_DEFAULT_DISABLED=y, so without it the ram-pressure health detector reads zeros = a false all-clear (the test lane omits it; the product image must not). A virtio+ext4+crc32c modules-initrd so the image can actually find a virtio root disk on a cloud hypervisor — with the test lane's LUKS/dm-crypt cipher modules deliberately absent.
  • Lean package setlinux-image-amd64, systemd/systemd-sysv/systemd-boot, the docker-ce stack, ca-certificates, dbus, util-linux, kmod, udev, iproute2, sudo, and the base shell utils. Explicitly NOT installed (the cuts): network-manager, avahi-daemon/avahi-utils, samba, mergerfs, cryptsetup, tpm2-tools, and the appliance SSH posture (openssh-server + nftables).
  • No LUKS/TPM repart. dev/cloud/ ships no mkosi.repart/ — providing it at all takes over partitioning, so omitting it uses mkosi's default plain ESP + root layout (exactly the unencrypted ESP+root this profile wants; the test lane provides mkosi.repart/ only because it needs a LUKS root). No rd.luks.* cmdline, no first-boot TPM-enroll units, no malmo-storage-verify/malmo-network-verify/malmo-tpm-enroll baking.
  • The markerdev/cloud/mkosi.extra/etc/malmo/profile contains hosted, baked via ExtraTrees. This is exactly the file internal/profile.Read (#202/C1a) reads at brain startup. Unlike the test lane's generated mkosi.extra/, this one is a single static committed file, so it needs no staging script.
  • dev/cloud/bootstrap.sh — the thin build harness (analog of the test lane's bootstrap.sh, minus the QEMU/swtpm/LUKS machinery): preflight (mkosi>=22, curl, python3), stage Docker's apt repo + signing key into the auto-detected mkosi.pkgmngr/ tree (trixie pocket), mkosi build, then assert the lean cut list is absent from the JSON package manifest and the marker reads hosted. Runs unprivileged (mkosi self-escalates).
  • make build-cloud-image runs dev/cloud/bootstrap.sh; wired into .PHONY + make help.

Firewall posture — decided, not omitted (DECISIONS.md 2026-06-19). Dropping nftables means Docker publishes container ports to 0.0.0.0 by default, which on a public-by-default cloud VM could expose app ports with nothing in front. The call: hosted v1 relies solely on the cloud provider's security groups / VPC firewall, recorded as an explicit operator requirement (provision every tenant behind a firewall admitting only 443 + the ACME/redirect 80). The appliance's nftables exists only to LAN-scope SSH/SMB — hosted ships neither, so there is no ruleset to port. A minimal in-guest nftables default-deny backstop (for provider postures lacking security groups) is deferred to NEXT.md. ENVIRONMENT.md # Public-by-default now states the requirement explicitly.

Verification

  • Config validity (done on this box). mkosi summary under the installed mkosi 26 parses dev/cloud/mkosi.conf cleanly and resolves the intended settings on the main image: debian/trixie, Format=disk, ManifestFormat=json, ImageId=malmo-cloud, Bootable=enabled, Bootloader=systemd-boot, the psi=1 cmdline, the committed ExtraTrees, Repart Directories: none (confirming the mkosi-default plain ESP+root, no LUKS), and the lean package set (linux-image-amd64, docker-ce…). The cut packages are absent from the resolved Packages.
  • Lean assertion logic (done). bootstrap.sh's manifest check matches exact package names, so a transitive libcryptsetup12/systemd-cryptsetup pulled by systemd is not a false positive — only the appliance packages themselves (cryptsetup, network-manager, avahi-daemon, avahi-utils, samba, mergerfs, tpm2-tools, openssh-server) fail the build. The marker check trims whitespace and compares to hosted.
  • Full mkosi build is NOT exercised on this box. It is blocked by the same mkosi-26/Ubuntu-24.04 sandbox limitation that blocks the medium QEMU lane (PR_CAPBSET_DROP EPERM, tracked as #189) — a host limitation, not a config error (config parsing, above, succeeds). The build+lean-assertion runs on any working mkosi host via make build-cloud-image; it is the same path #205/C2 consumes to bake + boot the image.

Known gaps / what's next

  • No boot proof here. This slice is the image definition + lean package set + marker + build target only. Emitting the qcow2, booting the VM under QEMU, bringing the control plane up, and asserting psi=1 is live + the marker is read are all #205/C2's job. C2 builds this image with the slim host-agent (#204/C1c, go build -tags hosted).
  • No host-agent/brain bring-up baked. Deliberately out of scope (avoids a circular dependency on C1c and keeps the boot assertions in C2): no systemd units, no control-plane image tarballs, no PAM/malmo-group provisioning, no first-boot networking. C2/C3a add those.
  • Trixie vs the test lane's bookworm. The cloud image targets Trixie (the locked product base); the medium QEMU lane is still bookworm. If Docker's trixie apt pocket or a Trixie/mkosi sharp edge blocks the build, bootstrap.sh notes the bookworm-pocket fallback and #203's escape hatch — file a follow-up rather than expanding this slice. Aligning the test lane to Trixie once the cloud image validates it is tracked in NEXT.md (Tier 3).
  • Shared base with a future appliance product image (so the appliance ISO/USB image and this cloud image don't duplicate the package/repo boilerplate) is a deliberate later refactor, not this slice.
  • The lean cloud image completes the C1 split alongside #202 (marker + brain read) and #204 (slim agent). C2 (#205) emits and boots the assembled image.