RAUC v1.7 Released
Better late than never: Finally, here is our blog post for RAUC v1.7, which was released a month ago.
In its 1.7 release, RAUC comes with two much-requested features: Built-in HTTP(S) streaming support and bundle encryption. Both are built on the capabilities provided by the 'verity' bundle format and cannot be supported by the legacy 'plain' format.
We will use the release as an opportunity to give a deep-dive into the technology, requirements and purposes of streaming and encryption. But let's have a short glance at a few other notable changes, first:
PR #907 added a RAUC configuration option to allow partial chain verification for bundles.
This can be interesting for use-cases where one does not want to trust the entire PKI but only one or several sub-trees. This can be used to have a single company PKI but different sub-trees for various products or product variants where one wants to allow only the installation of bundles signed for the specific product or product variant.
To enable this, set allow-partial-chain=true in your system.conf and place the intermediate certificate(s) in the keyring. For details, see the documentation.
Due to their implementation model, the progress information emitted by RAUC so far emitted 100% multiple times during installation finalization. As this could cause confusion, this was fixed in #784 to report 100% only for the very last progress update.
A common configuration error for RAUC is a compatible mismatch. Until v1.7, the error emitted was quite meaningless:
Installation error: Compatible mismatch.
Since v1.7 we now print a more helpful error message instead:
Installation error: Compatible mismatch: Expected 'demo platform' but bundle manifest has 'demo platfrom'
Streaming Updates Over HTTP
Although RAUC has some basic HTTP download functionality, it so far focused on installing from update bundles on local storage. When not using casync, an update with a bundle provided by a remote web server was a two-step process: First download the bundle to local storage (e.g. by rauc-hawkbit-updater) and then install it using RAUC.
But, even when most modern embedded systems are not that short on storage, the need for reserving extra space for a temporary update image is still quite inefficient.
RAUC's new built-in HTTP streaming removes the need for intermediate local storage. The bundle data (i.e. file system images) is read on-demand while writing it to its destination device(s) on the target. No intermediate storage is required.
To build RAUC with streaming support, you must enable the network and the streaming option during configuration:
$ ./configure --enable-network --enable-streaming [..]
Also note that your kernel must have CONFIG_BLK_DEV_NBD enabled as either module or compiled-in.
The RAUC command line tool (as well as the InstallBundle() D-Bus method) then allows starting an installation directly from a remote URL:
# rauc install https://example.com/update-bundle.raucb
How Does This Work Internally?
The HTTP streaming support leverages another well-established Linux kernel feature, the network block device (NBD). NBD provides access to a remote block device via a standardized network protocol and a client/server architecture. The Linux kernel implements the NBD client and allows transparent access via a /dev/nbdN block device.
In RAUC, an unprivileged helper process implements the NBD server part that converts NBD read requests to HTTP range requests. This way, RAUC has random access to a remote bundle.
Since almost all common web servers (and CDNs) support range requests, the requirements on server side are actually quite simple.
Streaming supports HTTP/1.1 and HTTP/2, basic authentication (user/password), HTTPS (with TLS-based client authentication) and custom headers.
With its use of signed bundles, RAUC is explicitly designed to not require any trusted/secure communication channel or infrastructure. For example, this makes it possible to use a USB memory stick as well as untrusted cloud storage as update source.
However, in some scenarios though, it's not enough to ensure the authenticity of the bundle, but also that it cannot be extracted or examined by third party. Sensitive application code or calibration data might be part of an update and should be protected during transport.
This is where the new bundle encryption comes into play. With 1.7, RAUC allows encrypting a bundle for one or more different recipients. An encrypted bundle can still be streamed, which makes it possible to use the same bundle for both the USB and the untrusted cloud storage cases above.
Encrypted bundles introduce a third bundle format: the crypt bundle. Just like for the legacy plain format and the recommended verity format, you can specify the bundle format to use in your bundle's manifest:
The actual encryption is designed as a two-step process as often the entity that builds the system software and thus generates the bundle and the entity that manages the per-device keys use independent infrastructure.
Thus in a first step, one can build a so-called 'unencrypted crypt bundle', which means that the payload is already (symmetrically) encrypted, but with a random unencrypted key:
$ rauc bundle [..] unencrypted-crypt-bundle.raucb
In a second step, the CMS structure holding the signature and the bundles manifest can be asymmetrically encrypted for one or multiple recipients:
$ rauc encrypt [..] --to recipients.pem unencrypted-crypt-bundle.raucb encrypted-crypt-bundle.raucb
How Does This Work Internally?
This (and how to get started with bundle encryption) was described in my blog post Tutorial: Start With RAUC Bundle Encryption Using meta-rauc already in chapter 'Implementation Background'. Refer to this for more information.
What Will Come Next?
This is of course not always predictable, as contributions are community or customer project driven, but we can already give a preview of some features that are already being worked on or close to being merged:
- Support for desync (as an alternative implementation of the casync protocol) which is used together with RAUC on Valve's Steam Deck finally made its way into the master branch.
- Support for atomic bootloader updates for support ROM loaders that support fallback images at fixed addresses/offsets (instead of a partition) was contributed and merged in PR #918.
- We are working on built-in incremental updates, also leveraging the new built-in streaming capabilities. The draft PR #936 contains working code, but still needs review and documentation. A preparation PR that supports the incremental image property is already part of RAUC 1.7 to ease compatibility.
- There has been ongoing discussion and also promising PRs to enhance the progress handling of RAUC on various levels (better partitioning, more fine-grained updates, etc.)
Even more ideas and PRs are in progress already. Stay tuned and feel invited to participate and guide the direction of RAUC's development, for example by joining our Matrix channel.
"Getting things off the ground" could be the motto for the v1.9 release of RAUC. The support for custom metadata in the manifest got a step further, a new, more flexible, D-Bus API for bundle inspection paved the way for obtaining more detailed information, and a new manifest hash marks the first of several planned changes for configurable event logging. However, one of the most invasive changes happened under the hood: We have started the transition from autotools to meson as a build system.