-
-
Notifications
You must be signed in to change notification settings - Fork 14.4k
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
Comments
But how will you guarantee identical ordering on two systems running the Wout.
|
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. |
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. |
That is fine. It can act the same as when mutable is true, but after configuring, it will make immutable. |
No, it is not fine. |
There can be 3 situations:
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? |
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. |
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? |
I'm pretty sure that I would explain the purpose of IMO, idempotency might be a better descriptor than immutability - given a 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 (Edited: resolved an ambiguity.) |
@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. |
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 same |
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. |
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. 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 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 |
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. |
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. |
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? :) |
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. |
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. |
It takes forever to change ownership on a large homedir... And this also
|
@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. |
I've always considered running everything as root would make everything easier. Especially with throw away containers/machines. |
@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? |
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). |
@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. |
Ok, I tried to do that with my first post but I guess it grew out of hand; hopefully this one is shorter.
|
You know, having a uid registry for daemon users is totally doable, we So create a list of users and uids in a uids.nix file, which you amend for Those could be overridden if needed, and everything is declarative. Regular users still need uids, and that is not a big deal imho.
|
On Sat, Jun 14, 2014 at 12:05 AM, wmertens [email protected] wrote:
|
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:
|
So then why did you write this whole "declarative users" patch? The user is not a configuration.nix file. |
@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 :-) |
@Mathnerd314 I don't think mutableUsers = false breaks modularity, as I described above. Can you explain why you think it does that? |
When |
@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. |
@Mathnerd314 Please open issues or PRs for your suggestions 3 and/or 4. We should close this issue since it's too undefined. |
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) 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 @rickynils do these two changes satisfy your original goals for introducing mutableUsers? |
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. |
Sorry but what's the advantage of systemd-sysusers? On Sun, Jul 6, 2014 at 7:51 AM, Rickard Nilsson [email protected]
www.debian.org - The Universal Operating System |
@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 According to Lennart, he supports three configurations (s/usr/nix/ for this discussion):
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. |
this can be closed right? |
Yeah. the current situation is reasonable enough, and the rest can happen in #3191. |
@domenkozar Do it ;) |
So is the conclusion is to just rely on systemd? |
When making:
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?
The text was updated successfully, but these errors were encountered: