Install with Yocto and RAUC¶
For manufacturers who build their own gateway image with Yocto and update it with RAUC. One agent goes into your image: the Bootstrap-Agent, one service that runs as its own unprivileged user. It leaves starting your software, the LEDs and any data deletion to you. An overview is on Gateway overview.
Release candidate
This page describes cproto-v0.2.0-rc.2, a release candidate. The recipe
inside this release still pins the previous candidate (cproto-v0.2.0-rc.1):
set RELEASE, PV and the two SHA-256 pins in it to this release, using the
table below, before you build an image with it. The recipe in our layer
already pins this release.
What you get¶
A signed release archive per version, three files: the archive
bootstrap-agent-cproto-v0.2.0-rc.2-linux-armv7.tar.gz, its signature (.sig) and its
checksum (.sha256). The archive holds:
| Path in the archive | What |
|---|---|
bootstrap-agent |
the agent (armv7, linked dynamically) |
systemd/bootstrap-agent.service |
the one service unit |
examples/ |
the .path and .service examples from Start your software and confirm |
tmpfiles/bootstrap-agent.conf |
creates the state directory and the socket directory |
env/bootstrap-agent.env |
configuration default |
local-api-v1.openapi.yaml, wire-v1.md |
the local interface contract and the platform contract |
VERSION, CHECKSUMS.sha256 |
the version, and a checksum for every other file |
The archive holds no installer script, and the agent downloads no program: it only fetches its configuration.
Download¶
The three files of the release cproto-v0.2.0-rc.2, no account needed:
https://packages.pxdc.io/bootstrap-agent/cproto-v0.2.0-rc.2/bootstrap-agent-cproto-v0.2.0-rc.2-linux-armv7.tar.gz
https://packages.pxdc.io/bootstrap-agent/cproto-v0.2.0-rc.2/bootstrap-agent-cproto-v0.2.0-rc.2-linux-armv7.tar.gz.sig
https://packages.pxdc.io/bootstrap-agent/cproto-v0.2.0-rc.2/bootstrap-agent-cproto-v0.2.0-rc.2-linux-armv7.tar.gz.sha256
| File | SHA-256 |
|---|---|
bootstrap-agent-cproto-v0.2.0-rc.2-linux-armv7.tar.gz |
fad9e36e7b3b412f198effcda621d55cab0c4963aa98c8d1f8ba332c8ee65700 |
bootstrap-agent-cproto-v0.2.0-rc.2-linux-armv7.tar.gz.sig |
ce2d4a9d8ea9a99c707ce93f4640a0274c0e44d3252bc6ba825f073b32b117a8 |
bootstrap-agent-cproto-v0.2.0-rc.2-linux-armv7.tar.gz.sha256 |
fc4a8295998ceb8030e6c7ebb1f7ae4deefc21f2427c2fcc4a997f9ba1db2b47 |
Check the signature¶
The signature is Ed25519, made with the agent's own release key. The key is stable: there are no per-release keys.
You need sha256sum and OpenSSL 3. Older versions do not know the option
-rawin that the check uses: OpenSSL 1.1.1 and LibreSSL 3.3 stop with
unknown option -rawin; OpenSSL 3.5 and 3.6 work.
1. Save the public key as wlpc-agent-ed25519.pub. It is also in our
Yocto layer under the same name.
-----BEGIN PUBLIC KEY-----
MCowBQYDK2VwAyEAN8+mCK4/qSV4xO6uFNHrc5+8Dje5wK609NI7WEGqYa4=
-----END PUBLIC KEY-----
2. Compare the fingerprint with the one below, which is published on this site, not in the download directory, and with the one support sends you separately. A key fetched from the same place as the archive proves nothing by itself; the second source is what makes the check worth anything.
openssl pkey -pubin -in wlpc-agent-ed25519.pub -outform DER | sha256sum
# 79c12a4d7b4cc3868129a0afac587fd2441246e5c61382bd8221bc2ec52d402a
3. Check the three files you downloaded, in one directory:
sha256sum -c bootstrap-agent-cproto-v0.2.0-rc.2-linux-armv7.tar.gz.sha256
openssl pkeyutl -verify -pubin -rawin -inkey wlpc-agent-ed25519.pub \
-sigfile bootstrap-agent-cproto-v0.2.0-rc.2-linux-armv7.tar.gz.sig \
-in bootstrap-agent-cproto-v0.2.0-rc.2-linux-armv7.tar.gz
Signature Verified Successfully is the only good answer. A changed byte in
the archive, or a signature made with another key, is refused. Then check the
files inside against CHECKSUMS.sha256:
mkdir agent-files
tar -xzf bootstrap-agent-cproto-v0.2.0-rc.2-linux-armv7.tar.gz -C agent-files
(cd agent-files && sha256sum -c CHECKSUMS.sha256)
The Yocto recipe¶
The recipe bootstrap-agent-c_1.0.bb in our layer downloads the archive over
HTTPS, refuses it unless its SHA-256 matches the one pinned in the recipe,
checks the signature against the pinned key before unpacking, checks
CHECKSUMS.sha256, and installs:
| Path | What |
|---|---|
/usr/bin/bootstrap-agent |
the agent |
/usr/lib/systemd/system/bootstrap-agent.service |
the one unit, enabled by a preset |
/usr/lib/wlpc/bootstrap-agent.env |
configuration default |
/usr/lib/tmpfiles.d/bootstrap-agent.conf |
creates the state directory and the socket directory |
The recipe also creates the user bootstrap-agent and the groups tss and
wlpc. It installs only that one unit, and not the examples. Your software
writes /run/wlpc as a member of the group wlpc; the archive's tmpfiles rule
creates that directory for the group, see
Who may write /run/wlpc.
Choosing a new version means changing the version and the two hashes in the
recipe; nothing else changes unseen.
Libraries and known problems of the recipe¶
The agent is linked dynamically, so your image must provide these libraries,
and the recipe lists them as dependencies: libtss2-esys.so.0,
libtss2-mu.so.0, libcurl.so.4, libssl.so.3, libcrypto.so.3,
libjson-c.so.5 and glibc (the highest symbol version the binary needs is
GLIBC_2.34).
What was and was not verified for the recipe:
- Verified: download, hash pin, signature check and
do_installfrom an empty build directory, against the recipe on the development branch, with the build dependencies removed. - Open problem 1, the work directory. In a full test build (Yocto
scarthgap,
qemuarm), the recipe stopped indo_package:Sset to${WORKDIR}/pkgalso hides${WORKDIR}/pkgdatafrom the tool that tracks file ownership. A test copy with another directory name got past it. The recipe is not changed yet. - Open problem 2, a version tag of the curl library. After that, the
package check (
file-rdeps) reported that the program needslibcurl.so.4(CURL_OPENSSL_4)and no package provides it: the program was linked against a curl library with versioned symbols, the one built by Yocto has none. Not solved; whether the program runs against that library was not measured. - Not done: no image build (
do_rootfs) and no start on a Yocto image.
Updates with RAUC¶
The agent writes only /etc/iot-config (its state) and
/run/bootstrap-agent; everything else can be read-only. The unit says
RequiresMountsFor=/etc/iot-config, so the agent starts after that mount. The
state must survive reboots and RAUC slot switches:
- If
/etclies on the data partition, nothing more is needed. - If
/etcon your image is part of the root file system, bind-mount/etc/iot-configfrom the data partition. systemd only accepts the mount unit under the name derived from the path,etc-iot\x2dconfig.mount(systemd-escape -p --suffix=mount /etc/iot-config); under any other name it ignores the unit and the state stays in the slot. - A state directory inside the slot is empty after the switch, and the device provisions itself again.
This agent has not been run through a RAUC A/B switch or a rollback. Test it on your image.
Settings¶
The platform address goes into /etc/bootstrap-agent/agent.env, never into
the image, so the same image works with your own platform instance. The unit
reads the defaults from /usr/lib/wlpc/bootstrap-agent.env first and this
file second.
| Setting | Required | Meaning |
|---|---|---|
BOOTSTRAP_AGENT_URL |
Required | The platform's address for gateways. Without it the agent starts and serves its local interface, but reports state: error. |
BOOTSTRAP_AGENT_TRUST_BUNDLE |
Optional | Empty: check the platform's certificate against the image's list of trusted authorities. The shipped default points to /etc/bootstrap-agent/platform-ca.pem; if that file does not exist, the agent logs reading trust bundle and cannot reach the platform. Only use a file if support gave you one. |
BOOTSTRAP_AGENT_NTP_SERVERS |
Optional | Time servers, comma separated. The agent waits for the clock to agree with one of them before it opens any TLS connection. Empty: it only rejects an obviously unset clock. |
BOOTSTRAP_AGENT_AK_HANDLE |
Optional | The TPM handle of the attestation key, see The TPM. |
The TPM¶
The agent keeps its attestation key (AK) as one persistent object in the TPM, so a start reads the key instead of deriving it again.
- One handle, set by you.
BOOTSTRAP_AGENT_AK_HANDLEin/etc/bootstrap-agent/agent.env: a persistent handle in the TPM's owner range. Empty uses the default handle, which we agree with you.offkeeps the key transient. - Only that handle, only while it is empty. The first start makes the key
persistent there with one
TPM2_EvictControlcall and records its TPM name in/etc/iot-config/ak. If the handle holds anything else, the agent leaves it untouched and works with a transient key. - Owner authorization. With an owner hierarchy authorization set, the agent persists nothing.
- Factory reset. Before your reset wipes the data partition, stop the
agent and run
bootstrap-agent --release-ak. It evicts the agent's key, and only if the object at the recorded handle carries the recorded name. - Cleaning at start. At start the agent removes its own leftover key
objects (the shape of an endorsement or attestation key) that it can see
through
/dev/tpmrm0. It does not remove anything else and does not touch the raw device/dev/tpm0, see TPM slots.
What is yours¶
Starting and supervising your gateway software, the LEDs, and deleting data
(a factory reset) belong to your image. The agent does none of it; for its key
in the TPM, your reset runs bootstrap-agent --release-ak first (above). How
your software starts and confirms its target:
Start your software and confirm. How it reads its
configuration: Local API reference.