-
-
Notifications
You must be signed in to change notification settings - Fork 1.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
[BUG] Cannot run as unprivileged container #340
Comments
Welcome to Dashy 👋 Issues are sometimes closed when users:
Before you reopen this issue, please also ensure that:
Once you have verified the above standards are met, you may reopen this issue. Sorry for any inconvenience caused, I'm just a bot, and sometimes make mistakes 🤖 |
Sudo privileges are not be required to run the app. But let me look into it, I run it with a non-privileged user, so haven't come across this issue before. Could you share the console output? |
Lissy, here you go:
Tested on a RHEL 8 based host (functionally the same as CentOS 8, Rocky Linux 8, etc) with Docker CE. Also verified that the issue exists with SELinux policy enforcement disabled. Could you please provide a sanitized copy of your compose file or Docker options? Also a procps/ps output displaying the container processes, which is the only effective way to prove that the container is indeed running unprivileged. Also, you must take into account that the only real safe way to operate a Docker container under the privileges of an unprivileged user is to start it already as that user. Dropping privileges and capabilities on runtime is a tricky game, and often any leftover privileges can be used to re-escalate. You can find a very extensive look at this issue here: Now, back to our issue with Dashy: so far, nothing I have observed, using the compose file suggested, or the arguments in the documentation you provide, results in effective privilege removal:
Once the build completes, the situation is the same:
The compose file used to produce the above output: Exactly the same as you suggest in the documentation. I'm time constrained, but a cursory look through your code (entrypoint scripts, etc) indicates there is no use of the provided UID/GID, and definitely the container executes as root:
With a whole host of unwise groups (dialout can allow privileged IO to devices, video can allow the same to GPU devices, etc...). Furthermore, searching for files owned by the UID/GID confirms this:
You should mark this as a security issue, as the documentation provides a false sense of security with the implicit assumption that privilege drop will work, where this is obviously not the case. The way the image is developed, it assumes and relies on running as root as far as the above tests show. |
Missed an additional output:
Some notes to clarify why this is a Dashy issue and not a deployment issue: you cannot rely on a non-root user operating the docker daemon socket as your assumed privilege level. In other words, if user Z within the 'docker' group was to run this container it would still not make any difference as he has effective privileges to communicate to the docker daemon, and this allows trivial root escalation in most configurations. Running docker root-less would mitigate this, but this still does not displace responsibility away from the container developer: the technically appropriate way to run a container as another user, beyond dropping privileges inside (which is better than nothing but still suboptimal) is to use the 'user' directive in the compose file so that the container is instantiated from the very beginning as a non-root user. For this to work, you need to fix the directory permissions and owner assignments and cleverly leverage DAC to allow whatever upgrades/writes must be done, without allowing anything beyond the necessary. The place to do this is the entrypoint of the container, or, optionally, an altered entrypoint and custom Dockerfile. If you can provide me with a list of sensible directories that need to be written to on runtime, I can probably test it for you sometime today. Hopefully this clarifies the context and problem in depth. FTR, most folks get it wrong as far as privilege drop goes with docker, and if you learn from most docker containers and how they are built you will find very few actually developed from the ground up to tolerate, let alone work well with, running with an unprivileged user in the 'user' directive. In some cases they also resort to using a nobody:root approach, where the container user still runs with root group privileges. |
Had a moment to give this a go, this Dockerfile essentially fixes the problem but should not be used as-is:
Note that /.cache needn't be owned by the user, and so forth. You might need to very carefully consider if you want self-buildable objects at all. I highly suggest against this. If an user wants to upgrade he can do so from your signed image upstream or one in his own registry. The content of the image should be as static as possible, save for the config. In any case, using user: 9999:9999 this will allow the image to run fully disengaged from the privileges of root or the user in the docker group that launched the container:
|
Thank you so much for all the details, it's super helpful :) |
Hello Lissy, Yours is a hobby project and I (and our company) have a policy of reporting security bugs in cases like yours (if you were a big traded corp we wouldn't do it ;-) ) and helping whenever we can. I'm on a tight schedule at the moment but since I have personally used your project to save myself some work for internal dashboards that link to a plethora of services that I deploy for testing, I can try to help you. OK, so:
You can take a look at how linuxserver containers do the privdrop and also how they span commands. Since I'm not very knowledgeable with JS frameworks, I'm not quite sure how much you need to be 'mutable' on runtime. Let me know if this helps. I can review whatever you implement, but this should get it going. You can always just use a static GID/UID, but make sure you chmod/chown and take care of permissions and print errors if something is off. Permission issues are annoying to debug because they often show up in abstract errors and finding the origin requires grepping through a lot of source. Also, this isn't your fault. The Docker documentation isn't exactly great for this and they are lacking a simple tutorial covering this. The marketing also doesn't help. Docker has been billed as a security "as a feature" thing until very recently, but the damage is done. It was meant to be used for development and reproducible testing, not containment or isolation. All the security features in Docker are patchwork. |
This issue has gone 6 weeks without an update. To keep the ticket open, please indicate that it is still relevant in a comment below. Otherwise it will be closed in 5 working days. |
Still relevant. /keep-open |
Did some tests and came to this docker-compose file that works:version: '3.7' networks: volumes: services: |
This comment has been minimized.
This comment has been minimized.
Check it out: https://github.com/nallej/HomeStack/blob/main/Dashy/docker-compose.yml
|
Awesome, thank you so much!! I am away from home this week, but will test and mege next week. |
This comment was marked as off-topic.
This comment was marked as off-topic.
Thank you @Singebob 🙌 :) |
Hello @Lissy93 👋 As of today I cannot get the latest (v2.1.1) image running with non-root user, neither by using the Am I missing something? |
I can confirm. This is the same for me with the following docker-compose file, which is adapted to run on an Umbrel node. I confirmed the user ID and group ID by running
|
I will suggest to look into using FROM ... AS ... constructs in the Dockerfile. Build the image on top of a working base, but make the one meant to be deployed immutable. This will also solve the problem with necessitating a bunch of permissions from the get go. |
Signed-off-by: Bjorn Lammers <walkxnl@gmail.com>
Environment
Self-Hosted (Docker)
Version
Latest
Describe the problem
Despite what the documentation says, it seems that Dashy fails to both drop privileges and run under an unprivileged user (via --user argument or in compose).
The compose file below can be used to reproduce the issue.
The expected result is that the UID and GID values, matching the user argument, would work properly together to launch the container in a fully unprivileged state.
The actual result is that it fails to start and the entire build/prep process depends on root privileges being effective at launch.
Additional info
No response
Please tick the boxes
The text was updated successfully, but these errors were encountered: