You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
nixos: the checkout unit runs the least trusted code with no systemd hardening #50
The hardening attrset in nixos/astroadmin-instance.nix — NoNewPrivileges, ProtectSystem=strict, ProtectHome, PrivateTmp, ProtectKernelTunables, ProtectKernelModules, ProtectControlGroups, RestrictSUIDSGID, LockPersonality — is applied only to the two long-running units. Its own comment says it is "systemd hardening shared by the long-running units".
The checkout one-shot gets none of it, and that unit is where bun install runs: arbitrary postinstall scripts from the site's dependency tree, i.e. the least trusted code on the host. The servers it feeds are sandboxed; the thing that installs them is not.
#48 adds RestrictNamespaces = true to it directly, because that is the one that closes the kernel-privesc vector and it was tested against a real install. The rest was left alone deliberately — the shared set has never been validated against a package install, and quietly applying ProtectSystem=strict to something that writes node_modules is how you get a confusing failure at 2am.
What needs checking
Most of it looks like it should just work — the unit already declares StateDirectory, so the writes it needs are inside a path systemd grants, and HOME is the state dir rather than a real home, so ProtectHome should be inert. But "looks like" is not a test.
Does bun install --frozen-lockfile complete under ProtectSystem=strict for a site with native/postinstall dependencies, not just a clean one?
Does PrivateTmp break any package that shells out through /tmp?
Does the initial git clone path still work (different from the fast-forward path, and only exercised on a fresh instance)?
Test it the way #48 was tested: /run/systemd/system drop-ins on a live instance, exercise the real thing, then remove them so the box matches its declared config again. Confirm the property actually applied with systemctl show -p <Property> before trusting the result — a first attempt at #48 wrote drop-ins to /etc/systemd/system, which is read-only on NixOS, and it would have read as a clean pass if the property had not been checked.
Update after #48's review: one item from the shared set already applies here. With User= set, systemd implies NoNewPrivileges=yes for any seccomp-based option, so RestrictNamespaces = true on the checkout unit turned it on too. The live bun install run in #48 passed with it in place, so that one is covered. The rest of the list above still needs testing.
Related, and broader than the checkout unit: no editor unit has resource or network limits. On main, git grep -E "MemoryMax|CPUQuota|TasksMax|IPAddressDeny|ProtectProc" -- nixos returns nothing.
When this is picked up, consider adding these to the admin, preview and checkout units together:
MemoryMax, CPUQuota and TasksMax, so one site can't OOM or fork-bomb the box;
IPAddressDeny=localhost plus an allow for the unit's own port, so sibling editors' loopback ports are unreachable (see astroadmin-ops#3);
ProtectProc=invisible, PrivateDevices, and a SystemCallFilter=@system-service baseline.
Activity
euoia commentedon Oct 3, 2026
Update after #48's review: one item from the shared set already applies here. With
User=set, systemd impliesNoNewPrivileges=yesfor any seccomp-based option, soRestrictNamespaces = trueon the checkout unit turned it on too. The livebun installrun in #48 passed with it in place, so that one is covered. The rest of the list above still needs testing.euoia commentedon Oct 12, 2026
Related, and broader than the checkout unit: no editor unit has resource or network limits. On
main,git grep -E "MemoryMax|CPUQuota|TasksMax|IPAddressDeny|ProtectProc" -- nixosreturns nothing.When this is picked up, consider adding these to the admin, preview and checkout units together:
MemoryMax,CPUQuotaandTasksMax, so one site can't OOM or fork-bomb the box;IPAddressDeny=localhostplus an allow for the unit's own port, so sibling editors' loopback ports are unreachable (see astroadmin-ops#3);ProtectProc=invisible,PrivateDevices, and aSystemCallFilter=@system-servicebaseline.