Skip to content

Make it possible to run the Nix daemon as a non-root user #5208

Open

Description

@thufschmitt

Problem

In multi-user mode, Nix currently assumes that the daemon is running as root (and the installer sets things up that way).
This can be (and in practice is) a blocker for some corporate environments where installing Nix could be acceptable, but running it as root is out of the question.
More generally, this is a security concern as it means running a fairly large (and not tremendously well audited) codebase as root.

Most of what Nix does however don’t require it: For the most part, everything the Nix daemon needs is to be able to write to the /nix directory.
So it should be possible to run the Nix daemon as its own dedicated user, which would also be the user of /nix.

Solution

Make it possible (and the default) to have the Nix daemon run as a non-root user

Additional context

What is root used for atm? (and how can we avoid it?)

(Possibly I’m missing some uses, please let me know if you think of something that’s not already there)

  • Writing to the Nix store. This can trivially be changed by changing the owner of the store (like in single-user mode)

  • Using the build users. This is partially redundant with the build sandbox, except that

    1. The build sandbox doesn’t actually change the user, which might mean that different sandboxed builds might still be able to interfere with each other
    2. Fixed-output derivations aren’t sandboxed
    3. The sandbox is costly, so the default configuration (sandbox = relaxed) allows derivations to opt-out of it (by setting __noChroot)

    Point 1. can be fixed by using a subuid mapping for the nix user (like all container systems do).
    Point 2 and 3 can be fixed by having a light sandbox that can be used both by FO derivations and __noChroot derivations.

  • The GC needs to follows the roots through the user home directories (for indirect roots).

    I don’t think there’s a solution to that, so I think the root discovery system will have to be factored out into a separate executable (with a much smaller attack surface) with the right capabilities.

Activity

  1. self-assigned this
    on Sep 2, 2021
  2. nixos-discourse commented on Sep 15, 2021

    @nixos-discourse

    This issue has been mentioned on NixOS Discourse. There might be relevant details there:

    https://discourse.nixos.org/t/tweag-nix-dev-update-17/15037/1

  3. stale commented on Apr 16, 2022

    @stale

    I marked this as stale due to inactivity. → More info

  4. alexshpilkin commented on Apr 28, 2022

    @alexshpilkin
    Member

    Not stale, dammit.

  5. Ericson2314 commented on Oct 16, 2023

    @Ericson2314
    Member

    Is there a branch for this, even if it has conflicts?

  6. thufschmitt commented on Oct 17, 2023

    @thufschmitt
    MemberAuthor

    @Ericson2314 oh, I forgot to backlink it, but yes, there's #5380 open for that (and it's essentially conflict-free barring some trivial things)

  7. UnderTheCarpet commented on Feb 20, 2024

    @UnderTheCarpet

    Would it be also possible to change the prefix of the nix store from a hardcoded /nix/store to something variable/custom and potentially in the user's home?

    This would help to run nix as a user in a single-user scenario without requiring root (and the cooperation of your IT department ) to set up a non-user-owned folder in the file system root.

  8. alexshpilkin commented on Feb 20, 2024

    @alexshpilkin
    Member

    @clamydo Currently, the Nixpkgs build system embeds absolute paths to dependencies in the build artifacts. As long as that’s true, a Nix store located in a nonstandard location (even if supported) would require rebootstrapping and rebuilding literally everything you might want to use.

    [On Linux, you could live inside a mount namespace that bind-mounts the store back to the standard location, I guess, but that probably(?) doesn’t require changes to Nix.]

  9. Ericson2314 commented on Feb 20, 2024

    @Ericson2314
    Member

    Yes "chroot stores" are already supported on Linux just fine.

  10. UnderTheCarpet commented on Feb 21, 2024

    @UnderTheCarpet

    Currently, the Nixpkgs build system embeds absolute paths to dependencies in the build artifacts.

    Hmm, couldn't derivations refer to a substitutable placeholder like $NIX_STORE_PATH that is resolved when actually building/instantiating? For bash wrapper scripts using absolute paths this could work when a environment variable is present. pkg-config files should support variables? But there are probably places, where a resolved absolute path is strictly required?

    I guess rpath needs an absolute path and cannot be resolved at a later time 🤔?

    Yes "chroot stores" are already supported on Linux just fine.
    Well, I have tried nix-portable and took a few tries to get it working. It kinda worked eventually but I remember it to be a bit brittle. I don't want to complain, it is a descent workaround.

    However, to me it seems that nix is nicely positioned to be a OS agnostic package/dependency manager. Requiring a folder in the root of the filesystem works just fine for NixOS but is a hindering in an more constrained environment. I feel that is a bit of a pity.

    My current personal frustration with this stems from a not so cooperative sys admin responsible for my team's dev machine/server. It is hard enough to convince the rest of the team to try out 'new stuff' 😉. But also in a HPC context nix would just not be usable because of this requirement.

  11. alexshpilkin commented on Feb 21, 2024

    @alexshpilkin
    Member

    @clamydo said:

    Hmm, couldn't derivations refer to a substitutable placeholder like $NIX_STORE_PATH that is resolved when actually building/instantiating? [...]

    Today they refer to store paths as Nix generates them according to its own desires—which happen to go like /nix/store/ and so on, but I don’t expect the vast majority of derivations to make use of that fact. The problem is, as you said, binaries, which embed the paths and ordinarily come from a cache / substituter; I doubt you feel like building Firefox on your laptop, let alone doing a full system bootstrap including compilers and everything else.

    (I don’t actually know how to bootstrap Nixpkgs from nothing but a Nix binary and a system C toolchain that may produce nonreproducible results. It’s bound to be gnarly. And bootstrapping e.g. rustc from C++ with mrustc is strictly experimental.)

    I guess rpath needs [to be] absolute and cannot be resolved at a later time 🤔?

    Also shebangs and—crucially—the ELF interpreter1 in dynamically linked binaries. (Note we are again talking about built binaries or in any case build artifacts.)

    A lot of software also just happens to bake the configured $prefix into random places, occasionally even as parts of compressed data. I don’t expect most of these are required per se, but patching the world to avoid it has got to be a gigantic pain (even more than it already is). It sounds like you’d need to solve content-addressed derivations first at least.

    Just running the damn thing in a chroot or mount namespace with /nix bind-mounted to whatever physical directory you want is bound to be simpler.

    (I don’t think this situation is good or proper, to be clear; I just expect the effort of fixing it to be so large as to be functionally infinite. Unless somebody wants to get started on that :) )

    Footnotes

    1. Technically the ELF interpreter path can be relative, but then it’s relative to the working directory at time of launch, not to the directory where the launched executable is located. Not useful for our purposes. I guess you couuuld replace each binary with a statically linked wrapper that locates the correct ld.so and launches it manually with the actual executable in argv, but honestly it doesn’t sound like a good time. OK, it absolutely does, but not in a “I want to spend my life patching every piece of FOSS in the world to work with this” way. ↩

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions