Docs Blog Forgejo Keycloak Postgres OpenFGA Pi-hole Pricing

Getting Started

1. Install the CLI 2. Login 3. Build and Push 4. Boot on GCP 5. Boot on Bare Metal

Guides

Authentication Pushing and Pulling Images Configuring Images Working with Hosts Working with GCP Working with Bare Metal latitude.sh OVHcloud Working with AWS Sealed Images Backups Tips and Tricks

CLI Reference

kheeper auth kheeper authorizations kheeper bots kheeper clouds kheeper contexts kheeper hosts kheeper images kheeper orgs kheeper push kheeper releases kheeper secureboot kheeper status

Sealed Images

A sealed release boots only what your org signed, and runs only the files it was built with. It carries a Unified Kernel Image signed with your org's Secure Boot key, and the UKI's kernel command line pins the composefs digest of the release's entire filesystem. With Secure Boot enforced, the chain is:

  1. Firmware checks your signature on systemd-boot.
  2. systemd-boot checks your signature on the UKI.
  3. The initramfs mounts only the filesystem whose digest the UKI names.
  4. The kernel checks every file it reads against that digest with fs-verity.

Change one byte of /usr and the file does not read. Swap the UKI and the firmware does not boot it. This is bootc's sealed image chain; Kheeper makes the keys, does the signing on your machine and gets the keys into the firmware.

Sealed images are new and bootc's composefs backend, which they run on, is still marked experimental. Today they work on bare metal installed over iPXE, and Kheeper has tested them on latitude.sh.

What you need

  • A Linux machine with podman to release from. Sealing runs a container there, next to your signing key.
  • A host installed with the composefs backend (step 2). An existing host can't be converted: bootc can't move a host between backends.
  • Images built FROM us.kheeper.com/public/composefs-base instead of public/base.
  • Access to the host's firmware setup to turn Secure Boot on, once.

Step 1 — Create your org's keys

kheeper secureboot init myorg

This makes the three Secure Boot keys — the platform key (PK), the key exchange key (KEK) and the signature database key (db) — on your machine, in ~/.config/kheeper/secureboot/myorg/, and registers their certificates with your org. The private keys never leave your machine. Only an org owner can register keys.

  • db.key signs every sealed release. Whoever releases needs it.
  • PK.key and KEK.key are needed only to change the keys. Keep them offline.

Check what's registered with kheeper secureboot show myorg.

Step 2 — Install a composefs host

Create the iPXE script with --composefs and boot it the usual way:

kheeper hosts ipxe create myorg/vault --composefs

The Fedora 45 installer puts the host on an ext4 root (composefs needs fs-verity, which xfs lacks), and it boots and registers itself. It isn't sealed yet: it boots an unsigned UKI, and Secure Boot is off.

Step 3 — Build on composefs-base

FROM us.kheeper.com/public/composefs-base:v0.1.0

RUN dnf install -y nginx && systemctl enable nginx

composefs-base is base with systemd-boot instead of grub and shim. It takes the same configuration, and you push it the same way.

A sealed release's kernel command line is fixed when it's sealed. Put kernel arguments in /usr/lib/bootc/kargs.d/ in your image.

Step 4 — Release it sealed

kheeper releases create myorg/vault:v1 \
  --image us.kheeper.com/myorg/app:v1 \
  --config-file config.json \
  --seal --activate

--seal puts together the release exactly as the host will run it, computes its composefs digest, and signs a UKI that commits to it with your db key. The first sealed release downloads your image once into ~/.cache/kheeper/seal; after that only the release's own layers move.

The release names your image by digest: the seal covers the exact image, so a tag that moved later must not change what the host gets.

Step 5 — The host enrols your keys

On its first sealed boot the host puts your signed systemd-boot on its EFI system partition and, if its firmware is in Setup Mode — no platform key enrolled, which is how bare metal on latitude.sh arrives — writes your db, KEK and PK into the firmware. kheeper hosts get myorg/vault then shows:

SecureBoot  off

off means your keys are enrolled but the firmware isn't enforcing them yet. setup means the host never left Setup Mode; see Troubleshooting.

Step 6 — Turn on Secure Boot

Enforcing Secure Boot is a firmware setting, so it's done once, by hand, in the server's BIOS setup — through the provider's remote console, or by asking their support. After the next reboot:

kheeper hosts get myorg/vault
SecureBoot  enforced

and the release shows as verified:

kheeper releases list myorg/vault
TAG          IMAGE                                CREATED              BOOTED               SEAL
v1 (active)  myorg/app@sha256:4f1c…               2026-10-11 09:12:44  2026-10-11 09:31:02  verified

verified means the host booted the digest the release was sealed to, with Secure Boot enforced. sealed alone means it hasn't yet.

Living with sealed hosts

  • Every release must be sealed. The registry refuses an unsealed release to a host that enforces Secure Boot, since the host couldn't boot it.
  • Only your db key boots. A UKI signed with any other key is refused by the firmware, and the host stops at the firmware's boot menu until someone picks an older entry at the console. releases create --seal refuses a key that isn't your org's registered db certificate.
  • Option ROMs. With only your key in db, firmware won't load add-in cards' UEFI drivers signed by Microsoft. If a host needs them, add Microsoft's UEFI CA with kheeper secureboot add-db myorg --cert microsoft-uefi-ca.pem. Hosts pick up the new db with their next sealed release. Be aware that this also lets anything else Microsoft's CA signed boot, such as a Linux distribution's shim.
  • The upgrade agent is sealed too. The poll layer that keeps a host on its active release is part of the sealed filesystem, so a sealed host keeps the version it was sealed with until its next release.
  • Sealed hosts always reboot fully into a new release. A soft reboot would keep the kernel the firmware verified for the previous release.
  • Each release is sealed per host. Hosts have their own configuration, so their own digest and their own UKI, about 125 MB each.

Troubleshooting

Symptom Cause
has not reported booting composefs The host was installed without --composefs, or hasn't checked in since it booted.
is not built for composefs The image isn't built FROM public/composefs-base.
SecureBoot setup after a sealed release The firmware was in Setup Mode but the keys didn't take. journalctl -u kheeper-secureboot on the host says why.
SecureBoot off and the BIOS has no Secure Boot option enabled Some boards also need CSM disabled ("Boot mode: UEFI") before Secure Boot can be enabled.
The host doesn't come back after enabling Secure Boot Something in the boot path isn't signed by your db key — most often an option ROM. Disable Secure Boot at the console, then see Option ROMs above.