The Zitadel JWT-bearer private key is now generated locally on each fleet device via a new `fleet-agent keygen` subcommand. Only the public key reaches Zitadel — closing the storage-and-future-decryption hole where the key previously crossed SSH on enrollment. Backed by pure-Rust `rsa = "0.9"` + `rand_core::OsRng`. No `openssl(1)` needed on the device, no shell string interpolation, one SSH round-trip instead of two, typed errors all the way down. Key changes: - `fleet-agent keygen` subcommand (PKCS#8 private + SubjectPublicKeyInfo public PEM, idempotent, atomic write) with 6 unit tests - `FleetDeviceAuth::ZitadelEnroll` variant: inline on-device key-gen + public-key registration during setup - `RemoteCommand` capability trait, kept narrow and out of the `LinuxHostConfiguration` umbrella so most Scores don't see it - Zitadel `register_device_public_key` + `mint_device_credentials` helpers for client-supplied public keys - Drop dead `MachineKeyFile._type` (serde ignores unknown fields) - Renumber FleetDeviceSetupScore log steps cleanly to 1..9
35 lines
1.2 KiB
TOML
35 lines
1.2 KiB
TOML
[package]
|
|
name = "harmony-fleet-agent"
|
|
version = "0.1.0"
|
|
edition = "2024"
|
|
rust-version = "1.85"
|
|
|
|
[dependencies]
|
|
harmony-fleet-auth = { path = "../harmony-fleet-auth" }
|
|
harmony-reconciler-contracts = { path = "../../harmony-reconciler-contracts" }
|
|
harmony = { path = "../../harmony", default-features = false, features = ["podman"] }
|
|
async-nats = { workspace = true }
|
|
async-trait = { workspace = true }
|
|
chrono = { workspace = true }
|
|
futures-util = { workspace = true }
|
|
serde = { workspace = true }
|
|
serde_json = { workspace = true }
|
|
tokio = { workspace = true }
|
|
tracing = { workspace = true }
|
|
tracing-subscriber = { workspace = true }
|
|
anyhow = { workspace = true }
|
|
clap = { workspace = true }
|
|
toml = { workspace = true }
|
|
thiserror = { workspace = true }
|
|
# Pure-Rust RSA: pulled in for the `keygen` subcommand. No openssl
|
|
# dep on the device — the same binary that ships to the Pi mints
|
|
# its own keypair on first run so the private key never crosses
|
|
# the network. We use `rsa`'s bundled `rand_core::OsRng` (no
|
|
# separate `rand` dep needed — and avoids a version skew against
|
|
# the workspace `rand = "0.9"`, since `rsa = "0.9"` ships with
|
|
# `rand_core = "0.6"` internally).
|
|
rsa = { version = "0.9", features = ["pem"] }
|
|
|
|
[dev-dependencies]
|
|
tempfile = { workspace = true }
|