Rootless Nix Daemon

We quietly implemented support for a rootless Nix daemon a few months ago, and I have just finished a post describing the challenges in a bit more detail.

Thank you to the Nix Foundation and the Sovereign Tech Agency for funding this project.

43 Likes

I applied code snippet from blog post to my NixOS configuration but I get permission denied errors after reboot and trying to nixos-rebuild build my configuration

warning: creating directory "/root/.cache/nix": Permission denied
error: opening lock file "/nix/store/1xp94zk7f614k0jwc794yvmiwbwmnxmh-xkb-console-keymap.lock": Permission denied

I managed to workaround this with manually setting /nix/store ownership to nix-daemon:nix-daemon but now daemon doesn’t use binary cache to download pre-built binaries.

What am I doing wrong?

1 Like

What are the positives / negatives of rootless vs … not rootless nix daemon?

I’ve been using this for a while on Ubuntu, (although I didn’t go through the read-only mount process for the nix store and the local overlay, since I won’t be giving my users root access) and it’s been great!

One note for Ubuntu users, the OS wants the nix daemon to have an apparmor profile because apparently user namespaces are a huge source of security bugs

1 Like

That’s my mistake, I seemed to have missed something during upstreaming. the Nix daemon isn’t getting a home directory needed for the cache, so you’ll have to make one.

A simple workaround would be:

systemd.tmpfiles.rules = [
"d /nix/var/nix/home 0700 nix-daemon nix-daemon - -"
];
systemd.services.nix-daemon.environment.HOME = "/nix/var/nix/home";

I’ll work on something cleaner and upstream it.

2 Likes

A potential solution which I’ve been using for a while is to set

systemd.services.nix-daemon = {
  serviceConfig = {
    CacheDirectory = "nix";
    CacheDirectoryMode = "0700";
  };
  environment.XDG_CACHE_HOME = "%C";
};

This puts the cache in /var/cache/nix.

Yes, this is very interesting and satisfies my OCD of having fewer and fewer daemons running as root, but what is it actually meant to protect against?

It obviously can’t prevent a compromised Nix daemon to inject code into packages (à la “trusting trust”) and escalate privileges or do anything it wants, really.

Does it make escaping the build sandbox harder? I’m not sure.

EDIT:

Was this done completely downstream of Nix? Because I don’t see any mention of this work in the relevant issue.

I’ve found another couple of issues:

  1. This /nix/var tmpfiles rule replaces permissions 666 with 755 for daemon socket, making other users unable to connect to daemon, eg after nixos-rebuild switch causes systemd-tmpfiles-resetup.service to run
  2. Some programs (eg ssh, logrotate) fail to run because they expect their config files to have specific ownership or permissions
> ssh somehost
Bad owner or permissions on /nix/store/mc901k2s1n3v1disrj0356l7lwz7l6vg-systemd-261.1/lib/systemd/ssh_config.d/20-systemd-ssh-proxy.conf
systemd[1]: Starting Logrotate Service...
logrotate[5339]: error: Ignoring /nix/store/0zz9zaka91d8ybiaim9avzh36zvs6w46-logrotate.conf because the file owner is wrong (should be root or user with uid 0).
systemd[1]: logrotate.service: Main process exited, code=exited, status=1/FAILURE
systemd[1]: logrotate.service: Failed with result 'exit-code'.
2 Likes