Auto Load - CyberMind-FR/secubox-deb GitHub Wiki

Auto-Load

Français

🔴 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 lite profile, so also isp and full). 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.

The two halves

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

What happens, step by step

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.

Resuming

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.

Signed answers file

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 gpgv against 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.

Workshop: autoload-atelier

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:

  1. On the infrastructure, issue a token: autoloadctl emettre --client <client> --profil lite --lot <lot>. It is printed once.
  2. Write the answers file from the example shipped with secubox-premier-pas (reponses-autoload.toml); keep jeton = "ref:/etc/secubox/secrets/autoload-jeton".
  3. Flash the release image (see Live-USB for dd) and mount its boot partition.
  4. 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.
  5. Check: autoload-atelier verifier --boot /mnt/boot.
  6. Unmount and ship. After the first boot, autoload-agentctl etat shows progress and autoload-agentctl rapport the 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.

Pre-report and grace period

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).

Final report

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.

Tunnel wg-autoload

A star: every box opens an outbound WireGuard tunnel to the hub.

  • Range 10.64.0.0/16 (hub 10.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 ListenPort and no default route (AllowedIPs is 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.

Infrastructure: autoloadctl

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

Follow-up panel (administrator only)

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).

Security

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.

Limits

  • 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 isp profile and the subscription cycle are covered by the bench; the first real-board run is still to do.

See also

⚠️ **GitHub.com Fallback** ⚠️