motioneye icon indicating copy to clipboard operation
motioneye copied to clipboard

Docker: add support for PUID/GUID

Open ecsufio opened this issue 5 months ago • 9 comments

Good evening everyone, Simple beginner's question, I want to install MotionEye via docker compose, with a specific user (in my example, UID/GID 1000:1000). Can I add the following lines to the docker-compose script?

environment:
  - PUID=1000
  - PGID=1000

Or will this not work?

Thanks for your help!

ecsufio avatar Jul 17 '25 20:07 ecsufio

Use RUN_UID and RUN_GID instead: https://github.com/motioneye-project/motioneye/blob/main/docker/Dockerfile#L4-L6

MichaIng avatar Jul 17 '25 20:07 MichaIng

Thank you for your quick reply. If I understand correctly, here it's better to create an image with the dockerfile rather than using the docker-compose script, right?

ecsufio avatar Jul 17 '25 21:07 ecsufio

Ah yeah right, that only works when generating a new image. motionEye (and motion) within the container runs as motion user, mapped to UID/GID 0 within the container, by default, i.e. with the images provided via container registry.

I see PUID/PGID is sort of a convention to make this dynamic. Looks like a reasonable feature we should implement, and replace the RUN_UID/RUN_GID.

MichaIng avatar Jul 17 '25 21:07 MichaIng

Great! Thanks a lot for your help!

ecsufio avatar Jul 17 '25 22:07 ecsufio

Hello, I'm having some problems creating an image with the dockerfile to assign it a user. Several errors when trying to build the image. I want to install MotionEye on my NAS, the fact that it runs as root was disturbing me. Unfortunately, this is beyond my competencies.

Is there any risk in running MotionEye as root in a Docker container on a NAS ?

ecsufio avatar Jul 18 '25 11:07 ecsufio

Docker containers run always as root anyway. There is a limited option to run it as different user (including the Docker daemon) though: https://docs.docker.com/engine/security/rootless/

But the access of the container is limited to the container image and volumes, so security implications are naturally limited, being one of the reasons for using containers anyway.

Optional UID/GID is about what the related software daemon within the container runs as. This is not really a security feature, but for convenience, since this is the user which creates config/data in the volumes, hence you can define which user outside of the container can access those natively. In this case access to e.g. camera recordings and snapshots. Since it runs with UID/GID by default, motionEye data is owned by root outside of the container, which is not bad, from privacy POV. But it might managing them outside the container easier, if owned by your non-root login user, of course.

I never tried building the Docker image with a different user, TBH, did not create the Dockerfile originally, and did not touch this optional user part. Does it work when building without RUN_UID/RUN_GID? In case, compare with the build command used by our buildx action: https://github.com/motioneye-project/motioneye/actions/runs/16352511452/job/46202665732#step:6:210

MichaIng avatar Jul 18 '25 12:07 MichaIng

To start, I must confess I'm not an expert on Docker at all, but I've done some research on container security due to running stuff in Kubernetes at work, and I have an interest in practical infosec in general.

But the access of the container is limited to the container image and volumes, so security implications are naturally limited, being one of the reasons for using containers anyway.

Optional UID/GID is about what the related software daemon within the container runs as. This is not really a security feature, but for convenience, since this is the user which creates config/data in the volumes

@MichaIng I agree with what you said about the optional UID/GID being more for convenience for MotionEye, and it is true that running things in container adds one level of isolation between the host system and the application/daemon run inside the container.

However, in general it is a commonly recommended best practice these days (like in OWASP Docker security cheat sheet) that one should not run stuff as root (UID 0 / GID 0, it doesn't really matter if it's called "motion" or "root") since it also has consequences to what level of access the process within the container has: non-root users cannot modify system files, install packages etc. Non-root users also cannot access root owned files in the host filesystem (or create files owned by host root user) even if the container had been given a volume mount that was not thought through. Also, in case of container escape, if the attacker had root access inside the container, they would immediately gain root access also to the host system.

The importance of all this depends of course on the threat model. For a home user who only allows access to MotionEye from their local LAN/Wifi, and trusts their fellow users in the network, it's probably not a big deal if stuff is run as UID 0 in the container. But things change if one allows access to MotionEye from the internet, uses it for business purposes, tweaks the configs to adjust to some custom needs, mounts host file system carelessly etc and/or just isn't techically savvy enough to understand what they are doing when following some random advice found on the Internet.

In a simple case where no mounted volumes are needed and you don't have dependencies within the image that expect some specific user, running as a custom non-root user in container is a piece of cake, but indeed it gets a bit more complex when you have dependencies and need to access stuff external to the container, or when you provide your images for others to run... 😅

zagrim avatar Jul 19 '25 07:07 zagrim

In the end the question is what you want to protect from what: in case of camera recordings, usually they are somewhat sensitive, may violate local privacy regulations if made accessible to 3rd parties without consent of everyone visible on the recording etc. So if a default is needed for a user which stores such recordings into a volume that is accessible outside of the container, then root can be seen as best defaults in these regards, limiting access to the recordings to a minimum.

If access to recordings are less a concern than potential access from container to host: I do not see any argument why software within the container should not run as root if volumes are used, compared to no volumes being used. Sure they are a way to indirectly have access to outside the container. But any user within the container can deploy any kind of malware in the volume, no root needed for this. And root can execute files stored in the volume from any user to give potentially harmful code elevated permissions. Only, maybe, that one might be forced to access the data as root, can be seen as argument. Allowing access to a proper unprivileged user, might reduce the chance that admins go the easy way and access as root. But I mean we are talking about media files here, accessed with a media player, and we are not on Windows where some double-quick magic might execute a media file as script/program or such, especially if the file extension is hidden 😅.

Things are different when running multiple applications within the container: you do not want some web server/backend user to access the database files directly vice versa. If each of them requires a volume, it makes sense to sandbox them (deny "other" execute permissions on a parent dir of the volume, to deny content listing, hence access reliably, in both directions). But motionEye containers run a single application only.

root can access and manipulate the container image freely, of course. This makes it also easier to hide malware or any such. But it is still limited to the container, and there is rarely anything even nobody cannot gather as info from the host system root can, when thinking about leaking information to somewhere else.

Fact is, containers run as root in any case (unless the specific rootless Docker method is used, which is pretty uncommon, and limited), as the blackbox they otherwise are, and intended to be. So Docker is designed to work like that without much chance to risk compromising the host system, if access is not explicitly granted via volumes or such to sensitive host system areas. Of course it does not hurt, and makes sense to configure processes within the container to run as non-root, and in case particular UID to tailored host system access to its produced data. But especially in this case, where the data produced is probably more sensitive than stuff on the host, storing them as root is probably the best default. In a highly sensitive network environment, one would not run motionEye with its hardcoded users and outdated password hashing anyway, meaning there are in fact (other) things we need to work on for security reasons 😅. But otherwise, bringing things into perspective, no reason to worry about motionEye within the container to run as root.

But I totally agree that we should implement PUID/PGID support. That additional potential layer of security and flexibly tailored access control totally makes sense. And it is not complicated to implement, AFAICTO. Let's add it to the milestone.

MichaIng avatar Jul 19 '25 13:07 MichaIng

Hello everyone, Thank you, @MichaIng, for your quick replies! I'm glad my simple question has helped to move your project forward! I'm generally interested in security issues. I don't have any particular programming skills, but please let me know if there's anything I can do to help with this project.

In any case, I'm discovering MotionEye (running as root :wink: ) and so far everything is going as expected. Thank you!

ecsufio avatar Jul 19 '25 14:07 ecsufio