Skip to content
The steps that need a physical board are not run by any automated test; the CM5 profiles and their images are.

Bring up a Raspberry Pi CM5

The Raspberry Pi Compute Module 5 is the SpaceOS reference board. SpaceOS owns its whole boot path there. The board verifies a signed boot image, and dm-verity checks the root filesystem block by block. A new release boots on trial and falls back on its own, and unikernels get real KVM under the Solo5 hvt tender. Use the CM5 to prove your deploy flow on the bench before you move to a flight computer.

The CM5 is a commercial part, neither radiation-qualified nor hardened against fault injection. Fault injection is an attack that disturbs the chip on purpose, with a voltage or clock glitch for example, to make it skip an instruction such as a signature check.

Prerequisites

  • A CM5 Dev Kit. It holds the module (BCM2712, four Cortex-A76 cores, 4 GB of RAM, 32 GB of eMMC), the IO board, a cooler and case, a 27 W USB-C power supply, and the USB-A to USB-C cable that flashing uses.
  • rpiboot on your computer. It presents the module's eMMC as a USB mass-storage device.
  • Gigabit Ethernet between your computer and the board.
  • The Space CLI, installed as the documentation home shows.

Choose a profile

Two content-addressed target profiles ship for the CM5. They make different trust claims, and a release signed for one does not serve the other:

ProfileBoot policyRollbackUse
cm5-devThe board checks the customer signature, and the policy can be reversed.A software trial and rollback record.Development, provisioning rehearsal, fault injection.
cm5The hash of the customer RSA key is written to one-time-programmable (OTP) memory, and the development key path is revoked.A discrete TPM holds a rollback floor that only rises, and seals the node's secrets.The locked deploy reference.

On cm5, the rollback floor is a TPM 2.0 NV counter index: the TPM increments it on command and can never decrement or reset it, even after the disk is wiped. To seal a secret is to encrypt it so that the TPM releases it only while chosen platform configuration registers (PCRs) hold expected values. A PCR can only be extended, never set: extending computes PCR := SHA-256(PCR || digest). Measuring a release means extending a PCR with its identity, and space-init extends PCR 11 with the identity of the release it booted.

Writing the key hash to OTP memory is permanent: a locked board cannot return to cm5-dev. Start with cm5-dev, and move to cm5 once your provisioning flow passes on the bench. A cm5 board is admitted only when its enrollment and attestation prove the OTP and TPM claims. Enrollment records a board's OTP key hash and TPM identity with the authority that admits it. Attestation is the board proving which release it booted: its TPM signs a quote over PCR 11 with an attestation key the verifier enrolled. Neither step ships in the current release. Measured boot evidence says when attestation arrives.

Verified boot sequence

The CM5 uses the Raspberry Pi native boot chain, not UEFI. Each stage checks the next:

  1. The boot ROM, the VideoCore firmware, and the EEPROM bootloader load boot.img and verify it against boot.sig with the customer RSA key.
  2. boot.img carries the kernel, the initramfs, the device tree, and the command line.
  3. The initramfs verifies the SpaceOS boot manifest. The manifest is a SUIT envelope, the IETF format for signed firmware updates, that lists the SHA-256 digest of the kernel, initramfs, device tree, root filesystem, and service set. An Ed25519 signature covers the envelope, and the 32-byte digest it signs is the release's identity.
  4. dm-verity opens the read-only root against the root hash pinned as verity.roothash= on the kernel command line inside the signed boot.img. It hashes each 4096-byte block with SHA-256 as it is read, checks it up the hash tree to that root hash, and fails the read on a mismatch. space-init then takes over.
  5. The runner launches each service only after checking its signature against the mission's pinned trust root.

The profile pins the firmware, bootloader, kernel, and device tree by digest, so a board with a different firmware set fails release planning.

Three keys sign at three levels, and none can stand in for another. The Raspberry Pi customer RSA key makes boot.img bootable. The Ed25519 release key binds the boot inputs into one manifest. The mission's Ed25519 and ML-DSA-65 identity, the one space keys manages, authorizes the services that run.

The chain has limits you should know before a review. The VideoCore firmware and the EEPROM code are closed and run before any SpaceOS code, so they sit inside the trusted base unmeasured. On the cm5 profile the TPM measures from the initramfs onward. dm-verity covers the read-only root; deployment state and keys are protected by the TPM-sealed key and the rollback counter instead.

Install the SpaceOS system image

  1. Connect the target with its profile and transport. --always-reachable suits a bench board on your network. A node reached over real passes names its orbit with --tle and its ground station with --station. With no --signing-key, the CLI generates a local bring-up key for the board:
Terminal window
space target connect cm5-bench --profile cm5-dev \
--endpoint ipn:7.1 --cla-address cm5-bench.local:4556 --always-reachable
  1. Build a release and print its plan. A release names a release signing identity; Port a Linux app shows how to generate one. The plan assembles the flashable cm5.img and prints the release descriptor: the composition, the target, its profile, the board, the kernel, the device tree, and the paths of cm5.img, boot.img, and boot.sig. It changes nothing on the board.
Terminal window
space build . -t app:release --release --signing-key release \
--rollback-index 1
space deploy app:release --target cm5-bench --plan
  1. Flash the first image by hand. Put the module in USB-boot mode as the CM5 IO board documentation describes, connect its USB-C port to your computer, and run rpiboot. The eMMC then appears as a disk on your computer. Write cm5.img to that disk with Raspberry Pi Imager or dd, leave USB-boot mode, and power-cycle the board:
Terminal window
sudo rpiboot

The image holds the firmware boot partition, the signed boot.img with its boot.sig, and a content store with an active and a recovery system release, so the board can fall back from its first boot onward.

  1. Deploy. Every later release crosses the network into the content store, boots on trial, and becomes the confirmed release only after its health checks pass. If the trial fails, the board returns to the last healthy release. The decision lives in the boot record, a mirrored record on a raw partition, authenticated with HMAC-SHA-256 under the board's 32-byte boot state key and framed by a CRC-32C. It names the confirmed release, the release on trial, and a last-known-good. Each trial boot spends one of three attempts, and a trial that runs out before its health checks confirm it boots the confirmed release again:
Terminal window
space deploy app:release --target cm5-bench
space show cm5-bench v1

space show reads the deploy record back: each phase, when it was reached, and the board's signed acknowledgements. The node signs its installed and activated acknowledgements with its Ed25519 acknowledgement key, the one space target connect records, and the ground checks them against the public half.

Rehearse on the bench before you lock the board

Run these checks on a cm5-dev board, in this order, before you write anything to OTP memory:

  1. Read back the flashed eMMC and compare its layout with the plan.
  2. Modify one byte of boot.img and confirm the board refuses to boot it. Corrupt the root filesystem and confirm dm-verity stops the boot.
  3. Cut power during a transfer, during a store write, during a trial boot, and during the confirmation, and confirm the board recovers at each point.
  4. Deploy a valid update, an update signed with the wrong key, and an update that fails its health check. Confirm that only the first becomes the confirmed release.
  5. Check that you can back up, rotate, and revoke the customer RSA key under your own custody procedure.

Enrolling the customer key hash in OTP memory and revoking the development key path are irreversible. Run them at the board with the Raspberry Pi provisioning tools, as a deliberate step of their own. space deploy never performs them.

Smoke tests

Each profile declares a smoke test and its pass criteria. cm5-dev declares cm5-dev-v1:

  • native-signed-boot: the board boots the signed boot.img.
  • modified-image-rejection: the board refuses a modified one.
  • dm-verity: the root filesystem is verified as it is read.
  • hvt-workload: a signed workload runs under the Solo5 hvt tender.

The locked cm5 profile declares cm5-v1, which adds otp-locked-boot, tpm2-sessions, nv-floor-replay-rejection, and sealed-secret-policy.

Run SpaceOS on Raspberry Pi OS instead

A CM5 can also keep Raspberry Pi OS (64-bit) and run SpaceOS as a set of services on it, the daemon install model. That board is a different target: it uses the hosted-linux profile, Raspberry Pi OS keeps its own boot path, and SpaceOS verifies only its own signed daemon bundle. hosted-linux declares runc alone. Never connect such a board with cm5-dev, whose digest asserts the SpaceOS boot chain.

  1. Flash Raspberry Pi OS Lite (64-bit) to the eMMC with rpiboot and Raspberry Pi Imager, then boot it and finish the first-run setup.
  2. Install the signed SpaceOS daemon bundle on the board. --issuer names the public key that signed it, and nothing is written until the bundle verifies:
Terminal window
sudo space target install --bundle ./space-bundle --issuer ./issuer.pem
  1. From your computer, connect the board as a target:
Terminal window
space target connect cm5-os --profile hosted-linux \
--endpoint ipn:8.1 --cla-address cm5-os.local:4556 --always-reachable