Files
harmony/fleet/harmony-fleet-agent/Cargo.toml
Jean-Gabriel Gill-Couture af20c40f25 feat(fleet): generate device RSA keys on-device, drop openssl dep
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
2026-05-26 11:29:46 -04:00

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 }