Encrypt Tentacle certificate password and subscription id at rest
Summary
- The Tentacle's at-rest encryption — machine-key AES-256-GCM protecting the certificate password (which guards the PFX holding the agent's private key) and the polling subscription id — was implemented and unit-tested in
TentacleCertificateManager, but never wired: the runtime (TentacleApp) and all five CLI commands (register,show-thumbprint,show-config,check-services,new-certificate) constructed the encryptor-less overload, so production agents wrote both secrets in plaintext on disk. - Add
ProductionTentacleCertificateManageras the single construction site that wires the machine-key encryptor, and route all six production sites through it. Routing every site through one factory keeps the write path (register/new-certificate) and the read paths (show-thumbprint, the runtime load) in agreement on whether the cert password is encrypted — otherwise a writer storing a random encrypted password and a reader built without the encryptor would fall back to the legacy fixed password and fail to open the PFX. - Completes the P2 at-rest encryption series (account credentials, certificate, external feed, SSH proxy password already shipped).
Non-breaking
- If the machine-key encryptor cannot be initialised (key derivation throws on an unusual host), the factory degrades to the legacy plaintext manager rather than blocking Tentacle startup — at-rest encryption is best-effort hardening, never a startup gate.
- Existing plaintext installs migrate seamlessly on first encryptor-aware load:
TentacleCertificateManageralready writes the existing password / subscription id back in encrypted form (the migration logic predates this PR). No data migration required. - The encryptor-less
TentacleCertificateManager(certsPath)constructor stays for tests and back-compat.
Test plan
-
Unit (real AES-256-GCM + real file IO + real X509): ProductionTentacleCertificateManagerTests— the factory produces a manager that encrypts the subscription id (v1:envelope +.encryptedmarker) and the cert password at rest, round-trips across reopen, and never returns null. -
Existing TentacleCertificateManagerEncryptorTests/TentacleCertificateManagerTestsstill green (21/21 cert-manager tests pass). -
E2E (Linux, real binary + real /etc/squid-tentaclefilesystem):D5h_RegisterWritesEncryptedSecretsAtRest— after a realregister, the on-disksubscription-idandtentacle-cert.pfx.pwdarev1:-encrypted. The existingD1hregister→show-thumbprint round-trip guards write/read path agreement. -
Full Tentacle unit suite: 1547 pass; 14 pre-existing LocalScriptServiceIdempotencyTestsfailures are unrelated (process/state-file tests that also fail onmainon this host).