Sign closures on the hypervisor so guest root login can close again #13

Open
opened 2026-10-22 05:40:14 +01:00 by vnprc-agent · 0 comments

The hypervisor signs the systems it builds and every guest trusts that signature, so a rebuild can be delivered to a guest as its login user again and root stops accepting SSH logins on guests at all.

Primary goals:

  • One signing key on the hypervisor — nix.settings.secret-key-files names an age-encrypted key the secrets layer owns; the public half is identity data the inventory or secrets layer exports, never a value in a framework repo.
  • Guests trust it — nix.settings.trusted-public-keys on every guest gains the hypervisor's public key beside the cache's, so nix-copy-closure from an untrusted user is accepted because the paths are signed, not because the user is trusted.
  • Root's door closes — users.users.root.openssh.authorizedKeys.keys goes back to empty on guests, PermitRootLogin to no, and rebuild-vm targets the login user with --sudo again; the assertion and sabotage fixtures from allod/vm#12 flip to pin the closed state.
  • Rotation is a routine — the signing key joins the staged rotation lifecycle the other hypervisor keys follow, since a signing key is identity material (architecture.md, published is forever).

Why

allod/vm#12 removed the guest user from nix's trusted users, which it had to, and the only way to keep rebuilds working without a signing key was to deliver as root. That is the same authority nexus already had through passwordless sudo, so nothing escalated, but it is a second account on every guest, privacy guests included, that accepts the hypervisor's SSH key, and every guest built before the change needed a one-time delivery by the old path. Signed closures are the shape the nix model intends: trust the bytes, not the courier. Cost: a key to generate and distribute, which is host-only, and a public key that every guest's configuration must carry from a data input, which is why this is its own arc and not part of allod/strategy#69.

Scope

In: allod/vm guest module (trusted-public-keys from an input, root login closed), allod/nexus (secret-key-files, rebuild-vm target), the secrets template (a synthetic signing key pair and its registry entry), and a nested or live witness that an unsigned path is refused and a signed one accepted. Out: substituter changes, the cache, and the sandbox command.

The hypervisor signs the systems it builds and every guest trusts that signature, so a rebuild can be delivered to a guest as its login user again and root stops accepting SSH logins on guests at all. Primary goals: - **One signing key on the hypervisor** — `nix.settings.secret-key-files` names an age-encrypted key the secrets layer owns; the public half is identity data the inventory or secrets layer exports, never a value in a framework repo. - **Guests trust it** — `nix.settings.trusted-public-keys` on every guest gains the hypervisor's public key beside the cache's, so `nix-copy-closure` from an untrusted user is accepted because the paths are signed, not because the user is trusted. - **Root's door closes** — `users.users.root.openssh.authorizedKeys.keys` goes back to empty on guests, `PermitRootLogin` to `no`, and `rebuild-vm` targets the login user with `--sudo` again; the assertion and sabotage fixtures from allod/vm#12 flip to pin the closed state. - **Rotation is a routine** — the signing key joins the staged rotation lifecycle the other hypervisor keys follow, since a signing key is identity material (`architecture.md`, published is forever). ### Why allod/vm#12 removed the guest user from nix's trusted users, which it had to, and the only way to keep rebuilds working without a signing key was to deliver as root. That is the same authority nexus already had through passwordless sudo, so nothing escalated, but it is a second account on every guest, privacy guests included, that accepts the hypervisor's SSH key, and every guest built before the change needed a one-time delivery by the old path. Signed closures are the shape the nix model intends: trust the bytes, not the courier. Cost: a key to generate and distribute, which is host-only, and a public key that every guest's configuration must carry from a data input, which is why this is its own arc and not part of allod/strategy#69. ### Scope In: `allod/vm` guest module (trusted-public-keys from an input, root login closed), `allod/nexus` (secret-key-files, rebuild-vm target), the secrets template (a synthetic signing key pair and its registry entry), and a nested or live witness that an unsigned path is refused and a signed one accepted. Out: substituter changes, the cache, and the sandbox command.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
allod/vm#13
No description provided.