Build guide

ST build guide #

Build your own transparent system.


This guide shows how to create a System Transparency OS package and boot it, both in an emulator (QEMU) and on real hardware.

The following topics will be covered:

  • Building a bootloader image
  • Creating an OS package
  • Using the bootloader to boot the OS

If you would rather skip all the building of things there’s a quickstart guide which lets you download prebuilt binaries.

Prerequisites #

  • You need a computer running Linux for building the binaries. If it is a Debian 12 (Bookworm) system, all commands can be pasted verbatim into a shell.

  • If you want to boot your OS on real hardware, you need an x86 computer capable of UEFI booting.

Prepare the build environment #

Assuming a Debian 12 (Bookworm) system, here is what to install and configure in order to set up a build environment for compiling images and booting them using QEMU.

Prepare for booting in an emulator #

For booting in QEMU, the following packages need to be installed.

apt install qemu-system-x86 ovmf ncat

If you already have a web server at hand you can skip ncat.

Prepare for building #

For building the boot loader and an OS package, this is what you need to do to prepare your build system.

As the root user, install the required packages. The first line is needed for both bootloader and OS package creation. If you only want to build a bootloader image you can skip the second line.

apt install golang-go ca-certificates git cpio pigz
apt install mmdebstrap

Switch to a non-root user and clone stimages-0.1.1 which contains examples of how to build all the components of ST. This will become your build directory for the remainder of this guide.

git clone -b stimages-0.1.1 https://git.glasklar.is/system-transparency/core/stimages.git
cd stimages

Set up a local GOBIN directory, add it to PATH and install stmgr to it.

mkdir -p go/bin; GOBIN="$(realpath go/bin)"; export GOBIN
export PATH="$GOBIN":"$PATH"
go install system-transparency.org/stmgr@v0.4.1

Generate keys and certificates for signing the OS package.

(umask 0077 && mkdir keys)
(cd keys && stmgr keygen certificate --isCA)
(cd keys && stmgr keygen certificate --rootCert rootcert.pem --rootKey rootkey.pem)

You are now ready to build both a bootloader image and an OS package.

Build your own bootloader image #

Build stboot.iso using one of the example scripts.

contrib/stboot/build-stboot http://10.0.2.2:8080/my-os.json keys/rootcert.pem

The URL is where stboot will download OS packages from. The server address used here is particularly convenient for testing stboot in a QEMU guest VM. Replace it with a DNS name pointing at a web server on the internet for a more realistic test.

The PEM file is the trust root that stboot will use to verify OS package signatures.

Build your own OS package #

An OS package contains an initramfs archive containing the root filesystem. The build-initramfs example script will build an initramfs based on Debian 12 (Bookworm).

build-initramfs will need a new root password for the OS package. To minimize the risk of reusing a sensitive password, you can write the new password to the config directory before running build-initramfs.

echo myrootpassword > config/example/pw.root

Build the initramfs archive for the OS package.

./build-initramfs config/example my-os.cpio.gz

Put it all together into an OS package, consisting of two files: my-os.json and my-os.zip.

stmgr ospkg create \
    --label="My example ST system" \
    --initramfs=my-os.cpio.gz \
    --kernel=my-os.vmlinuz \
    --cmdline="console=ttyS0,115200n8 ro rdinit=/lib/systemd/systemd" \
    --url=http://10.0.2.2:8080/my-os.zip \
    --out=my-os.zip

And sign the OS package.

stmgr ospkg sign \
    --cert keys/cert.pem \
    --key keys/key.pem \
    --ospkg my-os

You are ready to boot the new OS package.

Boot the OS package #

You can boot your OS package in the PC emulator QEMU without the need for any extra hardware.

Or you can boot your OS package on a real computer, as long as it’s an x86_64 system.

Boot in QEMU #

This section shows how to boot your newly built OS package in a VM on your build system.

The VM will want to store its EFI variables somewhere so create a file for NVRAM backing.

cp /usr/share/OVMF/OVMF_VARS.fd OVMF_VARS.fd

Serve the OS package files by running ncat twice on your build system.

(for e in json zip
     do ncat -lc "printf 'HTTP/1.1 200 OK\n\n'; cat my-os.$e" \
           0.0.0.0 8080; done) &

(This is a pretty shoddy hack and you might want to consider using a real web server instead.)

Boot the VM.

qemu-system-x86_64 \
    -m 3G \
    -accel kvm \
    -accel tcg \
    -pidfile qemu.pid \
    -no-reboot \
    -nographic \
    -rtc base=localtime \
    -drive if=pflash,format=raw,file=/usr/share/OVMF/OVMF_CODE.fd,readonly=on \
    -drive if=pflash,format=raw,file=OVMF_VARS.fd \
    -object rng-random,filename=/dev/urandom,id=rng0 \
    -device virtio-rng-pci,rng=rng0 \
    -drive file="stboot.iso",format=raw,if=none,media=cdrom,id=drive-cd1,readonly=on \
    -device ahci,id=ahci0 -device ide-cd,bus=ahci0.0,drive=drive-cd1,id=cd1,bootindex=1

(All of the options are not strictly necessary but none of them should pose any problem, even when running in a VM or in a container.)

When the dust settles you should find yourself at a login prompt. Try logging in as root using ‘myrootpassword’.

Debian GNU/Linux 12 amnesiac-debian ttyS0

amnesiac-debian login:

Boot real hardware #

The quickstart guide describes how to boot the ISO produced earlier. If you would rather boot a UKI, build stboot again as follows:

contrib/stboot/build-stboot http://example.org/my-os.json keys/rootcert.pem uki

Replace the URL with a DNS name pointing at a web server serving OS packages.

Explanation of commands #

This section explains in some more detail how we built the boot loader and an OS package and then ran it all under QEMU.

We started by installing all required software and cloning the stimages repo.

Then we built a bootable ISO running stboot by running the build-stboot script providing two things; a URL for stboot to pull OS packages from and a root certificate for verifying downloaded OS packages.

After that we built an OS package by running the build-initramfs script once and the stmgr program twice. The script used the Debian program mmdebstrap together with configuration found in the config/example directory to put together a file system and package it in an initramfs archive. The first stmgr command (ospkg create) used the new initramfs archive and a kernel extracted from the Debian system from the previous step to produce two new files named my-os.json and my-os.zip. The final step was to use stmgr (ospkg sign) to add a signature of the ZIP file to the JSON file, for stboot to use when verifying the OS package.

Finally we ran it all in QEMU by first faking a web server using netcat and then providing QEMU with the path to stboot.iso. QEMU started stboot which downloaded first the JSON file of our OS package and then the ZIP file named in the JSON file. stboot then verified the signature in the JSON file, unpacked the ZIP file and booted the kernel found there, providing the initramfs and kernel command line also found in the ZIP file.