Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mutable users issue #2821

Closed
CMCDragonkai opened this issue Jun 4, 2014 · 42 comments
Closed

Mutable users issue #2821

CMCDragonkai opened this issue Jun 4, 2014 · 42 comments

Comments

@CMCDragonkai
Copy link
Member

When making:

users.mutableUsers = false;

This means any new users and new groups created from configuration.nix needs to have a specified UID or GID.

I was thinking that is this is unnecessary. When you first create a new machine, you don't know UIDs or GIDs are available to be used. Can Nixos just create those users/groups and leave the system to specify the UID/GID and then enforce immutable users afterwards. The system shouldn't need to prevent the dynamic creation of users/groups inside the configuration phase, only afterwards?

@wmertens
Copy link
Contributor

wmertens commented Jun 4, 2014

But how will you guarantee identical ordering on two systems running the
same configuration but different uptimes?

Wout.
On Jun 4, 2014 3:42 AM, "Roger Qiu" [email protected] wrote:

When making:

users.mutableUsers = false;

This means any new users and new groups created from configuration.nix
needs to have a specified UID or GID.

I was thinking that is this is unnecessary. When you first create a new
machine, you don't know UIDs or GIDs are available to be used. Can Nixos
just create those users/groups and leave the system to specify the UID/GID
and then enforce immutable users afterwards. The system shouldn't need to
prevent the dynamic creation of users/groups inside the configuration
phase, only afterwards?


Reply to this email directly or view it on GitHub
#2821.

@CMCDragonkai
Copy link
Member Author

Wouldn't that be an issue even with mutableUsers? Besides people can still decide to have consistent ids by specifying it. All I'm saying is that it should still work even without specifying ids.

@rickynils
Copy link
Member

How would you recreate an identical system from just its configuration.nix in that case? When mutableUsers is true, the uids and gids depend not on the configuration, but on the order the users have been added to the system. The same would be true with your suggested functionality.

@CMCDragonkai
Copy link
Member Author

That is fine. It can act the same as when mutable is true, but after configuring, it will make immutable.

@rickynils
Copy link
Member

No, it is not fine. mutableUsers = false enables you to have a system that is re-createable only based on configuration.nix. Your suggestion breaks that, if I'm not totally misunderstanding you.

@CMCDragonkai
Copy link
Member Author

There can be 3 situations:

  1. Mutable users true, you let the system decide UIDs and GIDs and get mutability.
  2. Mutable users false, you let the system decide UIDs and GIDs and then get immutability.
  3. Mutable users false, you specify the UIDs and GIDs amd you get immutability.

If you are already doing 3., then you keep doing the same thing, this suggestion doesn't change anything.

The suggestion is to have 2., so one can have flexibility such as wanting immutable users, but not wanting to specify the UIDs and GIDs.

Is this impossible? Does it conflict with what you are already doing? Is there any backwards compatibility breaks?

@rickynils
Copy link
Member

For 2, what does "get immutability" mean, exactly?

For 3, the current implementation ensures immutability by overwriting any changes to /etc/passwd and /etc/group on each system activation (basically each boot and each run of nixos-rebuild). In this way, we are guaranteed to get a predictable system state, with the same uids and guids after each activation.

For your suggestion, there is no predictable system state and therefore no way to prevent mutation of uids/gids between activations, or between system incarnations.

There is one way of getting around having to specify uid/gid, by letting the uid/gid be the hash of the user name, for example. This is just another way of specifying uid/gid though. And there is the problem of hash collisions.

@CMCDragonkai
Copy link
Member Author

For 2. I mean that you let the system decide the first time nixos-rebuild switch is ran (even letting the system decide is probably not random). You get immutability afterwards and the process of overwriting the /etc/passwd upon boot starts working. There is predictable system state after this first run. I don't see how this is incompatible?

@cstrahan
Copy link
Contributor

cstrahan commented Jun 5, 2014

@CMCDragonkai

I'm pretty sure that mutableUsers works by entirely rebuilding/replacing /etc/passwd. For your No2, it would require extra work to keep the old users around, and with nothing to really gain. mutableUsers is probably a bit of a misnomer; when true, the activation script completely ignores any existing users, even if you've made changes in your configuration.nix - which, ironically, might sound quite a bit like immutability. Whereas false results in /etc/passwd being completely rewritten to match configuration.nix, which might sound a bit like mutability.

I would explain the purpose of mutableUsers thusly. Let's say you have a user Bob. Bob takes ownership of a file. When Bob does so, linux records the uid of Bob - not his name, of course. Some time down the road, bob decides he wants to be called Jack, so he changes his name. With MU set to true, what would happen is Bob would still exist while a new user Jack would come into existence, and of course that file Bob took ownership of would still belong to this old phantom Bob. This whole problem would have been avoided if Bob had explicitly specified his uid and MU was false, because then there would only be Jack in /etc/passwd, and with the same old uid from when Jack was known as Bob. It's a silly example, but I hope it make the purpose more clear.

IMO, idempotency might be a better descriptor than immutability - given a nixos-rebuild switch on machine A with config C, you end up with the exact same result running nixos-rebuild switch on any machine B with config C, regardless of orderings or previous executions.

If if you could have what you ask for, you logically run into the problem where you have a conflict between an existing user's uid and a user specified in your configuration: how do you resolve this conflict? I don't think there's a good, sensible answer to that question, which is why such behavior isn't good. What would you really gain, anyways?

(Edited: resolved an ambiguity.)

@CMCDragonkai
Copy link
Member Author

@cstrahan That makes sense, great explanation.

I only came across this issue because I wanted to get the benefits of mutableUsers = false, but without me needing to come up with some uid/gid. At the time, I did not know what uids/gids already existed in the system, so I was not sure whether specifying a particular uid/gid would conflict with any reserved ids.

@cstrahan
Copy link
Contributor

cstrahan commented Jun 5, 2014

@CMCDragonkai

Right, it's an all-or-nothing deal, and you do need some extra coordination - if you have two modules that each define a user, you need to make sure they don't share the sameuid/gid. Aside from a hashing scheme (as @rickynils pointed out), or some central unique id service, you kind of just have to accept that coordination overhead in order to reap the benefits.

@rickynils
Copy link
Member

When mutableUsers is true, you let the system decide which uids and gids to use, based on the current state of /etc/passwd. And this is indeed a random process, there is no way to get a consistent state if you let the activation decide this at runtime, because it will depend on the order you add new users to configuration.nix.

About first-time activation: Why would there be any meaning in just creating users once and then ignore all future changes to configuration.nix? This would also give you an unpredictional state, since you would have to know when the system was first activated and how the config looked at that time to be able to recreate it.

@Mathnerd314
Copy link
Contributor

So, we should generate the UID's somehow. I don't really like hashing. According to this blog post, with 100 usernames there's around a 1e-6 chance of hash collision. I guess that's OK on a single system, but since this is NixOS-wide I don't think it'll work (people generally choose unique usernames, as soon as NixOS gets near a million users, one of them is going to collide with "root" or "smbd" or something). In general, any static method of generation has problems; it has to be super-global ("everything is special!"), assigning UID's to not only the programs you use but also any programs you might ever think of using. Considering IP addresses, which are 32 bits as well and running low, this method leads to problems. config/ids.nix is already getting out of hand. I'm sure it could work somehow (the internet works, somehow...), but I don't like it.

To see why, let's take root, which currently is hard-coded in the kernel to UID 0. A hacker comes along and figures out a bug in setuid that lets him set it to anything; he sets it to 0, boom! System pwned. Any other privileged service with a fixed UID has similar problems. Suppose instead that we added a /proc entry for root's UID, and generated every uid completely randomly ("nothing is special!"). Now a hacker has to do two things to pwn our system: hack setuid, and determine which uid is root. If we run our webserver in a chroot with limited/no access to /proc or the passwd service, his life is suddenly a lot harder.

Randomness is a slightly weaker guarantee than purity, but still pretty strong. Instead of the guarantee that if a system ever activated successfully then it will do so again, as purity ensures, randomness ensures that, if a system successfully activated the configuration, it's "almost certain" to activate again. In the case of UID's, the probability of it activating again by chance alone (because a UID is shared across runs) is less than 1/2^32. That's also the chance of 2 users colliding in a hash, but in this case it's localized in space and time - it's only two successive runs on the same machine that might collide, not all users over all time. The entropy "compartmentalizes" the mutability away, so it is distinct from the functioning of the system. The only meaningful operation on UID's is comparison for equality, and randomness can enforce distinctness easily while scaling to all 2^32 possible users using an O(n) random shuffle algorithm, which hashing does not and can not provide.

In terms of implementation, I'm guessing patching the kernel to not hard-code root might take a while, so for the time being we can just special-case it, like /bin/sh is/was special-cased. Binary-level compatibility can be achieved by wrapping programs in user namespaces. Other than that, it's just changing the activation script to generate UID's randomly, write the right passwd file, and chown the proper entries. There might be bugs where someone reboots and suddenly can't log in to /home/whatever because it's owned by a different UID that doesn't exist anymore, similar to what someone reported with lightdm. But that will be a persistent, >99.999%-reproducible bug, and thus easy to fix by correctly propagating UID's during activation. From a quick grep, it looks like most activation scripts do stuff by username anyways. On the other hand, there will be no need at all for UID assignment. We could also extend this to randomizing other things, e.g. directories like /var/setuid-wrappers, but that can come later.

@CMCDragonkai
Copy link
Member Author

Is there an algorithm for producing an absolute GUID? Something is unique no matter what happens across all independently running worlds.

Is it possible to create IDs that are universally unique without needing to check some sort of registry. Like atomic level IDs. There is 0% probability of collisions.

@Mathnerd314
Copy link
Contributor

No and no. There are things that come close, using things like MAC address or system time, but they aren't guaranteed unique and their power comes from the centralized data (UTC is a world standard and MAC addresses are unique per manufacturer). But they definitely don't work in this case, because they need lots of data bits and here we only have 32.

@CMCDragonkai
Copy link
Member Author

You can use base 85 or base 100 to shorten the length.

Also is our DNA unique no matter what? Or is there a probability that the universe might create a duplicate person? :)

@Mathnerd314
Copy link
Contributor

Sure, but you can't store a 128-bit UUID in a 32-bit kuid_t without losing the uniqueness property...

And I'm going to say no again, although cloning is probably more likely than random chance.

@CMCDragonkai
Copy link
Member Author

I think you can. Basically the longer UUID is using things like Base 2. It gets encoded into Base 85 resulting in a shorter by character string, but it can easily be reverted back to Base 2 to get the longer string. This is how IPv6 works where the base2 representation is long, but the hexadecimal is shorter. Basically you're not "compressing" the string, you're encoding it...

Unless I'm misunderstanding something.

@wmertens
Copy link
Contributor

It takes forever to change ownership on a large homedir... And this also
means nfs no longer works for sharing a homedir...
All for pretty little gain...
On Jun 13, 2014 6:05 AM, "Mathnerd314" [email protected] wrote:

So, we should generate the UID's somehow. I don't really like hashing.
According to this blog post
http://blogs.msdn.com/b/ericlippert/archive/2010/03/22/socks-birthdays-and-hash-collisions.aspx,
with 100 usernames there's around a 1e-6 chance of hash collision. I guess
that's OK on a single system, but since this is NixOS-wide I don't think
it'll work (people generally choose unique usernames, as soon as NixOS gets
near a million users, one of them is going to collide with "root" or "smbd"
or something). In general, any static method of generation has problems; it
has to be super-global ("everything is special!"), assigning UID's to not
only the programs you use but also any programs you might ever think of
using. Considering IP addresses, which are 32 bits as well and running low,
this method leads to problems. config/ids.nix is already getting out of
hand. I'm sure it could work somehow (the internet works, somehow...), but
I don't like it.

To see why, let's take root, which currently is hard-coded in the kernel
to UID 0. A hacker comes along and figures out a bug in setuid that lets
him set it to anything; he sets it to 0, boom! System pwned. Any other
privileged service with a fixed UID has similar problems. Suppose instead
that we added a /proc entry for root's UID, and generated every uid
completely randomly ("nothing is special!"). Now a hacker has to do two
things to pwn our system: hack setuid, and determine which uid is root.
If we run our webserver in a chroot with limited/no access to /proc or the
passwd service, his life is suddenly a lot harder.

Randomness is a slightly weaker guarantee than purity, but still pretty
strong. Instead of the guarantee that if a system ever activated
successfully then it will do so again, as purity ensures, randomness
ensures that, if a system successfully activated the configuration, it's
"almost certain" to activate again. In the case of UID's, the probability
of it activating again by chance alone (because a UID is shared across
runs) is less than 1/2^32. That's also the chance of 2 users colliding in a
hash, but in this case it's localized in space and time - it's only two
successive runs on the same machine that might collide, not all users over
all time. The entropy "compartmentalizes" the mutability away, so it is
distinct from the functioning of the system. The only meaningful operation
on UID's is comparison for equality, and randomness can enforce
distinctness easily while scaling to all 2^32 possible users using an O(n)
random shuffle algorithm, which hashing does not and can not provide.

In terms of implementation, I'm guessing patching the kernel to not
hard-code root might take a while, so for the time being we can just
special-case it, like /bin/sh is/was special-cased. Binary-level
compatibility can be achieved by wrapping programs in user namespaces
http://lwn.net/Articles/532593/. Other than that, it's just changing
the activation script to generate UID's randomly, write the right passwd
file, and chown the proper entries. There might be bugs where someone
reboots and suddenly can't log in to /home/whatever because it's owned by a
different UID that doesn't exist anymore, similar to what someone reported with
lightdm http://comments.gmane.org/gmane.linux.distributions.nixos/12234.
But that will be a persistent, >99.999%-reproducible bug, and thus easy to
fix by correctly propagating UID's during activation. From a quick grep, it
looks like most activation scripts do stuff by username anywa ys. On the
other hand, there will be no need at all for UID assignment. We could also
extend this to randomizing other things, e.g. directories like
/var/setuid-wrappers, but that can come later.


Reply to this email directly or view it on GitHub
#2821 (comment).

@rickynils
Copy link
Member

@Mathnerd314 "chown the proper entries" can be a somewhat expensive operation, if you have sizeable SAN attached or so. Just an ordinary /nix/store can get quite unwieldly. Not to mention filesystems that happens to be offline during activation.

I don't understand the desperate need to not specify uids in the configuration. As long as we deal with filesystems that handles file permissions by means of mutation, we need a way to map our configs to that reality. Now, if you would give me a fs with declarative permissions, things would look considerably better.

I admit that the way NixOS specifies uids/gids for different services is unsustainable. I think that responsibility should be moved out of NixOS and put on the user instead. I'm not sure how to do that in a convenient way though.

Another possibility could be to run all services as root, but properly isolated in containers that specify what state they are allowed to modify.

@CMCDragonkai
Copy link
Member Author

I've always considered running everything as root would make everything easier. Especially with throw away containers/machines.

@Mathnerd314
Copy link
Contributor

@wmertens Well, NFSv3 security sucks... to let the UID model match, it looks like you should use all_squash and map anonuid/anongid to the owner of your homedir. NFSv4 changes the wire format to pass usernames and do actual user authentication, so there UID mapping should work (using idmapd), although apparently RPC is still insecure so I guess you have to use all_squash there too unless you set up Kerberos. But you do gain declarativeness, which IMO is nontrivial; if you don't want that, why are you using NixOS instead of e.g. Debian?
@rickynils For everything you list, e.g. offline filesystem, sizable SAN, etc., the same exact problem exists whether or not the UID's are "user"-configured or not - if they change, then things break. As I said before, configuring the uid's might work, but only if NixOS takes on responsibilities like IANA and assigns every single username ever a fixed number. Otherwise, two configurations assign the same UID to two different usernames, then you try to change from one configuration to the other, and everything breaks. Say you have a thumb drive with an ext4 filesystem on it, and you move it between two machines. Without an IANA-like centralized registry, the UID's will be different in some cases and overlap badly in other cases. Random UID's ensure that they's almost always different, which IMO is a lot better than usually-different-but-in-some-unfortunate-cases-the-same.
I agree the proper solution is to store something in the filesystem, e.g. a UID<->user mapping. That lets us pick both random activation-time UID's and random filesystem-user-creation-time UID's, and gives us various options on how to handle nonexistent users, privileged users, or nonexistent UID-maps. The function stubs for the translation are already in the kernel, although they're no-ops currently, so the only hard part is figuring out how to make the filesystem store the mapping. I'm uncertain as to how long a patch like that would take, but definitely longer than a NixOS patch.
Until that's written, I suggest a flag alwaysUseRandomUIDs which when false preserves existing UID's and assigns new ones randomly and when true assigns everything randomly on every activation. Setting it to false doesn't ensure that the add user->remove user->re-add user case is bug-free, like setting it to true would, but the false users would still benefit from fixing the bugs found in the true case.
Running everything as root is indeed a possibility to look into, but I doubt that containers have enough flexibility or security-testing yet to match the uid/gid model, although maybe chroot + capabilities + UserNS will work. If it does, there's no reason to use uid's at all, or rather every file/directory will have uid 0 (processes can also have uid 0, or we can wrap and remap it to uid 1).

@Mathnerd314
Copy link
Contributor

I looked into running everything as root a bit more; here's a nice image from libcap-ng that shows a little of how the bounding capability set restrictions might work: (Note though that users/shells allowed to use su or sudo should actually have unbounded privileges, and just lower their effective privileges, although programs they run might drop privileges).
untitled
So it looks like the kernel support is in fact there, in terms of capabilities, mount namespaces, etc.. In user space, though systemd has options for setting capabilities and mounts on services, it hard-codes "don't be mean to root" in a few places, so I'm guessing it will need a few patches. libcap has a PAM module, so user permissions and stuff should work, or I guess systemd can handle that too (#1689).

@CMCDragonkai
Copy link
Member Author

@Mathnerd314 hey I'm trying to understand what you're trying to say, but if you could summarise in dot points what are the advantages/disadvantages with fixed UID/GID versus randomised UID/GID versus running everything as root + containers, I believe this would help me and others engage in this interesting conversation more.

@Mathnerd314
Copy link
Contributor

Ok, I tried to do that with my first post but I guess it grew out of hand; hopefully this one is shorter.

  1. Normal UID/GID management (like in other distros, similar to before Generate /etc/passwd and /etc/group statically #1076) has the advantage of fitting in with traditional distro management styles. So the tooling is there, the API's / software understands it, etc. We could just revert Generate /etc/passwd and /etc/group statically #1076 or change mutableUsers=true to be more like the previous behavior (use useradd, allow missing uid's/gid's, etc.) But it leaves some corner cases hanging around and isn't "the NixOS way".
  2. Fixed UID/GID management, with "normal" assignment conventions, doesn't really work unless we can make that convention NixOS-global. The current convention, as enforced by Generate /etc/passwd and /etc/group statically #1076 and mutableusers=false behavior, is unsustainable. Hashing could theoretically salvage it, but UID's are only 32 bits and e.g. system ID's are typically <1000, so AFAICT there's no way to make it actually work.
  3. Random UID/GID assignment is its own convention, so it does "work" in terms of implementability. The main issue is that it means the UID's have to change every time you re-activate to test that things are working, which requires chown'ing the entire filesystem every reboot, which is slow. There are probably ways to skip this or make it faster, but that same effort could be invested in the next option.
  4. Assigning everything uid 0 is another implementable convention, and it has the virtue of being consistent so there's no chown'ing needed. However, general *nix wisdom considers running everything as root to be a Bad Thing™, so it needs a lot of caution and extra configuration options to make certain that getting rid of uid's doesn't also get rid of the security rules that uid's enforced. On the other hand, from what I can tell, the linux capabilities model is actually simpler and better documented than the model imposed by setuid, seteuid, and friends.

@wmertens
Copy link
Contributor

You know, having a uid registry for daemon users is totally doable, we
don't have millions of daemons in nixpkgs.

So create a list of users and uids in a uids.nix file, which you amend for
every added service, with numbers in the high 32 bit range.

Those could be overridden if needed, and everything is declarative.

Regular users still need uids, and that is not a big deal imho.
On Jun 14, 2014 7:49 AM, "Mathnerd314" [email protected] wrote:

Ok, I tried to do that with my first post but I guess it grew out of hand;
hopefully this one is shorter.

  • Normal UID/GID management (like in other distros, similar to before
    Generate /etc/passwd and /etc/group statically #1076 Generate /etc/passwd and /etc/group statically #1076) has the advantage
    of fitting in with traditional distro management styles. So the tooling is
    there, the API's / software understands it, etc. We could just revert
    Generate /etc/passwd and /etc/group statically #1076 Generate /etc/passwd and /etc/group statically #1076 or change
    mutableUsers=true to be more like the previous behavior (use useradd, allow
    missing uid's/gid's, etc.) But it leaves some corner cases hanging around
    and isn't "the NixOS way".
  • Fixed UID/GID management, with "normal" assignment conventions,
    doesn't really work unless we can make that convention NixOS-global. The
    current convention, as enforced by Generate /etc/passwd and /etc/group statically #1076
    Generate /etc/passwd and /etc/group statically #1076 and mutableusers=false
    behavior, is unsustainable
    Generate /etc/passwd and /etc/group statically #1076 (comment).
    Hashing could theoretically salvage it, but UID's are only 32 bits and e.g.
    system ID's are typically <1000, so AFAICT there's no way to make it
    actually work.
  • Random UID/GID assignment is its own convention, so it does "work"
    in terms of implementability. The main issue is that it means the UID's
    have to change every time you re-activate to test that things are working,
    which requires chown'ing the entire filesystem every reboot, which is slow.
    There are probably ways to skip this or make it faster, but that same
    effort could be invested in the next option.
  • Assigning everything uid 0 is another implementable convention, and
    it has the virtue of being consistent so there's no chown'ing needed.
    However, general *nix wisdom considers running everything as root to be a
    Bad Thing™, so it needs a lot of caution and extra configuration options to
    make certain that getting rid of uid's doesn't also get rid of the security
    rules that uid's enforced.


Reply to this email directly or view it on GitHub
#2821 (comment).

@Mathnerd314
Copy link
Contributor

On Sat, Jun 14, 2014 at 12:05 AM, wmertens [email protected] wrote:

You know, having a uid registry for daemon users is totally doable, we
don't have millions of daemons in nixpkgs.

No, we have something even worse - concurrent development. Say person A
assigns uid 123 to his daemon, and person B assigns the same uid to some
other daemon. Now they can't merge their development without (a) choosing
an ordering and (b) changing the uid's to match. The uid registry is
non-modular and hinders doing anything interesting with daemons.

@rickynils
Copy link
Member

But if the daemon modules are abstracted over the uids they need, the user that imports the modules is responsible for assigning non-conflicting uids. I don't see why the uids must be hard-coded in the modules? I mean, if the daemons stores data at some path, this could possibly also conflict, but it is quite natural to have a datadir option and let the user handle conflicts.

I think it makes perfect sense to let the user manage the uid registry, since it ultimately depends on how the surrounding environment looks like (filesystem contents, fileservers, other daemons etc).

On June 14, 2014 8:15:17 AM CEST, Mathnerd314 [email protected] wrote:

On Sat, Jun 14, 2014 at 12:05 AM, wmertens [email protected]
wrote:

You know, having a uid registry for daemon users is totally doable,
we
don't have millions of daemons in nixpkgs.

No, we have something even worse - concurrent development. Say person A
assigns uid 123 to his daemon, and person B assigns the same uid to
some
other daemon. Now they can't merge their development without (a)
choosing
an ordering and (b) changing the uid's to match. The uid registry is
non-modular and hinders doing anything interesting with daemons.


Reply to this email directly or view it on GitHub:
#2821 (comment)

@Mathnerd314
Copy link
Contributor

So then why did you write this whole "declarative users" patch? The user is not a configuration.nix file.

@wmertens
Copy link
Contributor

@Mathnerd314 while that is strictly true, in practice it doesn't matter a whole lot. Changing one number is ok, plus you get to pick any number > 2^31 so collision is not super likely.

@rickynils not having to pick a uid but having the option if necessary is more fun :-)

@rickynils
Copy link
Member

@Mathnerd314
But the user needs a sensible, declarative tool to manage the uid registry in a reproducable fashion. And if NixOS knows about the uids, we can notice conflicts automatically.

I don't think mutableUsers = false breaks modularity, as I described above. Can you explain why you think it does that?

@Mathnerd314
Copy link
Contributor

When mutableUsers=false, if you change the uid in configuration.nix, it doesn't change every uid on the associated filesystems. This means the state given given by install->x.uid=1->x.uid=2 is not the same as install->x.uid=2, i.e. mutableUsers=false is not declarative, and, since there's state in two places, the NixOS configuration and the filesystem, not modular either.
The methods I've proposed designate one place, either on disc (1,3) or in NixOS's configuration (2,4), as the primary location. Methods 1 and 2 don't ensure that the filesystem and NixOS are synchronized, and thus are non-modular. Methods 3 and 4 do ensure this, by making things break if they get out of sync. Method 3 is under-permissive by default while method 4 is over-permissive by default.

@rickynils
Copy link
Member

@Mathnerd314, just for the record, mutableUsers = true should behave like your suggestion 1. If it doesn't, please file an issue about it so I can look into it.

@rickynils
Copy link
Member

@Mathnerd314 Please open issues or PRs for your suggestions 3 and/or 4. We should close this issue since it's too undefined.

@Mathnerd314
Copy link
Contributor

I did a little more research on this and it looks like Lennart is writing his own user-id daemon. It re-implements solution 1 in a nicer way than before; now you just have to write a (static) sysusers.d file, point systemd to the directory containing those files, and systemd will assign the UID's. It's included in systemd 215, released a few days ago. Assuming we switch to it, that means UID randomization (3) will be a systemd feature request or two. Opened #3191 for switching to systemd-sysusers.

After researching solution 4; it looks like it needs a RBAC like SELinux to properly enforce; I'm guessing we probably don't want to require using a RBAC, so discarding that solution in favor of #3191.

Finally, as for the original issue. I think that mutableUsers=false should just go away, as it's fundamentally broken for NixOS to specify UID's; they can only be assigned freely on a clean disk. However, a read-only /etc makes sense regardless of a clean install, so I have filed #3192.

@rickynils do these two changes satisfy your original goals for introducing mutableUsers?

@rickynils
Copy link
Member

mutableUsers=false is not broken for "non-clean" disks. It always replaces /etc/passwd with a static one from the nix store. Uid collisions are therefore guaranteed not to happen.

The systemd way could be nice, but I guess the uids would be unpredictable? If you, like me, have /etc on tmpfs, systemd would assign new uids on each boot (if users had been added/removed). Of course, if there's a way to specify uids in sysusers.d then that could be solved.

@lucabrunox
Copy link
Contributor

Sorry but what's the advantage of systemd-sysusers?

On Sun, Jul 6, 2014 at 7:51 AM, Rickard Nilsson [email protected]
wrote:

mutableUsers=false is not broken for "non-clean" disks. It always replaces
/etc/passwd with a static one from the nix store. Uid collisions are
therefore guaranteed not to happen.

The systemd way could be nice, but I guess the uids would be
unpredictable? If you, like me, have /etc on tmpfs, systemd would assign
new uids on each boot (if users had been added/removed). Of course, if
there's a way to specify uids in sysusers.d then that could be solved.


Reply to this email directly or view it on GitHub
#2821 (comment).

www.debian.org - The Universal Operating System

@Mathnerd314
Copy link
Contributor

@rickynils I change ntp=3 to ntp=4; mutableUsers=false does a blind&dumb overwrite of /etc/passwd; now my system is broken because ntp can't write to /var/lib/ntp. That is why mutableUsers=false is broken - it will very easily break my system.

According to Lennart, he supports three configurations (s/usr/nix/ for this discussion):

  1. All of /etc, /var, and /home are on a tmpfs, while /nix is persistent
  2. /nix and /etc are persistent, /var and /home are on tmpfs
  3. All of /nix, /etc, /var, /home are persistent

I am not certain which one your system is closest to; if it is (1), then this change should not matter, if it is (2) or (3), then you will need to use a real filesystem for /etc.

@lethalman Systemd-sysusers has more features and error-checking than the current shell script.

@domenkozar
Copy link
Member

this can be closed right?

@Mathnerd314
Copy link
Contributor

Yeah. the current situation is reasonable enough, and the rest can happen in #3191.

@jgillich
Copy link
Member

@domenkozar Do it ;)

@peti peti closed this as completed Dec 26, 2015
@CMCDragonkai
Copy link
Member Author

So is the conclusion is to just rely on systemd?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

9 participants