Set Docker Image Username at Container Creation Time

Set docker image username at container creation time?

The below code has been checked into https://github.com/bmitch3020/run-as-user.

I would handle this in an entrypoint.sh that checks the ownership of /home/myuser and updates the uid/gid of the user inside your container. It can look something like:

#!/bin/sh

set -x
# get uid/gid
USER_UID=`ls -nd /home/myuser | cut -f3 -d' '`
USER_GID=`ls -nd /home/myuser | cut -f4 -d' '`

# get the current uid/gid of myuser
CUR_UID=`getent passwd myuser | cut -f3 -d: || true`
CUR_GID=`getent group myuser | cut -f3 -d: || true`

# if they don't match, adjust
if [ ! -z "$USER_GID" -a "$USER_GID" != "$CUR_GID" ]; then
groupmod -g ${USER_GID} myuser
fi
if [ ! -z "$USER_UID" -a "$USER_UID" != "$CUR_UID" ]; then
usermod -u ${USER_UID} myuser
# fix other permissions
find / -uid ${CUR_UID} -mount -exec chown ${USER_UID}.${USER_GID} {} \;
fi

# drop access to myuser and run cmd
exec gosu myuser "$@"

And here's some lines from a relevant Dockerfile:

FROM debian:9
ARG GOSU_VERSION=1.10

# run as root, let the entrypoint drop back to myuser
USER root

# install prereq debian packages
RUN apt-get update \
&& DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
apt-transport-https \
ca-certificates \
curl \
vim \
wget \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*

# Install gosu
RUN dpkgArch="$(dpkg --print-architecture | awk -F- '{ print $NF }')" \
&& wget -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$dpkgArch" \
&& chmod 755 /usr/local/bin/gosu \
&& gosu nobody true

RUN useradd -d /home/myuser -m myuser
WORKDIR /home/myuser

# entrypoint is used to update uid/gid and then run the users command
COPY entrypoint.sh /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]
CMD /bin/sh

Then to run it, you just need to mount /home/myuser as a volume and it will adjust permissions in the entrypoint. e.g.:

$ docker build -t run-as-user . 
$ docker run -it --rm -v $(pwd):/home/myuser run-as-user /bin/bash

Inside that container you can run id and ls -l to see that you have access to /home/myuser files.

How to set time in Docker container at build time

So @JanGaraj's answer gave me an important lead: Alpine 3.14's release notes mention that it requires Docker >=20.10.0 (I am currently on 19.03.15).

Going back to Alpine 3.13's release notes:

  • The Docker version requirement is 19.03.9 [which I have]
  • along with libseccomp 2.4.2

Simply using FROM alpine:3.13 still didn't work.

Checking the second requirement, I had a previous version of libseccomp[2] and web-searching led me to this post: https://blog.samcater.com/fix-workaround-rpi4-docker-libseccomp2-docker-20/

Using the steps therein to upgrade libseccomp[2] did the trick for both alpine:3.13 and alpine:3.14!!

The steps to fix (from the post)

The steps for libseccomp2 are well documented, as this has been a problem on multiple platforms (not just RPI4). You could do a 'oneshot' installation of a newer version, which can be found here https://github.com/itzg/docker-minecraft-server/issues/755#issuecomment-781615497

Personally I feel the better method is to install it from the Buster Backports repo, which is very safe to add. It also means any future updates to libseccomp will be applied to the Pi.

# Get signing keys to verify the new packages, otherwise they will not install
rpi ~$ sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 04EE7237B7D453EC 648ACFD622F3D138

# Add the Buster backport repository to apt sources.list
rpi ~$ echo 'deb http://httpredir.debian.org/debian buster-backports main contrib non-free' | sudo tee -a /etc/apt/sources.list.d/debian-backports.list

rpi ~$ sudo apt update
rpi ~$ sudo apt install libseccomp2 -t buster-backports

Now on to the next build-time error message /p>

How to add users to Docker container?

The trick is to use useradd instead of its interactive wrapper adduser.
I usually create users with:

RUN useradd -ms /bin/bash newuser

which creates a home directory for the user and ensures that bash is the default shell.

You can then add:

USER newuser
WORKDIR /home/newuser

to your dockerfile. Every command afterwards as well as interactive sessions will be executed as user newuser:

docker run -t -i image
newuser@131b7ad86360:~$

You might have to give newuser the permissions to execute the programs you intend to run before invoking the user command.

Using non-privileged users inside containers is a good idea for security reasons. It also has a few drawbacks. Most importantly, people deriving images from your image will have to switch back to root before they can execute commands with superuser privileges.

How to set image name in Dockerfile?

Tagging of the image isn't supported inside the Dockerfile. This needs to be done in your build command. As a workaround, you can do the build with a docker-compose.yml that identifies the target image name and then run a docker-compose build. A sample docker-compose.yml would look like

version: '2'

services:
man:
build: .
image: dude/man:v2

That said, there's a push against doing the build with compose since that doesn't work with swarm mode deploys. So you're back to running the command as you've given in your question:

docker build -t dude/man:v2 .

Personally, I tend to build with a small shell script in my folder (build.sh) which passes any args and includes the name of the image there to save typing. And for production, the build is handled by a ci/cd server that has the image name inside the pipeline script.

Ensure both user name and user id are the same in host and Docker container

If you are using linux based image (say ubuntu for example), in your Dockerfile, you will need something like

sudo addgroup --gid 3000 mygroupname && 
sudo adduser --uid 4000 --gid 3000 --disabled-password --gecos "" myusername
  1. I'm using 3000 and 4000 just as examples. They can both be same
    number if you want them to be.
  2. Whether to disable password or not depends on what you want to do with the user.
  3. gecos is for setting full name, room number, work phone etc for the user. We are setting them all to be blank. You can definitely set them to something more useful if you want to.

You will have to switch to that user and maybe use that user's home directory as your work directory. Lines in Dockerfile would be:

USER myusername
WORKDIR /home/myusername

What is the created time in docker images command?

It should be the date of the latest docker build run by the image owner, as defined in the image/image.go file, which can be found in the container once the image has been run.

You can inspect low-level image info to see its exact value with:

docker inspect -f '{{.Created}}' hello-world

where 'hello-world' is the name of your image.

If you are in a VM, the timestamp might not be precise for local images, as your VM clock might not be precisely synchronized (by typing 'date', I see mine is synchronized, but on UTC: one hour shift).

Switching users inside Docker image to a non-root user

You should not use su in a dockerfile, however you should use the USER instruction in the Dockerfile.

At each stage of the Dockerfile build, a new container is created so any change you make to the user will not persist on the next build stage.

For example:

RUN whoami
RUN su test
RUN whoami

This would never say the user would be test as a new container is spawned on the 2nd whoami. The output would be root on both (unless of course you run USER beforehand).

If however you do:

RUN whoami
USER test
RUN whoami

You should see root then test.

Alternatively you can run a command as a different user with sudo with something like

sudo -u test whoami

But it seems better to use the official supported instruction.



Related Topics



Leave a reply



Submit