A collection of systemd portable services and system extensions (sysext) for Linux, built with reproducibility and cryptographic verification in mind.
This repository provides secure, self-contained, cryptographically-signed portable services and system extensions for various applications. Each service is built as a minimal, isolated root filesystem packaged into a dm-verity signed raw image.
- chrony - Network Time Protocol (NTP) client/server
- unbound - Validating DNS resolver
- tailscale - WireGuard-based VPN mesh network
- podman - Daemonless container engine
- apparmor - Mandatory Access Control (MAC) using Linux Security Modules
- hardened_malloc - Security-focused memory allocator (sysext)
- dm-verity signing - Cryptographic verification of root filesystem integrity
- Reproducible builds - Deterministic build process for verifiable outputs
- Minimal footprint - Stripped-down images with only essential dependencies
- Arch Linux base - Built from official Arch Linux containers
- Network-isolated signing - Private keys never exposed to network
- Parallel builds - Build all services concurrently
- Linux system with systemd
- Podman or Docker
- Just command runner (
just) - OpenSSL (for key generation)
- sudo access (for privileged operations)
First, generate the dm-verity signing keys (stored in _shared/ and gitignored):
just gen-verity-keysBuild a single portable service:
just build chronyOr build all services in parallel:
just build-allSign a built service with dm-verity:
just sign chronyOr sign all built services:
just sign-allPackage a service (build + sign):
just package chronyOr package everything:
just package-all# List all available commands
just list
# Check status of all services
just status
# Clean a specific service
just clean chrony
# Clean everything
just clean-allAfter building and signing, deploy with portablectl:
# Attach the portable service
sudo portablectl attach /path/to/chrony.raw --enable
# Start the service
sudo systemctl start chrony
# Check status
sudo systemctl status chrony
# Detach when done
sudo portablectl detach chronyFor sysext images like hardened_malloc:
# Copy to system extension directory
sudo cp hardened_malloc/outraw/hardened_malloc.raw /var/lib/extensions/
# Refresh extensions
sudo systemd-sysext refresh
# Verify
sudo systemd-sysext statusEach service follows this workflow:
-
Build Stage (
Containerfile)- Creates a minimal
/portableor/sysextroot filesystem - Installs only required runtime dependencies
- Strips documentation, caches, and unnecessary files
- Copies service-specific configuration from
rootfs/
- Creates a minimal
-
Signing Stage (
_shared/sign.Containerfile)- Calculates optimal partition sizes
- Creates dm-verity partitions using
systemd-repart - Generates cryptographic root hash
- Signs with private key (network disabled during key operations)
- Produces
.raw,.roothash, and.roothash.p7sfiles
.
├── Justfile # Build automation recipes
├── _shared/ # Shared signing infrastructure
│ ├── sign.Containerfile # Common signing logic
│ ├── verity.crt # Public signing certificate (gitignored)
│ └── verity.key # Private signing key (gitignored)
├── chrony/ # Example service
│ ├── Containerfile # Build definition
│ ├── rootfs/ # Service-specific files
│ ├── outdir/ # Extracted portable tree
│ └── outraw/ # Signed .raw image + signatures
└── ... # Other services
After building and signing, each service produces:
outdir/- Unsigned portable/sysext tree (for inspection)outraw/<service>.raw- Signed raw disk imageoutraw/<service>.roothash- dm-verity root hashoutraw/<service>.roothash.p7s- PKCS#7 signature
CONTAINER_RUNTIME- Container runtime to use (default: auto-detect podman/docker)BUILD_ELEVATE- Privilege escalation command (default:sudo)
To customize a service:
- Modify
<service>/Containerfileto adjust packages or build logic - Add configuration files to
<service>/rootfs/(overlaid onto/portable) - Rebuild:
just build <service> - Re-sign:
just sign <service>
- Private keys (
_shared/verity.key) are gitignored and should never be committed - Network isolation - Signing operations run with
--network=noneto prevent key exfiltration - Reproducibility - Builds should be deterministic for verifiable supply chain
- Minimal attack surface - Services include only runtime dependencies
- dm-verity - Read-only root filesystem with cryptographic integrity verification
Ensure your Containerfile creates either /portable or /sysext directory and populates it.
Run just gen-verity-keys first to generate signing keys.
Ensure the service has:
- Proper systemd unit files in
/portable/usr/lib/systemd/system/ - Correct naming convention for portable services
os-releaseorextension-releasemetadata
The signing process auto-calculates sizes based on content. If builds fail with size errors, check the partition calculation logic in _shared/sign.Containerfile.
To add a new service:
- Create a new directory:
mkdir -p <service>/rootfs - Add a
Containerfilefollowing the existing patterns - Add service configuration to
<service>/rootfs/ - Build and test:
just package <service>
This repository's build infrastructure is provided as-is. Individual services are subject to their respective upstream licenses.