Building the image¶
The kiosk is a complete system image, built with
mkosi from Debian 13 (trixie) packages.
Everything runs in a Debian 13 container (image/Dockerfile: mkosi, QEMU,
OVMF): the build computer only needs Docker.
Warning
The image and the signature sets are signed with development keys only. The production image has no signature set: the kiosk scans nothing until a signature update device is inserted (see Signatures). See the phase 2 tasks in the roadmap.
In short¶
image/build.sh # offline kiosk
image/build.sh --profile online # kiosk with network: online updates, SIEM, NTP
The image is image/mkosi.output/pandora-box.raw: write it to the disk of the
kiosk (Initial installation), or test it first in a virtual
machine (Testing with QEMU).
Requirements¶
Docker, about 5 GB of disk space, network access (Debian packages and Python wheels).
On Windows, build in WSL from a clone in the WSL file system (not under
/mnt/c), with LF line endings: Windows line endings (CRLF) break the
configuration of the image, and USBGuard then blocks every USB device.
image/build.sh refuses to build from files with CRLF.
git config --global core.autocrlf input
git clone https://github.com/sourcentis/pandora-box.git
Before the build¶
The image is read-only: everything below is part of it, and changing it means building a new image, then installing it as an update.
| What | Where |
|---|---|
| Configuration of the kiosk | packaging/pandora-box.toml (see Configuration) |
| Theme of the interface | image/theme/ (see Interface) |
| Mode of the screen | video= on the kernel command line, image/mkosi.conf (see Screen) |
| Touchscreen allowed by USBGuard | image/mkosi.extra/etc/usbguard/rules.conf (see USB devices) |
| Disk controller of another computer | KernelModulesInitrdInclude= of image/mkosi.conf (see Unified kernel image) |
| Certificate authorities of the SIEM | image/siem-ca.pem (see SIEM) |
abuse.ch Auth-Key, profile online |
image/credentials.toml (see Profile online) |
NTP servers, profile online |
see Time |
Keys¶
The image is signed with image/mkosi.key and image/mkosi.crt
(systemd-boot, unified kernel image, dm-verity root hash): the firmware of a
kiosk only starts an image signed with this key. It trusts the signature
sets, image updates and maintenance requests signed with image/update.key:
its public key image/update.pem is installed in the image.
When they do not exist, image/build.sh generates a development pair of
each, valid 10 years, that never leaves the build computer (ignored by git).
Keep them: a kiosk only accepts the updates signed with the keys of its
image. A kiosk must only trust the release keys of the project, which are not
defined yet: they will be kept out of the repository, and mkosi can sign with
a key in a hardware token (--secure-boot-key-source=provider:pkcs11).
Build¶
image/build.sh # production image
image/build.sh --profile online # production image with network
image/build.sh --profile test # test image, for the virtual machine only
The image is written to image/mkosi.output/: pandora-box.raw (or
pandora-box-test.raw, a GPT disk image), the unified kernel image (.efi)
and the list of installed packages (.manifest). The first build takes a few
minutes; the following ones reuse the installed packages (mkosi incremental
build, cached in the pandora-box-mkosi Docker volume) and take less than a
minute.
The cache is not rebuilt when image/requirements.txt or
image/mkosi.prepare.chroot change: rebuild it with image/build.sh -f
(docker volume rm pandora-box-mkosi removes it completely).
The version of the image is the date and time of its build, UTC, like the
serial of a signature set: 20261005143700 (--image-version=N overrides
it). It is in /etc/os-release (IMAGE_VERSION), in the labels of its
partitions and in the name of its unified kernel image. An update must have a
newer version than the running one.
Profile online¶
Without a profile, the image has no network configuration at all.
--profile online adds online signature updates from their sources (see
Signatures): systemd-networkd (DHCP on the
wired network), systemd-resolved, systemd-timesyncd, freshclam, the
pandora-box-update timer and a firewall that only lets the update service,
the log export to a SIEM (see SIEM) and NTP out
(image/mkosi.profiles/online/). Its postinst.chroot enables [updates]
in the configuration of the kiosk, and installs the credentials of
image/credentials.toml (outside git) in /etc/credstore.
cp image/credentials.toml.example image/credentials.toml # then the abuse.ch Auth-Key
image/build.sh --profile online
Warning
An image built with credentials must not be published: anyone with the image or the disk of the kiosk can read them.
Time¶
The clock of the kiosk dates its logs and scan reports, and decides whether
the certificates of the update servers and of the SIEM are valid. An online
kiosk synchronizes it with systemd-timesyncd, from the NTP servers of
NTP= in
image/mkosi.profiles/online/mkosi.extra/usr/lib/systemd/timesyncd.conf.d/50-pandora-box.conf
(empty by default), else those the DHCP server gives, else the Debian pool
(FallbackNTP=). To use the servers of the organization, set them there
before building the image:
[Time]
NTP=ntp1.example.org ntp2.example.org
Only systemd-timesyncd may send NTP requests (UDP 123) through the firewall;
timedatectl timesync-status shows the server in use. NTP is not
authenticated (timesyncd has no NTS): someone in the path of the requests
can shift the clock, so prefer NTP servers of the local network. Without the
profile, the kiosk keeps the time of its hardware clock (UTC).
Dependencies¶
Runtime dependencies are pinned with their hashes in image/requirements.txt.
After a change of the dependencies in pyproject.toml, regenerate it with
image/lock-requirements.sh, then rebuild the cache (image/build.sh -f).
Files¶
| Path | Role |
|---|---|
image/mkosi.conf |
Image definition: Debian 13, x86_64, systemd-boot, unified kernel image (UKI), packages |
image/mkosi.repart/ |
Partitions: ESP, two system slots (read-only root filesystem, its dm-verity hash and signature), data partition |
image/mkosi.images/initrd/ |
The initrd: the default initrd of mkosi, which restarts instead of opening an emergency shell, without the files a read-only root does not need |
image/mkosi.prepare.chroot |
Runtime dependencies in a virtual environment (/usr/lib/pandora-box), from image/requirements.txt (pinned with their hashes) |
image/mkosi.build.chroot |
pandora-box wheel, built from the repository without network |
image/mkosi.postinst.chroot |
Installs pandora-box, its configuration, systemd service, tmpfiles and logrotate files (packaging/), and the clamd settings |
image/mkosi.extra/ |
Files copied into the image: systemd presets (enabled and disabled units), /etc/fstab, growth of the data partition (/usr/lib/repart.d/), A/B updates (/usr/lib/sysupdate.d/, boot assessment), USBGuard policy, kernel settings (sysctl.d), firewall (nftables.conf), clamd sandbox |
image/mkosi.profiles/online/ |
Profile online |
image/mkosi.profiles/test/ |
Test profile, for the virtual machine tests only |
image/vm/ |
Virtual machine tests: corpus, QEMU driver, automated test |
image/build.sh, image/vm.sh |
Build and run in the container |
image/build-test.sh, image/package-update.sh |
Build the images of the virtual machine test; build a signed image update |
image/maintenance-key.sh |
Prepare a maintenance device |
What the image contains and how it is protected: see Image internals.