The Pi onboarding flow can now mint a per-device Zitadel machine user
on the operator's machine and ship the resulting JWT key to the Pi —
the agent then authenticates to NATS via JWT-bearer instead of shared
nats_user/nats_pass.
`FleetDeviceSetupConfig.auth: FleetDeviceAuth` replaces the previous
flat `nats_user` / `nats_pass` fields. Two variants:
- TomlShared { nats_user, nats_pass } — legacy / dev fallback.
- ZitadelJwt { machine_key_json, oidc_issuer_url, audience, ... } —
per-device JWT-bearer. The Score:
* Drops `machine_key_json` to /etc/fleet-agent/zitadel-key.json
(mode 0640, owner fleet-agent — matches the agent's secret-mount
conventions).
* Renders [credentials] type = "zitadel-jwt" pointing at that
keyfile + the issuer + audience the agent's CredentialSource
needs.
A change to either the keyfile content or the TOML triggers an
agent restart, same as binary / unit drift.
`fleet_rpi_setup --bootstrap-token <PAT>` activates the Zitadel path.
The bootstrap PAT is held in the CLI's memory only; it never lands
on the Pi. New flags: --zitadel-issuer-url, --zitadel-project-id,
--zitadel-device-role (default `device`), --danger-accept-invalid-certs.
`zitadel_bootstrap` is a slim ManagementAPI client that, idempotently
per device:
1. Find-or-create machine user `device-${device_id}`.
2. Find-or-skip a project role grant (defaults to `device`).
3. Always mint a fresh JSON key and return its content. (Zitadel
doesn't expose the private half of an existing key, so reusing
isn't possible — stale keys remain valid until expiry, which is
fine because each setup run overwrites the on-device keyfile.)
Three new render_toml tests cover the zitadel-jwt path; eleven
existing agent tests still pass.
Out of scope, tracked: device-join-request + admin-approve flow that
would replace bootstrap-PAT entirely (closer to the OKD
node-approval pattern). Long-lived admin PAT is acceptable for the
demo per product call.
24 lines
580 B
TOML
24 lines
580 B
TOML
[package]
|
|
name = "example_fleet_rpi_setup"
|
|
version.workspace = true
|
|
edition = "2024"
|
|
license.workspace = true
|
|
|
|
[[bin]]
|
|
name = "fleet_rpi_setup"
|
|
path = "src/main.rs"
|
|
|
|
[dependencies]
|
|
harmony = { path = "../../harmony" }
|
|
harmony_cli = { path = "../../harmony_cli" }
|
|
harmony_secret = { path = "../../harmony_secret" }
|
|
harmony_types = { path = "../../harmony_types" }
|
|
tokio.workspace = true
|
|
log.workspace = true
|
|
anyhow.workspace = true
|
|
clap.workspace = true
|
|
reqwest = { workspace = true }
|
|
serde = { workspace = true, features = ["derive"] }
|
|
serde_json.workspace = true
|
|
base64 = "0.22"
|