-
Notifications
You must be signed in to change notification settings - Fork 307
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
Raspbian / RaspberryPiOS no longer allowing user Pi #542
Comments
I am reasonably sure that there are no actual dependencies on There are quite a few "bad examples" ("bad" since 2020-04-04) in the documentation which should probably be turned into "better" examples. But those don't affect anything.
Quite a few templates have things like With IOTstack, the "user pi" at "/home/pi" with "ID 1000" has always been more about testing. Those being the defaults (until now) they got a lot more testing than any "roll your own". Stating those assumptions explicitly has always been directed more towards getting each user to at least ask themselves the question, "if I've rolled my own environment, is it possible that that explains my current problem?" I might turn out to be wrong but we'll only really know if/when issues are opened pointing to specific incompatibilities. Fingers crossed... |
The answer to the ID=1000 question is that if you select a different username (eg "me" instead of "pi") in Raspberry Pi Imager, that user (ie "me") gets ID=1000. So that means all the |
ideally, for me, there wouldn't be any hardcoding. It's fine to assume that the folder iotstack should exist in the $home folder but there shouldn't be any presumption about the user being 1000, or that you're running on a PI. It should be detected or enumerated. I would go so far as to say that, in the case of bluetooth for instance, it should be enumerable and an env flag set for the remainder of the session. Yes, I know this makes it more work, and more difficult, it's just my opinion. |
Well, any of us saying "shouldn't" is true. But there are just so many containers that assume ID=1000 that it becomes a practical question of how to adapt them. Every individual user is entirely free to declare, "I don't want to use 1000, I want to use X". But it is then up to that person to follow through and make sure that none of the containers they want to run depends on 1000 and, if it does, fix it. |
Possibly the other answer is to create a user and/or group called IOTStack and assign it all to that user/group. Yes this abstracts everything away from rasppi but the more abstraction there is, the less you're dependant on third party changes ? |
It's probably time for a somewhat longer response to your question. First, a bit of conceptual background to set the scene. The web is full of information about processes that have been "containerised" along with examples of how to use those containers in a docker environment. I'm sure you've seen them. In general, they break down into:
If you took a random sample of group #2 off the web, you'd find a whole bunch of different approaches. In particular, examples differ in:
If you concatenated a random sample of group #2 service definitions into a IOTstack is not a "system", as such. It's a set of conventions which are designed to give you a better-than-even chance that a group of containers you select from the menu will work out-of-the-box. In particular, IOTstack's conventions:
A key thing to keep in mind is that, we (IOTstack) still have to work within the rules and constraints imposed by docker and docker-compose. After a clean clone from GitHub, there is no
docker-compose will do the equivalent of:
On first launch, When the WireGuard container starts, it does the equivalent (from inside the container) of:
The container is running as root so these changes propagate to the external file system. I assume the logic is to minimise the need for the user to use
The obvious next question is, where does the WireGuard container get PUID and PGID? Answer, via environment variables contained in its service definition:
That's the template. In a running system the menu would have copied the template into At this point, it's probably a good idea to get an appreciation for the extent of this general pattern:
Your next thought is likely to be, "why not abstract all those hard-coded Let's go back to the WireGuard service definition and add another environment variable:
Now I'll tell docker-compose to apply that:
And now I'll prove that
I assume you know that
So let's try this pattern in the compose file:
Apply that:
The same thing happens if I substitute EUID. It's probably because those variables are either given special handling or aren't exported. Let's try setting up our own variable and exporting it:
Editing:
Testing:
That works. As a strategy for getting the current UID into containers, you would only need to do something like add
Some comments:
Bottom line: ID=1000 is where it's at. We are reasonably sure that the actual username "pi" does not matter. But we are equally reasonably sure that s/he who futzes with ID=1000 will find her/himself neck deep in repair work. Should it be that way? Perhaps not. But IOTstack isn't responsible for this state of affairs. You really need to discuss the problem with the maintainer of every container that needs to know the ID of the external user. Does that answer your question? By the way, I like to explore questions of this kind in a reasonable amount of detail because, for every person who asks something like this, there are bound to be plenty of others who are wondering about it. I reckon it's better to try to cover-off as much of the how, what, when, where and why as possible. Plus, everything I write is implicitly tied to my own limited knowledge and questionable assumptions. I'm no expert. You, or someone else following this thread may well spot the flies in my logical ointment, find a solution, and we all benefit. Go for it! |
Thank you for generously taking the time to explain the logic. I guess sometimes things are just the way they are and it would take a larger amount of effort to try and change it, than to go along with the current. Thanks again for your time. I appreciate it. |
I've been doing some reading, and investigation, and nothing I'm going to state here detracts from your excellent synopsis above. Apparently a good way of getting the current userid is in a dockerfile (which is not appropriate for most of this) it can be done, I believe, as follows: RUN export currentuserid=$(id -u);echo $currentuserid; I think another fair perspective is that a user id is arbitrary (which is harder programmatically) unless it's standard i.e. root or pi (which is worse from a security perspective). My view would be to create an IOTuser and an IOTgroup and set everything to that (no different to how most daemons act) . Which would also mean that uninstallation would be easier, and the locations of files could be prescribed definitively and from a security perspective minimum rights, and smaller attack surface. I would also be inclined to include a random password generator, generate passwords for each service and drop them, and the full urls into a reference file which could then be used to import in to a password manager and/or book mark manager. At this point the conversation has descended in to conjecture, design and opinion, for which I apologise. Thanks for tolerating my blathering. |
Any problems with a solution to:
I can implement, update docs and make the PR. |
I, personally, would prompt/test to create an IOTStack user and group with a random pwd (logged) but I'm sure you both know better than me (newb). Perhaps give the option to run as current user if an additional user is not desired. Thanks for the effort you've all put in, I appreciate it. |
The new Raspberry OS installer already prompts user/pw.
This user used in containers is just for convenience, so that your main login can access files it creates without using sudo. Nothing to do with security. Regardless of what you choose, the service will work. |
That will change if you ever implement a samba service or something similar ? Either way, if you say it's fine, it's fine :-) |
@ukkopahis the only "problem" is the containers that do support some form of ID environment variable but where we (IOTstack) haven't yet captured it in our templates. Those will still default to 1000. I've only really noticed this in passing so don't quote me if I'm mis-remembering but I think it's the LinuxServer builds which do that. I'm not sure this matters in the scheme of things. After all, we get the occasional "WTF?" question about 1883 for Mosquitto which does no real harm so, if the current ID is not 1000 and there are containers assuming it is, the worst that is going to happen is the need to use sudo when mucking about in volumes. Like that's an exception to the rule... On balance, I'd say "go for it". It will capture a reasonable number of cases out-of-the-box and be a standard we can work towards. |
I think you might misunderstand what is going on inside Dockerfiles. When a Node-RED is a good example. At the point of the FROM statement in the Dockerfile, the user in effect is called "node-red" and, guess what, that name is mapped to ID=1000:
See how that ID=1000 keeps popping up. It's a persistent little beast. If you look at IOTstack's Dockerfile for Node-RED, you'll see this kind of pattern (this is my actual Dockerfile for Node-RED - each IOTstack user's is going to be different):
Running It doesn't matter which container you are talking about. Running Plus, the majority of containers come "as is" from DockerHub. It's only a subset where we use Dockerfiles so, even if this did actually work, it would not be a universal solution.
Well, "uninstallation" is both "easy" and "somewhat convoluted", depending on what you want to achieve. It's pretty easy for whatever user you define:
Bang. All gone. However, although it's simple to nuke the current user's IOTstack folder, you are still left with container images. Those exist outside of
I don't mind any of that. Discussion is how we get to solutions. |
This got me thinking. In actuality this statement should be hedged with "as long as the chosen user-id matches the owner of the existing files in volumes". It's rare (and a bit risky) for a container's entrypoint script to do the required 'chown' operations for a changed user-id. It's therefore user's responsibility to match the container As such, when we remove the "User has the user ID 1000" assumption from 'Getting started'-page, we can't change the As example: Assumptions: a) an existing service defaults to PUID=1000. b) the logged-in-user
Therefore the pull-request I'm working on, and all future added services, must in their service.yml set the user-id ("PUID") correctly from the get-go (if the container supports it). Changing it later is a migration headache not worth it. |
A first time user deploying IOTstack on a Pi where ID is not 1000 is probably not too much of a concern because it's probably safe to assume "running the menu" so fixes can be applied. I've been wondering more about the migrating user. Running IOTstack now with ID 1000. Takes a backup, rebuilds a Pi with a different ID, then restores the backup. Not sure what the IOTstack restore scripts do but IOTstackBackup passes the "same owner" flag to tar so everything will come back with the wrong ID. I'm leaning towards dealing with this entire scenario via caveat rather than by code. A sentiment along the lines of
if you get my drift... |
When considering the troubles of accidentally using the wrong UID, I think it's better to not have a default, but use mandatory variables instead: - PUID=${IOTSTACK_UID:?IOTSTACK_UID must be defined in .env}
- PGID=${IOTSTACK_GID:?IOTSTACK_GID must be defined in .env} Then, if by some magic, the end-user manages to delete the .env-file, instead of risking a jolly file-ownership-mess we get a clean error: $ docker-compose up -d --force-recreate pihole
ERROR: Missing mandatory value for "environment" option interpolating ['WEBPASSWORD=%randomAdminPassword%', 'INTERFACE=eth0', 'IOTSTACK_UID=${IOTSTACK_UID:?IOTSTACK_UID must be defined in .env}'] in service "pihole": IOTSTACK_UID must be defined in .env which hopefully alerts the user to the .env-file missing due to problem in his backup, restore, cloning, etc... |
Self inflicted, unforced problem. Redo with better judgment. Practice makes perfect ;) I'll add instruction about this to docs. |
Newb question if that's okay. Why not, as part of the script, chown current $uid:$groupid ~/IOTstack/Volumes if the folder exists ? It won't apply to any externally mounted data but it would be assumed that IOTStack 'owns' the files in that directory ? This is just me learning, this has been a great help to my understanding so far |
Oh, I guess where the docker image doesn't have an option to specify user or group in the dockercompose this will default to 1000 and the chown will possibly break that container. Got it. |
It's not necessarily safe to chown everything in volumes to the current user. Some containers will barf if you change their ownership on them. Next point. There is no way (yet) of hooking a user script to docker-compose so you either have to do it in the menu or supply a script that the user just has to know to run. Not everybody uses the menu (I don't) and the The chown that Dockerfiles do are limited to the container's persistent storage. That's the whole idea of containers - they are contained. But, again, the uid/gid that an internal script uses in a chown can't come from the container. The only real way of getting it the info is what we've been talking about here. |
Not sure how my brain managed to "autocorrect" this as: "preserves owners and permissions, why are you stating the obvious?" 🤣 Anyway, I suspect wrong file owners may cause permission problems in certain corner cases, especially now that we're abandoning the ID=1000 assumption. I'd consider changing it. Did you have a reason to using that flag? |
Though I'm torn on if it'd be better to add to docker-compose.yml: env_file: docker-compose.iotstack.env And have all defaults added into the explicitly declared file. I don't like how This would have to be added to every service, though. |
Well, yes. So that the contents of |
I wholeheartedly agree with your comments on Although it isn't hidden, I also dislike Personally, I have my compose file structured like this:
(I do it that way so I can easily Anyway, that
A wrinkle on the theme might be to first:
and then prepend In theory, the |
So, that would be a candidate for this "header" file too, right? |
Not telling you how to handle this, but if restoring a backup changes file owner from the original 1883 to 1000, some breakage might occur. From man tar:
Yup, but it might contain other stuff than only network at some point in the future. Could be renamed e.g.
That's a good idea, might pick it up for #505 |
Was a nice dream, but doesn't work. Docker docs state:
And by my tests defining an |
I know that the script relies on Pi existing as a user ....
Just wondering if any moves have been made to change this to allow other users with the news that user Pi will be changed going forward?
The text was updated successfully, but these errors were encountered: