pi-provider assumes the hypervisor host key lives in machine-host-keys.json #29
Labels
No labels
bug
duplicate
enhancement
help wanted
invalid
question
wontfix
bug
duplicate
enhancement
help wanted
invalid
question
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
allod/nexus#29
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
pi-providercannot encrypt for a deployment that keeps its hypervisor host key outsidemachine-host-keys.json.collect_recipientsseeds its machine list with the literalnexusand then requires a record for every machine in$MACHINE_HOST_KEYS, which defaults to${IDENTITY_CONFIG}/machine-host-keys.json:The public template carries the hypervisor in that one file, so this holds there. A deployment whose secrets repo keeps VM host keys in
machine-host-keys.jsonand the hypervisor's own key in a separate registry — a reasonable split, since the two rotate through different commands with different gates — hitsno host recipient record for 'nexus'on the firstadd, before any prompt.The
MACHINE_HOST_KEYSenvironment variable is a usable workaround: point it at a merged file assembled outside the tool. That works because the script only ever reads it. But it means every operator with this shape maintains a derived file by hand, out of band from the registries that own the data, and a stale one silently encrypts to the wrong recipient set.Two smaller problems sit beside it:
The hypervisor name is a literal. A fleet whose hypervisor is not called
nexusgets the same failure with a more confusing message. The name is already available —secrets.lib.nexusIdentity.hostnameon the Nix side, and inventory knows which machine istype == "hypervisor".The same
PROFILES_CONFIG/IDENTITY_CONFIG/INVENTORYdefaults resolve to the public template checkouts (allod/profiles,allod/secrets,allod/inventory). A deployment that redirects those inputs must override all three by hand or the tool stages private provider metadata and Age ciphertext into public working trees. It fails closed in practice — the public inventory does not declare the private targets — but the diagnostic points at the target, not at the resolution, and the failure is one edit away from being a boundary incident rather than an error message.Suggestion
Derive the recipient machine set and the hypervisor name from the same sources the Nix contract uses, rather than from one file plus a literal. If a single merged host-key view is the right interface,
secretsis the repo that should expose it, so the tool andmkPiCredentialContractagree by construction instead of by an operator remembering to regenerate a file.Two more undocumented assumptions in the same family, both hit while driving
pi-provideragainst a real fork. Adding them here rather than opening separate issues, since the fix is the same idea: the tool's contract with the redirected repos is written down only inside the script.Check attribute names are part of the contract
post_install_validationbuilds two checks by hardcoded attribute name:A redirected repo that names its equivalent check anything else — or has none — takes the bearer at the prompt, encrypts it, then fails and rolls back:
The rollback is correct and nothing is written, but nothing announces the requirement beforehand. A
--dry-rundoes not surface it either, because the dry run stops before this stage. Checking for both attributes during preflight, beside the registry and inventory checks, would move the failure ahead of the prompt.The public template's own check makes
addself-defeatingallod/secrets'pi-credential-registryasserts the committed registry is empty:post_install_validationbuilds that check after writing a registry entry. On the template itself, the first successfuladdtherefore fails its own validation and rolls back. A fork only avoids this by writing a different check under the same name.The tool does not write
secrets.nixaddwrites the registry and the ciphertext but not the agenix recipient declaration. The credential contract compares declared recipients against derived ones, so the repo stops evaluating immediately after a successful add:The fix is a one-line entry, but the required list is order-sensitive — the contract compares
publicKeysas a list, so it must be nexus keys followed by targets in sorted order. That ordering is not documented anywhere, and getting it wrong reproduces the same error with no hint that only the order is wrong.This also interacts with the check-name requirement above: a fork's
pi-credential-registrycheck cannot force the committed contract, because the tool builds it in exactly the window where the registry is written andsecrets.nixis not yet updated. So the one check the tool insists on is the one that cannot gate the data it just wrote.Either the tool should write the recipient entry, or the derivation should be exposed so a repo can compute it rather than transcribe it.
Reproduced during a named-token rollout after rebuilding the host with merged Nexus revision
0a9b30e.The documented plain command fails before bearer input:
The deployment inventory redirects its private
profilescheckout to$HOME/work/profiles, butpi-providerresolves theallod/profilesalias instead. The host configuration suppliesINVENTORY; the installed command has no wrapper or declarative inputs supplyingPROFILES_CONFIG,IDENTITY_CONFIG, or the deployment’s split hypervisor recipient record. This confirms that the current workaround requires both explicit repository overrides and an externally merged host-key view, and that the documented plain CLI is not usable for this deployment shape.