Secure Realms during boot using Arm Confidential Compute Architecture (CCA) BootSync
Introduction
Understand Arm CCA BootSync and the Boot Injection protocol
Configure UEFI Secure Boot and disk encryption in Arm CCA Realms
Next Steps
Secure Realms during boot using Arm Confidential Compute Architecture (CCA) BootSync
What you will configure and validate
You’ll configure and validate both failure and success cases:
- First, you’ll launch a Realm without injecting any boot data to see that the firmware can run successful attestation and ask for BootSync data.
- Next, you’ll add the variable data file. BootSync completes, UEFI Secure Boot is enabled, and the unsigned kernel is rejected.
- Then, you’ll sign the Realm kernel and validate Secure Boot. The Realm boots with UEFI Secure Boot enabled, and the Secure Boot UEFI variable reports
1. - Finally, you’ll encrypt the Realm root file system and use BootSync secret data to provide UEFI variables and the unlock passphrase during early boot. You’ll unlock the encrypted file system.
You’ll run the User Context service in a Docker container and launch CCA Realms on an Arm Fixed Virtual Platform (FVP) in a separate Docker container.
You’ll use two terminals:
- In the User Context terminal, you’ll run the User Context service. This service represents the Realm initiator and decides whether to release BootSync data.
- In the FVP terminal, you’ll run the Arm CCA FVP and launch Realm virtual machines using
lkvm-bootsync.
Install dependencies
Set up Docker’s apt repository so you can pull and run the pre-built containers:
# Add Docker's official GPG key:
sudo apt-get update
sudo apt-get install -y ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
# Add the repository to APT sources:
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
Install Docker packages for the runtime used by both the User Context and FVP containers, and optionally install git for inspecting linked source files:
sudo apt-get install -y git docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
Add your user name to the Docker group so you can run Docker without sudo:
sudo usermod -aG docker $USER
newgrp docker
The group change applies to new shells; newgrp docker updates the current shell.
Start the User Context service
In the User Context terminal, pull the Docker image with the pre-built User Context service. Then, run the container:
docker pull armswdev/cca-learning-path:cca-key-broker-v4
docker network create cca-trustee
docker run --rm -it --network cca-trustee --name user-context armswdev/cca-learning-path:cca-key-broker-v4
The cca-trustee Docker network is important. It lets the FVP container resolve the User Context service by container name, user-context, when lkvm-bootsync later uses --service-ip user-context.
In the User Context terminal, start the User Context service inside the running container using the run-user-context-service.sh script.
The User Context service is part of the
EDK2
project.
Created specifically as a proof of concept, it’s intentionally small and not designed for production use.
When the script starts for the first time, it generates Secure Boot signing certificates and creates a Provisioning Data file. The Provisioning Data is a binary file generated by GenPd.py script. The file contains EFI variable definitions required for enabling UEFI Secure Boot.
You’ll be asked for a passphrase for the Secure Boot signing certificates. Remember it because you’ll use it again when signing the Realm kernel.
./run-user-context-service.sh
Validate BootSync failure without boot data
With the User Context service running in the User Context terminal, open the FVP terminal.
Pull the Docker image with the pre-built FVP and CCA reference software stack. Then, run the container connected to the same Docker network:
docker pull armswdev/cca-learning-path:cca-simulation-v4
docker run --rm -it --network cca-trustee armswdev/cca-learning-path:cca-simulation-v4
Within your running container, launch the run-cca-fvp.sh script to run the Arm CCA pre-built binaries on the FVP:
./run-cca-fvp.sh
The run-cca-fvp.sh script uses the screen command to connect to the different UARTs in the FVP.
When the host Linux boots, log in:
Enter root as the username:
Welcome to the CCA host
host login: root
(host) #
Change directory to /cca and use lkvm-bootsync to launch a guest Linux in a Realm:
cd /cca
./lkvm-bootsync run --realm --disable-sve --irqchip=gicv3-its \
--firmware KVMTOOL_EFI_SECUREBOOT.fd \
-c 1 -m 512 --no-pvtime --pmu \
--disk guest-disk.img --virtio-transport pci \
--service-ip user-context \
--service-port 1080 \
--realm-pv ARMCCA01
The BootSync-specific parameters are:
--service-ip user-contextpoints the VMM to the User Context container on the Docker network.--service-port 1080uses the default User Context service port.--realm-pv ARMCCA01sets the Realm Personalization Value (RPV). The User Context uses this value as a file-name prefix when looking for BootSync data, such asARMCCA01_VAR.datandARMCCA01_SEC.dat.
After running the command, you’ll see the Realm boot.
The output is similar to:
Shell> bootaa64.efi root=/dev/vda2 acpi=force ip=on
EFI stub: Booting Linux Kernel...
EFI stub: Generating empty DTB
EFI stub: Exiting boot services...
UEFI Secure Boot isn’t mentioned in the EFI messages. This is expected because you’ve not yet provided the UEFI variable data that enables Secure Boot.
After the Realm boots, log in using the root again as the username:
Welcome to the CCA realm
realm login: root
(realm) #
Use the efivar utility to check the Secure Boot EFI variable. A value of 0 confirms that Secure Boot is not enabled:
mount -t efivarfs efivarfs /sys/firmware/efi/efivars
efivar -p -d -n {global}-SecureBoot
__output__0
Stop the Realm:
poweroff
In the User Context terminal, you can see that the Realm firmware requested a Variable Data file, but the file is missing:
INFO: BIB Variable Data Requested
FileName = ARMCCA01_VAR.dat
Error: ARMCCA01_VAR.dat Not found!
Error: Boot Sync failed.
Info: Session State: ConnectionEstablished
Info: Attestation State: AttSuccess
Info: BootSync State: BootSyncNotDone
This is an intentional failure: BootSync completed enough of the protocol to request boot information, but the User Context had no ARMCCA01_VAR.dat file to release.
Next, you’ll add the missing Boot Information Block data and repeat the launch.
Pass UEFI variable data and validate unsigned kernel rejection
In the User Context terminal, stop the service by pressing Ctrl-C.
The RPV and file names used here are details of this Learning Path’s reference implementation. One User Context service can support multiple Realms by using the RPV as a file-name prefix. A Realm launched with --realm-pv ARMCCA01 requests files that start with ARMCCA01. If the matching files are missing, BootSync can establish a session and complete attestation, but the User Context can’t provide the requested boot information.
Copy the generated Provisioning Data file to a Realm variable data file with the name <RPV>_VAR.dat:
cp SecureBoot/SecBootCert/pd.bin SecureBoot/ARMCCA01_VAR.dat
Because you launched the Realm with --realm-pv ARMCCA01, the User Context service looks for ARMCCA01_VAR.dat.
Create a Secret Data file with a test string that’ll be shared with a Realm using the same RPV:
echo "My Realm secret data" > SecureBoot/ARMCCA01_SEC.dat
In the User Context terminal, relaunch the User Context service:
./run-user-context-service.sh
In the FVP terminal, relaunch the Realm with the same RPV:
cd /cca
./lkvm-bootsync run --realm --disable-sve --irqchip=gicv3-its \
--firmware KVMTOOL_EFI_SECUREBOOT.fd \
-c 1 -m 512 --no-pvtime --pmu \
--disk guest-disk.img --virtio-transport pci \
--service-ip user-context \
--service-port 1080 \
--realm-pv ARMCCA01
Keeping the same --realm-pv ARMCCA01 is what links the Realm request to the files you created.
In the User Context terminal, you can see that attestation succeeded and BootSync completed:
Info: Received FIN. Disconnecting.
Info: Session State: UnConnected
Info: Attestation State: AttSuccess
Info: BootSync State: BootSyncCompete
This means the User Context released the Boot Information Blocks to the Realm firmware.
The Realm now fails to boot the Linux kernel:
Shell> bootaa64.efi root=/dev/vda2 acpi=force ip=on
Script Error Status: Access Denied (line number 1)
This failure is expected. The same kernel booted before Secure Boot was enabled, but now the firmware enforces the Secure Boot variables injected by BootSync. The kernel image isn’t signed yet, so firmware rejects it.
Stop the realm by running reset in the EFI shell prompt:
reset
Next, you’ll launch a Realm with a signed kernel image.
Sign the kernel and verify Secure Boot
In the FVP terminal, use the sign_guest_kernel.sh script to sign the Realm Linux kernel with the Secure Boot certificate generated earlier by the User Context setup script. When prompted, enter the passphrase you used for the Secure Boot signing certificates:
sign_guest_kernel.sh
__output__Signing kernel image:
__output__Enter PEM pass phrase:
Signing Unsigned original image
In the FVP terminal, relaunch the Realm. Use the same User Context service, service port, and RPV so the Realm receives the same Secure Boot variable data:
cd /cca
./lkvm-bootsync run --realm --disable-sve --irqchip=gicv3-its \
--firmware KVMTOOL_EFI_SECUREBOOT.fd \
-c 1 -m 512 --no-pvtime --pmu \
--disk guest-disk.img --virtio-transport pci \
--service-ip user-context \
--service-port 1080 \
--realm-pv ARMCCA01
The output is similar to:
Shell> bootaa64.efi root=/dev/vda2 acpi=force ip=on
EFI stub: Booting Linux Kernel...
EFI stub: UEFI Secure Boot is enabled.
EFI stub: Generating empty DTB
EFI stub: Exiting boot services...
The EFI messages show that UEFI Secure Boot is enabled.
After the Realm boots, log in using root as the username:
Welcome to the CCA realm
realm login: root
(realm) #
Use efivar to check the Secure Boot EFI variable. A value of 1 confirms that Secure Boot is enabled:
mount -t efivarfs efivarfs /sys/firmware/efi/efivars
efivar -p -d -n {global}-SecureBoot
__output__1
You can also see that EFI SetupMode is disabled:
efivar -d -p -n {global}-SetupMode
__output__0
Using
securityfs
, you can
access the secret data shared with the Realm from under the GRUB_EFI_DISKPASSWD_GUID entry:
mount -t securityfs none /sys/kernel/security
cat /sys/kernel/security/secrets/coco/736869e5-84f0-4973-92ec-06879ce3da0b
__output__My Realm secret data
Stop the Realm:
poweroff
You’ve successfully started a Realm with UEFI Secure Boot configured and enabled using Arm CCA BootSync.
Encrypt the root file system and update secret data for disk unlock
You can use the secret data shared with a Realm using Arm CCA BootSync to provide access to encrypted file systems. You’ll now encrypt the root file system, observe a failed unlock when the wrong secret is available, and update the BootSync secret so the Realm can unlock the disk during boot.
Encrypt the root partition
There are different ways to provide a Realm with access to encrypted partitions using Arm CCA BootSync. For example:
Use an updated version of Grub as a boot loader. This version of Grub uses the secret data to open an encrypted partition and load kernel and
initrdimages from it.The following is an example Grub config file:
echo 'Mounting encrypted disk...' cryptomount -s efisecret (hd0,gpt2) echo 'Loading Kernel...' linux (crypto0)/bootaa64.efi echo 'Loading InitRD...' initrd (crypto0)/initrd.gz echo 'Booting Linux...' bootWith the current Grub implementation of Arm CCA BootSync support, the booted operating system has access to the
initramfsonly.Use an init script in an
initrdimage to unlock and mount the encrypted partition. You’ll use this approach in the next step.
In the FVP terminal, use the encrypt_rootfs.sh script to encrypt the root partition in the Realm disk image and add an initrd image to the kernel parameters.
You’ll be asked for a passphrase to encrypt the root partition. Use a memorable test passphrase and keep it available, because you’ll later write the same value into ARMCCA01_SEC.dat for BootSync to release.
You can use a maximum of 512 characters of uppercase or lowercase letters, numbers, and symbols. Ignore the warning message because you’re using small partitions.
encrypt_rootfs.sh
__output__Resizing root file system to accommodate minimal LUKS2 header
__output__resize2fs 1.47.3 (8-Jul-2025)
__output__Resizing the filesystem on /dev/loop0p2 to 260096 (1k) blocks.
__output__The filesystem on /dev/loop0p2 is now 260096 (1k) blocks long.
__output__
__output__tune2fs 1.47.3 (8-Jul-2025)
__output__Encrypting root partition
__output__Enter passphrase for LUKS2-temp-4684d923-d8b7-4371-8bb2-f8667bfb0498.new:
__output__WARNING: keyslots area (1015808 bytes) is very small, available LUKS2 keyslot count is very limited.
__output__Enable Initrd image
Validate failed disk unlock
In the FVP terminal, relaunch the Realm. At this point, ARMCCA01_SEC.dat still contains the test string from the previous Secure Boot step, not the disk encryption passphrase:
cd /cca
./lkvm-bootsync run --realm --disable-sve --irqchip=gicv3-its \
--firmware KVMTOOL_EFI_SECUREBOOT.fd \
-c 1 -m 512 --no-pvtime --pmu \
--disk guest-disk.img --virtio-transport pci \
--service-ip user-context \
--service-port 1080 \
--realm-pv ARMCCA01
In the Realm boot log, you can see that the init script failed to unlock the encrypted partition:
[ 32.761651] Run /init as init process
Detecting LUKS containers in vda1-2
/dev/vda1 is not LUKS
/dev/vda2 is LUKS, attempting unlock.
No key available with this passphrase.
Failed to unlock LUKS partition. Has BootSync been completed?
FAIL finding root on LUKS, loading BusyBox...
can't run '/etc/init.d/rcS': No such file or directory
Please press Enter to activate this console.
Press Enter to get into the Realm shell.
In the shell, check that only initramfs is mounted and that you can’t mount /dev/vda2 directly:
df -h
__output__Filesystem Size Used Available Use% Mounted on
__output__devtmpfs 174.4M 0 174.4M 0% /dev
mount -t auto /dev/vda2 /cryptroot
__output__mount: mounting /dev/vda2 on /cryptroot failed: Invalid argument
Stop the Realm:
poweroff
The init script failed to unlock the encrypted partition because the Secret Data file doesn’t contain the encryption passphrase yet.
Update the BootSync secret and validate successful disk unlock
Now, update the BootSync secret.
In the User Context terminal, stop the service by pressing Ctrl-C.
Save the encryption passphrase into the Secret Data file. Use echo -n so the file contains only the passphrase and no trailing newline character:
ROOTFS_PASSPHRASE='replace-with-the-passphrase-you-used-for-encrypt_rootfs'
echo -n "$ROOTFS_PASSPHRASE" > SecureBoot/ARMCCA01_SEC.dat
In the User Context terminal, relaunch the User Context service:
./run-user-context-service.sh
In the FVP terminal, relaunch the Realm with the same RPV:
cd /cca
./lkvm-bootsync run --realm --disable-sve --irqchip=gicv3-its \
--firmware KVMTOOL_EFI_SECUREBOOT.fd \
-c 1 -m 512 --no-pvtime --pmu \
--disk guest-disk.img --virtio-transport pci \
--service-ip user-context \
--service-port 1080 \
--realm-pv ARMCCA01
In the Realm boot log, you can see that the init script successfully unlocked and mounted the encrypted partition:
[ 233.501627] Run /init as init process
Detecting LUKS containers in vda1-2
/dev/vda1 is not LUKS
/dev/vda2 is LUKS, attempting unlock.
*** LUKS partition unlocked, switching root ***
After the Realm boots, log in using root as the username:
Welcome to the CCA realm
realm login: root
(realm) #
Check that the unlocked encrypted partition /dev/mapper/cryptroot is mounted as root:
df -h
__output__Filesystem Size Used Available Use% Mounted on
__output__devtmpfs 174.4M 0 174.4M 0% /dev
__output__/dev/mapper/cryptroot
__output__ 227.9M 93.0M 118.2M 44% /
__output__tmpfs 194.8M 0 194.8M 0% /dev/shm
__output__tmpfs 194.8M 40.0K 194.8M 0% /tmp
__output__tmpfs 194.8M 32.0K 194.8M 0% /run
__output__cgroup 194.8M 0 194.8M 0% /sys/fs/cgroup
Stop the Realm:
poweroff
Stop the FVP:
poweroff
What you’ve accomplished
You’ve now used Arm CCA BootSync to enable UEFI Secure Boot and unlock an encrypted root file system for a Realm.
You can extend the workflows covered in this Learning Path to provide trusted early-boot data for your own Realm workloads.