2025-11-04 05:11:24 +00:00
2025-09-25 22:24:50 -04:00
2025-11-04 05:11:24 +00:00

Introduction

This code is used to produce the files needed to update citadel. The citadel-fetch command is installed in citadel and may be run manually to check for updates.

N.B. This update framework is at the moment not production ready. It defends against arbitrary installation and rollback attacks. It partially defends against endless data attacks. It does not defend against fast-forward or indefinite freeze attacks. This system is vulnerable to key compromise and does not provide a method to update the root key through the update mechanism. Further work needs to be done to prevent these issues. Consider using libraries from the Update Framework (TUF).

Usage

  1. Clone this repo at the top level of the citadel directory for the automagic create-signed-file subcommand to work.
  2. Run cargo run generate-update-keys to generate an update keypair. This keypair is used to sign the version manifest file (version.cbor).
  3. Replace the existing public key file by moving update_server_key.pub to meta-citadel/recipes-citadel/citadel-config/files/citadel-fetch/update_server_key.pub .
  4. Set a channel name at: meta-citadel/conf/distro/citadel-distro.conf . If you use the dev channel, you may skip the generation of update keys as the keys are hard-coded in the citadel-tools code.
  5. Run cargo run generate-image-keys to generate the image signing keypair for the channel defined in meta-citadel/conf/distro/citadel-distro.conf. This command will place the public key (<channel>.pub) and private key (<channel>.priv) in meta-citadel/recipes-citadel/citadel-keys/files/.
  6. Build the OS.
  7. Run cargo run create-signed-file. A version.cbor file will be generated.
  8. Finally, the files generated (version.cbor and images) must be uploaded/ Run cargo run upload-to-server to automatically upload all the files to the server.

To perform the upload manually, put this version.cbor file to the server at: {UPDATE_SERVER_NAME}/{CLIENT}/{CHANNEL}/. For example: https://update.subgraph.com/public/dev/ . Upload the image files to {UPDATE_SERVER_NAME}/{CLIENT}/{CHANNEL}/. For example: https://update.subgraph.com/public/dev/rootfs_1.0.0.img

More information is available in the help menu.

Basic structure

We host the files used by this program as a file server. The current hostname is update.subgraph.com.

An installed citadel server will automatically check for updates by reading the file at https://update.subgraph.com/{CLIENT}/{CHANNEL}/version.cbor

{CLIENT} will default to "public" but is read from the currently running system.

{CHANNEL} will default to "stable" but is read from the currently running system.

The version.cbor file is signed with Subgraph-controlled keys or equivalent client-controlled keys. The corresponding public key will be embedded in the rootfs image during build. The public key is called update_server_key.pub and is stored in /etc/citadel/ .

Image Signing Keys

To ensure the integrity and authenticity of OS images during the boot process, each image is signed with a channel-specific key pair.

  • Generating Keys: Use the cargo run generate-image-keys command to generate a new key pair for the channel specified in meta-citadel/conf/distro/citadel-distro.conf (e.g., CITADEL_CHANNEL = "test").
  • Key Locations:
    • The public key (<channel>.pub) is placed in meta-citadel/recipes-citadel/citadel-keys/files/ and is embedded into the OS image during the build. This public key is used by citadel-boot on the target system to verify the image header's signature.
    • The private key (<channel>.priv) is also placed in meta-citadel/recipes-citadel/citadel-keys/files/. It is crucial to keep this private key secret and local to your build environment. It is used by the citadel-mkimage tool during the image creation process to sign the image header.
  • Verification: During boot, citadel-boot reads the embedded public key and verifies the signature of the image header. If the signature is invalid, the boot process will fail.

Update File Structure

version.cbor file

The version.cbor file is the only file read during update and contains all information required for the user's system to decide to update or not as well as where the update files are located on the server. This file is merely a container which provides a cryptographic guarantee that the serialized_citadel_version struct (which contains the actual information we need to disseminate) is authentic.

  1. serialized_citadel_version (CitadelVersionStruct): the serialized data containing the actionable information we need to read to make decisions on the update
  2. signature: the ed25519 signature of the above serialized data
  3. signatory: the name of the org or person who produced the version.cbor file

CitadelVersionStruct

  1. client: the Subgraph client making the request
  2. channel: whether this is a production release or other
  3. component_version (Vec): a vector containing structures called ComponentVersion which contain the information on each component's version number and the location of the download file of the component
  4. publisher: the name of the org or person who released this update

ComponentVersion

  1. component: the name of the image we may update. Either the rootfs, the kernel or the extra image
  2. version: a string which contains the semver describing the version of the component
  3. file_path: where on the update server can the file be downloaded from. This is relative to the domain name we are currently fetching from

Channel list

Finally, we place a channel list in the directory of every client directory called channels.cbor. Create a json file with structure:

{ "channels": ["stable", "dev", "beta"] }

You can run the json-to-cbor function subcommand in the update-generator tool to create the cbor file.

Description
No description provided
Readme 93 KiB
Languages
Rust 100%