Skip to content

Latest commit

 

History

History
164 lines (133 loc) · 7.3 KB

building.md

File metadata and controls

164 lines (133 loc) · 7.3 KB

Building Kryptik

The Distro workflow builds and tests every push to main on GitHub's runners, so a local build is optional. It needs Linux; make check refuses to run anywhere else and names what the host is missing.

Host packages

On Debian or Ubuntu, the same set the Distro workflow installs (HOST_PACKAGES in .github/workflows/distro.yml):

sudo apt install -y build-essential bison flex texinfo gawk m4 patch perl \
    python3 python3-pip xz-utils bzip2 zstd cpio rsync bc curl git openssl \
    libssl-dev libelf-dev e2fsprogs dosfstools mtools exfatprogs xorriso \
    util-linux cryptsetup-bin sbsigntool libasound2-dev qemu-system-x86 ovmf \
    musl-tools file
sudo dpkg-reconfigure dash        # answer "No": /bin/sh must be bash

The Secure Boot suites also need virt-fw-vars (pip install virt-firmware), and the acceptance suites want KVM.

WSL2

Build from a clone on the Linux filesystem, not /mnt/c: it is slow, and it cannot represent the POSIX ownership the chroot stages depend on. GCC's bootstrap wants about 8 GB of memory; if make check warns, raise the limit in %UserProfile%\.wslconfig and run wsl --shutdown:

[wsl2]
memory=12GB
processors=8

Stages

make check      # what the host is missing
make lock       # regenerate sources.lock; audit it (docs/supply-chain.md)
make sources    # fetch and verify
make toolchain  # stage 01                     (unprivileged)
make temp-tools # stage 02                     (unprivileged)
make system     # stage 04, inside the chroot  (root for the mounts)
make kernel     # stage 05, inside the chroot
make images     # the software images over stage 04: the toolkit, the browser (hours)
make media      # stage 06: USB image, ISO, signed release payload

untrusted, personal and work name the browser and toolkit images, and a zone naming an image does not start unless its root has a signed list that holds it, so a medium for use needs make images before make media. Firefox alone takes some three hours on four cores; a rebuilt stage 04 rebuilds it only when a step up to wlroots changed, or the headers and libraries a build can find (software delivery).

make paths prints where everything goes; KRYPTIK_WORK moves the work tree. Each step is stamped, so a rerun resumes where it stopped and a changed recipe rebuilds from that step on.

make media KRYPTIK_CHANNEL=https://<host>/<channel>/ names where the image's network zone asks for new releases (update channel). Without it the image fetches nothing, and updates come only from a payload on a disk.

A development image, the default, is signed with keys the build makes on first use under <work>/keys (<work> is KRYPTIK_WORK, as make paths prints it). A production image is signed only with keys it is handed, from the key medium, and names its version as MAJOR.MINOR.PATCH:

make media KRYPTIK_ROLE=production KRYPTIK_KEYS=/media/<medium> KRYPTIK_VERSION=1.0.3

The medium holds release-signers (the anchor the image will trust), kryptik-release and kryptik-release.pub, kryptik-sb.key and kryptik-sb.crt, and optionally kryptik-latest and kryptik-latest.pub and kryptik-testctl and kryptik-testctl.pub, which the build reads only to check they are the anchor's. Its private keys must be readable by their owner alone, who is root or the user running the build, and it must not be inside the work or output tree. Stage 06 checks all of that before it signs anything. It makes no key and copies none: the keys are read by the tools that sign with them, by path. Making the keys, publishing with them, and replacing them are in release keys.

The Distro workflow splits a production build so its keys never reach the machine that ran the chroot. KRYPTIK_MEDIA_PHASE=bind, with KRYPTIK_KEYS naming a directory that holds release-signers and kryptik-sb.crt and no private key, builds the root and binds the kernels to it. Then KRYPTIK_MEDIA_PHASE=sign, with the whole medium, on another machine given the work tree and that release's stage 06 stamps, checks what was bound against the medium, signs and assembles the media without touching the sysroot or the chroot.

To publish a build, add its payload to the channel's directory, which any web server can then serve at that address:

tools/release-channel.sh publish --key <work>/keys/release/kryptik-latest \
    --signers <work>/keys/release/release-signers \
    --payload <work>/images/payload-<version> --out /srv/<channel>

For a production image, the key and the signers file are the medium's kryptik-latest and release-signers. When the medium carries no kryptik-latest, stage 06 leaves publishing to the release host, which holds that key. Re-sign the channel's statement daily, with reissue and the same key and signers file, from a timer: a machine reports a statement older than 30 days.

Testing without a build

The host suites need no build and no root:

make test         # every tools/tests/* suite, then the compartment suites
make zone-tests   # adversarial.sh (the primitives) and launcher.sh (kryptikd run)

The compartment suites need a Rust toolchain and a kernel with user namespaces, seccomp and Landlock. The privileged launch path and cgroup limits run as root only on the installed system, in make zones-test.

Five kinds of test, one name each:

name where what
tool suites tools/tests/*.sh, *.py a tool's own offline suite, named after the tool it tests
compartment suites compartments/tests/*.sh kryptikd's suites, as root or not
guest checks build/guest-tests/*-check.sh run inside the booted image; print the pass and fail lines the image suite reads
image suites tools/image/*-test.sh boot the image under OVMF, drive it, judge its guest checks and screenshots
acceptance tools/acceptance.sh the verdict over all of them: make acceptance

Acceptance

make acceptance runs every suite against the built media, as root under KVM. The update suite installs the release before the newest and updates it to the newest, so it needs two. The production suite does the same with a production pair, signed with a throwaway key medium that exists only while make production-pair builds the pair, and kept apart in <work>/images-production. Build the pair first, since the suites take the release built last as the one under test:

make production-pair
make media KRYPTIK_VERSION=0.1.1
make media KRYPTIK_VERSION=0.1.2
make acceptance EXPORT=/tmp/kryptik-export

tools/release-publish.sh /tmp/kryptik-export puts that export on the repository's Releases page once tag v0.1.2 is pushed (releases).

The suites arm their unattended installs with a control disk the medium under test checks against its anchor. A development medium honours the build's own kryptik-testctl (under <work>/keys/release), the default; a production release's media honour the release's own, so its acceptance names it: make acceptance EXPORT=DIR KRYPTIK_TESTCTL_KEY=<copy>/kryptik-testctl (release keys). The boot tests enrol the Secure Boot certificate the medium under test carries, and the export publishes that certificate: a production release is tested as a machine that enrolled its certificate boots it.