fix: make sops-nix work beyond the default configuration - #534
Open
aldoborrero wants to merge 4 commits into
Open
fix: make sops-nix work beyond the default configuration#534aldoborrero wants to merge 4 commits into
aldoborrero wants to merge 4 commits into
Conversation
sops-nix installs secrets either from a NixOS activation script or, when `sops.useSystemdActivation` is set, from a sops-install-secrets.service oneshot. system-manager can only ever take the second path, and until now it relied on that option happening to default to true because userborn is enabled by default. Three configurations silently installed no secrets at all: - `sops.age.generateKey`: only implemented upstream as an activation script, so the age key was never generated and secret installation failed on a machine that did not already have the key. - `sops.secrets.<name>.neededForUsers`: the generated unit is ordered around systemd-sysusers.service, which system-manager never runs, so it was neither started on activation nor before userborn creates the users that consume the secret. - `services.userborn.enable = false`: turned `useSystemdActivation` off, which dropped secret installation entirely with no diagnostic. Default `sops.useSystemdActivation` to true and assert it stays enabled, re-point the for-users unit at userborn and sysinit-reactivation.target, and run the `generate-age-key` script from a oneshot unit ordered before the units that need the key.
Both tests run against every distribution in the container test matrix, following the same pattern as the existing sops-ssh-key test. sops-generate-age-key asserts that the age key is generated by a unit and that re-activation does not replace it. sops-needed-for-users consumes a neededForUsers secret as a user's hashedPasswordFile and asserts that userborn picks the decrypted hash up, which only works if the for-users unit is ordered before userborn.
Add a how-to guide for encrypted secrets, and correct the sops-nix section of the NixOS module import guide, which described the activation-script options as pure stubs and claimed secret decryption was handled elsewhere without saying how.
The restart path uses `try-restart`/`try-reload-or-restart` with --no-block, which are not incidental details: a stopped unit stays stopped, and the restart is requested rather than awaited because sops-install-secrets runs before sysinit-reactivation.target with DefaultDependencies=no. Also note the `keys` group fallback to `nogroup`, which is what happens on Debian and Ubuntu.
Contributor
|
Tick the box to add this pull request to the merge queue (same as
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #533.
What
Turns
nix/modules/upstream/sops-nix.nixfrom a set of activation-script stubs into a compatibility module that pins sops-nix to its systemd code path and fixes the places where that path still assumes NixOS.The premise is that system-manager can never run NixOS activation scripts, so
sops.useSystemdActivationis not one of two valid options here — it is the only one. Everything else follows from that.sops.useSystemdActivationtotrueregardless of userborn, and assert it stays enabled when secrets are configured. Previously,services.userborn.enable = falsedisabled secrets management with no diagnostic.neededForUsersis used together with userborn. sops-nix computes its own condition for the for-users unit and ignoresuseSystemdActivationthere, so this is the one case that cannot be papered over.sops-install-secrets-for-users.servicefromsystemd-sysusers.service(never run here) touserborn.service, and hook it intosysinit-reactivation.targetso it also runs on activation and not only on boot.generate-age-keyactivation script from asops-generate-age-key.serviceoneshot, ordered before the units that need the key. The script text is taken from the option sops-nix writes to, not reimplemented, so it stays in sync; if sops-nix ever stops emitting it, the unit simply is not created.Everything is guarded by
lib.optionalAttrs (options ? sops.secrets), so configurations that do not import sops-nix are unaffected.No changes to the Rust engine were needed: it already restarts
sysinit-reactivation.targeton every activation, so hooking units there is sufficient.Tests
Two new container tests, following the existing
sops-ssh-keypattern, so they run across the whole distribution matrix:container-*-sops-generate-age-key— asserts the key is generated by a unit, has mode 600, is ordered beforesops-install-secrets.service, that secrets still decrypt, and that re-activation does not replace an existing key.container-*-sops-needed-for-users— consumes aneededForUserssecret as a user'shashedPasswordFileand asserts that userborn picks the decrypted hash up in/etc/shadow. This only passes if the for-users unit runs before userborn.testFlake/sops/secrets-for-users.yamlis new test material, encrypted with the age key already committed attestFlake/sops/age-keys.txt.Docs
docs/site/how-to/import-nixos-module.mdclaimed the activation-script options were pure stubs and that "the actual secret decryption is handled differently in system-manager through a systemd service" without saying how. Corrected, and ahow-to/manage-secrets.mdguide added, since sops-nix support was previously undocumented outside a CHANGELOG line.Verification status
Run and passing:
vm-debian-13-sops-generate-age-key,vm-debian-13-sops-needed-for-users) before they were converted to container tests.vm-debian-13-example(which exercises sops),vm-debian-13-prepopulate,vm-debian-13-sudo-module.mypyandpyflakesover the generated container test scripts, replicating what the test derivation'sbuildCommanddoes.treefmt --fail-on-change, andnix build .#systemConfigs.default.toplevel,driverandclosureInfoof all six new container checks build on all three distributions.Not run: the container tests themselves. The Nix daemon on the machine they were developed on does not offer the
uid-rangesystem feature thatmakeContainerTestrequires, and the feature cannot be toggled from the command line — it is resolved daemon-side. To run them:Investigated and implemented with the help of Claude Code. Everything claimed above was checked against actual builds and runs at the revisions in the issue, not from model recall; in particular, the "not run" item is accurate and not an oversight.