how to correctly use system user in docker container

11,700

This sort of error will happen when the uid/gid does not exist in the /etc/passwd or /etc/group file inside the container. There are various ways to work around that. One is to directly map these files from your host into the container with something like:

$ docker run -it --rm --user=999:998 \
  -v /etc/passwd:/etc/passwd:ro -v /etc/group:/etc/group:ro \
  my-image:latest bash

I'm not a fan of that solution since files inside the container filesystem may now have the wrong ownership, leading to potential security holes and errors.

Typically, the reason people want to change the uid/gid inside the container is because they are mounting files from the host into the container as a host volume and want permissions to be seamless across the two. In that case, my solution is to start the container as root and use an entrypoint that calls a script like:

if [ -n "$opt_u" ]; then
  OLD_UID=$(getent passwd "${opt_u}" | cut -f3 -d:)
  NEW_UID=$(stat -c "%u" "$1")
  if [ "$OLD_UID" != "$NEW_UID" ]; then
    echo "Changing UID of $opt_u from $OLD_UID to $NEW_UID"
    usermod -u "$NEW_UID" -o "$opt_u"
    if [ -n "$opt_r" ]; then
      find / -xdev -user "$OLD_UID" -exec chown -h "$opt_u" {} \;
    fi
  fi
fi

The above is from a fix-perms script that I include in my base image. What's happening there is the uid of the user inside the container is compared to the uid of the file or directory that is mounted into the container (as a volume). When those id's do not match, the user inside the container is modified to have the same uid as the volume, and any files inside the container with the old uid are updated. The last step of my entrypoint is to call something like:

exec gosu app_user "$@"

Which is a bit like an su command to run the "CMD" value as the app_user, but with some exec logic that replaces pid 1 with the "CMD" process to better handle signals. I then run it with a command like:

$ docker run -it --rm --user=0:0 -v /host/vol:/container/vol \
  -e RUN_AS app_user --entrypoint /entrypoint.sh \
  my-image:latest bash

Have a look at the base image repo I've linked to, including the example with nginx that shows how these pieces fit together, and avoids the need to run containers in production as root (assuming production has known uid/gid's that can be baked into the image, or that you do not mount host volumes in production).

Share:
11,700

Related videos on Youtube

VorpalSword
Author by

VorpalSword

Here are some products I created (with the help of a great team, every time) AMS Logic 1. World's first all-digital, academy award winning audio deck. I designed & coded the signal processing (eq, dynamics, other effects) in floating point DSP, and the distributed control system in Occam 2 of all languages. Transputers were a thing. Kodak Cineon FX. The technology that turned film into a digital medium. Was doing 4k (i.e. film res) 3D DVE's 20 years ago, though admittedly not in real time. If you've seen The Matrix, Independence Day, Air Force One, and hundreds of others excellent FX movies, you've seen my work. I designed the 3D DVE that came out in V4.0. This is where I wrote most of my C++. Grass Valley Profile and Turbo video servers. Ultra reliable video playout for Super Bowl ads, and category defining ProAV HD server. By this point I had become an evil Engineering / Program manager and wrote a lot of MS Project Programs that, no surprise, never really executed. NewTek TriCaster Production Switcher. I was consulting product manager for their major upgrade of control surfaces. Main language was visio and powerpoint. This helped revenues grow over 3x over the 2 years I was doing this. Right now I'm in start-up mode developing an automated production solution that makes it bone simple (think tinder's ui) for ordinary people to make great looking TV. Hence my recent ascent of multiple HTML5 related learning curves. I'm turning into a big Javascript fan.

Updated on October 12, 2022

Comments

  • VorpalSword
    VorpalSword over 1 year

    I'm starting containers from my docker image like this:

    $ docker run -it --rm --user=999:998 my-image:latest bash
    

    where the uid and gid are for a system user called sdp:

    $ id sdp uid=999(sdp) gid=998(sdp) groups=998(sdp),999(docker)
    

    but: container says "no"...

    groups: cannot find name for group ID 998
    I have no name!@75490c598f4c:/home/myfolder$ whoami
    whoami: cannot find name for user ID 999
    

    what am I doing wrong?

    Note that I need to run containers based on this image on multiple systems and cannot guarantee that the uid:gid of the user will be the same across systems which is why I need to specify it on the command line rather than in the Dockerfile.

    Thanks in advance.

  • teoring
    teoring almost 3 years
    I have tried to mount these two "-v /etc/passwd:/etc/passwd:ro -v /etc/group:/etc/group:ro" and seems its not sufficient enough to overcome "Permission denied".
  • BMitch
    BMitch almost 3 years
    @teoring did you get to the second paragraph of the answer?