Auto Load - CyberMind-FR/secubox-deb GitHub Wiki
🔴 BOOT — deployment and provisioning
What it is for. Deliver a SecuBox that sets itself up, with no screen and no keyboard. A box is prepared at the workshop (a signed answers file and a one-time token written on its boot partition). When the customer plugs it in, it calls the Auto-Load infrastructure over HTTPS, opens an outbound tunnel, publishes a pre-report of what it is about to do, waits a grace period, installs its profile and sends a final report. A box that carries no answers file is never touched.
Status. Phase A (a prepared image) is delivered: the agent ships in every image (it is part of the
liteprofile, so alsoispandfull). Phase B (network boot without preparation) is not delivered. A full test on real hardware is still pending (#2186); the end-to-end bench without hardware passes.
| Half | Package | Runs on | Role |
|---|---|---|---|
| Infrastructure | secubox-autoload |
the Auto-Load host (never on a customer box) | issues and revokes tokens, runs the tunnel hub, receives enrolments, pre-reports and progress, serves the follow-up panel |
| Agent | secubox-autoload-agent |
every customer box | verifies the signed answers, enrols, brings the tunnel up, validates, installs, reports |
| Workshop tool |
autoload-atelier (in the agent package) |
workshop or infrastructure, never on the customer box | prepares and checks the boot partition |
workshop autoload-atelier preparer -> /boot/secubox/autoload/{reponses.toml, reponses.toml.sig, jeton}
customer plugs the box in -> secubox-autoload-agent.service starts at first boot
1. installs the token (0600, root) and ERASES it from /boot
2. checks the answers file signature against the "SecuBox Provisioning" keyring (gpgv)
3. generates the WireGuard key ON the box, enrols over HTTPS (token = proof), brings the outbound tunnel up
4. builds the plan, publishes a pre-report (box name, profile, packages, network, accounts)
5. waits for the grace period (15 min by default) - the operator may refuse
6. installs the profile, applies network and accounts, writes the final report
The unit starts only if all three conditions hold: /boot/secubox/autoload/reponses.toml exists, the keyring /usr/share/secubox/autoload/provisioning.gpg is installed, and no final report exists yet.
Every successful step is recorded (/var/lib/secubox/autoload-agent/etat.json, 0600). After a failure or a power cut the run resumes at the first unfinished step and never replays the enrolment (the token is single-use). After 8 consecutive failures the agent gives up and writes a marker; the manual First-Boot-Premier-Pas then takes over again at the next boot.
The answers file (reponses.toml) is the wizard profile plus a [provision] section. It is read in strict mode: unknown section or key, sub-table, or a file over 64 KiB is refused.
[provision] key |
Meaning |
|---|---|
mode |
auto (zero-touch, needs a complete profile because there is no screen to ask) or one-shot (an operator confirms) |
jeton |
a reference ref:/etc/secubox/secrets/<name>, never the value |
lot |
batch label |
grace_min |
grace period in minutes (0 to 1440, default 15) |
infra |
infrastructure host name |
Rules checked before anything is applied:
- no clear-text secret: the admin password is an argon2 hash, the token is a reference, a mesh invitation token in clear is refused;
- detached OpenPGP signature verified by
gpgvagainst the one keyring shipped in the image: a file modified by one byte, signed by another key, or unsigned is refused and nothing is installed.
| Command | What it does |
|---|---|
cle-init --homedir D --export provisioning.gpg |
creates the "SecuBox Provisioning" key once (Ed25519, no expiry) and exports the public part |
preparer --reponses R.toml --boot MNT --homedir D [--jeton-stdin | --jeton-fichier F] |
validates the file as the box will, signs it, verifies the signature against the keyring shipped in the image, and writes nothing unless all three succeed |
verifier --boot MNT |
checks what is deposited, as the box will: valid answers, accepted signature, token present |
Procedure:
- On the infrastructure, issue a token:
autoloadctl emettre --client <client> --profil lite --lot <lot>. It is printed once. - Write the answers file from the example shipped with
secubox-premier-pas(reponses-autoload.toml); keepjeton = "ref:/etc/secubox/secrets/autoload-jeton". - Flash the release image (see Live-USB for
dd) and mount its boot partition. - Prepare: pipe the token on standard input (never as an argument):
printf '%s' "$TOKEN" | autoload-atelier preparer --reponses reponses.toml --boot /mnt/boot --homedir <key dir> --jeton-stdin. - Check:
autoload-atelier verifier --boot /mnt/boot. - Unmount and ship. After the first boot,
autoload-agentctl etatshows progress andautoload-agentctl rapportthe final report.
The private part of the signing key never leaves the workshop; only the public keyring is shipped (by secubox-autoload-agent). To rotate, publish a package whose keyring holds both public keys, re-sign upcoming batches, then drop the old one. If the private key is lost or compromised, revoke the unclaimed tokens of the batches and publish a keyring without it.
The pre-report says what is about to happen: box name, profile, packages to install (from a dry-run apt-get -s install secubox-lite|isp|full), network mode, names of the accounts to create, and only that secrets exist, never their value or file name. It is written 0600 and identified by its SHA-256 fingerprint.
| Mode | Behaviour |
|---|---|
auto |
the pre-report is published to the infrastructure, then the box waits the grace period; the operator can refuse it from the panel. Closed by default: pre-report not publishable, or refusal not readable, means nothing is applied |
one-shot |
applies only if the operator confirms this pre-report's fingerprint (autoload-agentctl confirmer <fingerprint>); confirming another plan is worthless; no confirmation before the deadline means refusal |
Application then runs the wizard engine (premier-pasctl appliquer: network, accounts) and secubox-profilectl apply <profile> --yes (rollback 4R, audit).
At the end of the run the agent builds a report without any secret (client, profile, packages, domain, accounts by name, tunnel address, start, end, steps). It is written on the box (/var/lib/secubox/autoload-agent/rapport.json), shown on screen at the next login prompt, and sent to the infrastructure, which e-mails it to the customer when a contact is set. A failing delivery never stops the run. Mail delivery depends on the SMTP configuration of the infrastructure.
A star: every box opens an outbound WireGuard tunnel to the hub.
- Range
10.64.0.0/16(hub10.64.0.1), UDP port 51830, distinct from the mesh and ephemeral ranges. - Each peer is allowed its own /32 only: customers never see each other.
- The box key is generated on the box (
/etc/secubox/secrets/autoload-wg.key, 0600), never in the image, never on a command line. An existing key is never replaced. - Client configuration has no
ListenPortand no default route (AllowedIPsis the hub /32),PersistentKeepalive = 25: no inbound port on the customer side. - What the infrastructure answers is validated before any file is written (pinned host name, /32 inside the range and not the hub, valid keys, no unknown field).
- Inside the tunnel, the box talks only to the hub service (TCP 8470): progress, pre-report, refusal polling. The box identity is the connection's source address; no header is believed.
| Command | Effect |
|---|---|
emettre --client C --profil lite|isp|full [--lot L] [--serie S] [--duree-jours 90] |
issues a token (printed once) |
preenregistrer --serie S --client C --profil P |
pre-registers a serial number; its box receives its token on the fly, once |
lister [--etat emis|reclame|revoque] [--client C] [--lot L] [--json] |
lists tokens (never their value) |
revoquer (--id N | --lot L) --motif "..." |
revokes one token or a whole batch; for a claimed token, returns the public key to remove from the tunnel |
abonnement --client C --statut actif|suspendu|revoque |
sets the customer subscription |
tunnel-init |
creates the hub key (0600) and prints its public key |
tunnel-sync |
validates, writes the hub config atomically, wg syncconf: no existing peer is cut |
Route (under /api/v1/autoload) |
Role |
|---|---|
GET /boxes, /jetons, /prerapports, /prerapports/{fingerprint}
|
status (waiting, preparing, running, done, revoked) and progress in %; never a token value |
POST /jetons |
issue a token (value shown once) |
POST /jetons/{id}/revoquer |
revoke, remove the peer from the tunnel, apply |
POST /clients/{client}/abonnement |
change a subscription |
POST /lots/{lot}/revoquer |
revoke a batch |
POST /series |
pre-register a serial |
POST /prerapports/{fingerprint}/refuser |
refuse a pre-report during the grace period |
All of these require an administrator session. The public enrolment route POST /enrol is guarded by the token itself and rate-limited (10 refused tries per 10 minutes and per source).
| Measure | Detail |
|---|---|
| Single-use token | 128 random bits, fixed prefix (a leaked token is easy to spot), shown once, stored as a SHA-256 hash; claiming consumes it and binds the box to its WireGuard public key; one key cannot hold two tokens |
| Lifetime | 90 days before claiming by default, 365 at most |
| Uniform refusal | unknown, expired, already used, revoked, subscription not active, wrong key: always "token refused"; the real reason is in the audit log |
| Revocation | at any time, per token or per batch; the peer is removed from the tunnel |
| Subscription |
actif, suspendu, revoque: a non-active customer cannot claim or receive new deliveries; a box already in service keeps all local functions
|
| Signed answers |
gpgv against a single keyring; modified file = refusal |
| No secret on disk in clear | answers hold hashes and references; the token is erased from /boot at first boot (best effort on FAT: single use is what protects) |
| Confined services | dedicated user and AppArmor enforce on the infrastructure service; hardened unit on the agent |
| Audit | every issue, claim, refusal (with reason), revocation and subscription change is appended to the Auto-Load audit log, never with a token value |
| Cloned box | inherits no identity: the WireGuard key is generated on the box |
Firewall on the infrastructure: only UDP 51830 inbound, and TCP 8470 from the tunnel interface only. The port forward from the internet router to the host is a manual step.
- Network boot (phase B) is not delivered: the factory U-Boot of the MOCHAbin has no
wget. See Netboot-Install for the manual netboot procedure. - Release images carry the agent but no answers file: the workshop deposits it, per customer.
- The
ispprofile and the subscription cycle are covered by the bench; the first real-board run is still to do.
- First-Boot-Premier-Pas - the manual wizard that Auto-Load replaces (and falls back to)
-
Profils - what
lite,ispandfullinstall - Installation and Live-USB - flashing an image
- Netboot-Install - installing over the network
- Configuration