Creating user with uid 1000 on alpine Docker image - linux

When I'm trying to create user with UID=1000 in Dockerfile
FROM alpine:3.16
RUN addgroup -g 1000 sail
RUN adduser -g 1000 -u 1000 sail
I'm getting error:
Step 3/3 : RUN adduser -g 1000 -u 1000 sail
---> Running in 0c4ce7e0bddf
adduser: uid '1000' in use
The command '/bin/sh -c adduser -g 1000 -u 1000 sail' returned a non-zero code: 1
But if I'm build a container without this stage and look to /etc/passwd there is no user with UID=1000. So it's exists only while building.
How to create user with UID=1000 properly in alpine?

Your syntax is incorrect, the adduser command of Alpine is the BusyBox one, so, unlike the "regular" adduser, here are its help page:
BusyBox v1.35.0 (2022-08-01 15:14:44 UTC) multi-call binary.
Usage: adduser [OPTIONS] USER [GROUP]
Create new user, or add USER to GROUP
-h DIR Home directory
-g GECOS GECOS field
-s SHELL Login shell
-G GRP Group
-S Create a system user
-D Don't assign a password
-H Don't create home directory
-u UID User id
-k SKEL Skeleton directory (/etc/skel)
You can easily go through it, running the command:
docker run -ti --rm alpine:3.16 adduser
The important part of information here are:
-g GECOS GECOS field
-G GRP Group
Where you can see that, a group, in BusyBox adduser requires your to be added with the option G, in capital letter, and that the option g in lowercase if for something else.
The option allows you to add a group, and not a GID, so you'll need the command:
RUN adduser -G sail -u 1000 sail
Furthermore, if you run that command, the shell will prompt you to fill in a password. You will need to skip this with the D option:
-D Don't assign a password
And so, your Dockerfile ends up being:
FROM alpine:3.16
RUN addgroup -g 1000 sail \
&& adduser -G sail -u 1000 sail -D
Note that it is always a good idea, in Docker, to reduce as much as possible the number of layers you are creating by running subsequent RUN instruction, for further reading on this, see here.

Related

Why does Docker -u doesnt work in my server?

I add a User local in my Server with: adduser name -g 1002 and then I'd like to run my docker with this User so I make: docker run -v /home/user:/some -u "uid:gid" image there couldn't find The user: getpwuid() Not found in Passwd.
First of all, did your adduser command work for you? Following your pattern, I've created a user with useradd instead of adduser:
useradd -m -d /home/name -s /bin/bash -g 1002 name
Assuming that the group with ID 1002 already exists on your system, the following docker command should work for you as well:
docker run -v /home/name:/usr/share/nginx/html:ro -p 8080:80 -d nginx
95e38e96b6b1fdfbf18aece7ccb3c3486db5dc1b142f60515076d8d49fc815f6

Is it possible to map a user inside the docker container to an outside user?

I know that one can use the --user option with Docker to run a container as a certain user, but in my case, my Docker image has a user inside it, let us call that user manager. Now is it possible to map that user to a user on host? For example, if there is a user john on the host, can we map john to manager?
Yes, you can set the user from the host, but you should modify your Dockerfile a bit to deal with run time user.
FROM alpine:latest
# Override user name at build. If build-arg is not passed, will create user named `default_user`
ARG DOCKER_USER=default_user
# Create a group and user
RUN addgroup -S $DOCKER_USER && adduser -S $DOCKER_USER -G $DOCKER_USER
# Tell docker that all future commands should run as this user
USER $DOCKER_USER
Now, build the Docker image:
docker build --build-arg DOCKER_USER=$(whoami) -t docker_user .
The new user in Docker will be the Host user.
docker run --rm docker_user ash -c "whoami"
Another way is to pass host user ID and group ID without creating the user in Dockerfile.
export UID=$(id -u)
export GID=$(id -g)
docker run -it \
--user $UID:$GID \
--workdir="/home/$USER" \
--volume="/etc/group:/etc/group:ro" \
--volume="/etc/passwd:/etc/passwd:ro" \
--volume="/etc/shadow:/etc/shadow:ro" \
alpine ash -c "whoami"
You can further read more about the user in docker here and here.
Another way is through an entrypoint.
Example
This example relies on gosu which is present in recent Debian derivatives, not yet in Alpine 3.13 (but is in edge).
You could run this image as follow:
docker run --rm -it \
--env UID=$(id -u) \
--env GID=$(id -g) \
-v "$(pwd):$(pwd)" -w "$(pwd)" \
imagename
tree
.
├── Dockerfile
└── files/
└── entrypoint
Dockerfile
FROM ...
# [...]
ARG DOCKER_USER=default_user
RUN addgroup "$DOCKER_USER" \
&& adduser "$DOCKER_USER" -G "$DOCKER_USER"
RUN wget -O- https://github.com/tianon/gosu/releases/download/1.12/gosu-amd64 |\
install /dev/stdin /usr/local/bin/gosu
COPY files /
RUN chmod 0755 /entrypoint \
&& sed "s/\$DOCKER_USER/$DOCKER_USER/g" -i /entrypoint
ENTRYPOINT ["/entrypoint"]
files/entrypoint
#!/bin/sh
set -e
set -u
: "${UID:=0}"
: "${GID:=${UID}}"
if [ "$#" = 0 ]
then set -- "$(command -v bash 2>/dev/null || command -v sh)" -l
fi
if [ "$UID" != 0 ]
then
usermod -u "$UID" "$DOCKER_USER" 2>/dev/null && {
groupmod -g "$GID" "$DOCKER_USER" 2>/dev/null ||
usermod -a -G "$GID" "$DOCKER_USER"
}
set -- gosu "${UID}:${GID}" "${#}"
fi
exec "$#"
Notes
UID is normally a read-only variable in bash, but it will work as expected if set by the docker --env flag
I choose gosu for it's simplicity, but you could make it work with su or sudo; it will need more configuration however
if you don't want to specify two --env switch, you could do something like: --env user="$(id -u):$(id -g)" and in the entrypoint: uid=${user%:*} gid=${user#*:}; note at this point the UID variable will be read-only in bash that's why I switched to lower-case... rest of the adaptation is left to the reader
There is no simple solution that handles all use cases. Solving these problems is continuous work, a part of life in the containerized world.
There is no magical parameter that you could add to a docker exec or docker run invocation and reliably cause the containerized software to no longer run into permissions issues during operations on host-mapped volumes. Unless your mapped directories are chmod-0777-and-come-what-may (DON'T), you will be running into permissions issues and you will be solving them as you go, and this is the task you should try becoming efficient at, instead of trying to find a miracle once-and-forever solution that will never exist.

Starting a Docker container with a user different from the one on the host

I am trying to deploy an image on a Ubuntu server. The problem is I would like the container to have a user other than root. In other words, I would like to start the container under that user.
What I have tried.
I have successfully created a user in my container which has an image.
I tried to start the container with the docker start command which was unsuccessful.
I tried to create a new container with a user defined inside the dockerfile, it was also unsuccessful.
root#juju_dev_server:/home/dev# sudo docker run -it --user dev d08d53c4d78b
docker: Error response from daemon: linux spec user: unable to find user dev: no matching entries in passwd file
.
Here is my dockerfile
FROM debian
RUN groupadd -g 61000 dev
RUN useradd -g 61000 -l -m -s /bin/false -u 61000 dev
USER dev
CMD ["bash"]
FROM java:8
EXPOSE 8080
ADD /target/juju-0.0.1.jar juju-0.0.1.jar
ENTRYPOINT ["java","-jar","juju-0.0.1.jar"]
How I've done it, I use Alpine not Ubuntu but it should work fine:
Creating and running as a user called "developer"
Dockerfile
RUN /bin/bash -c "adduser -D -u 1000 developer"
RUN passwd -d developer
RUN chown -R developer /home/developer/.bash*
RUN echo "developer ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/developer
ENTRYPOINT ["/entrypoint.sh"]
CMD ["bash"]
entrypoint.sh
# stuff I need running as root here. Then below runs a bash shell as "developer"
sudo -u developer -H bash -c "$#;"
I suppose you'll want to change your ENTRYPOINT to CMD or similar, or write it into your entrypoint.sh however you like to launch your java stuff.
The Dockerfile you show creates two images. The first one is a plain debian image with a non-root user. The second one ignores the first one and is a somewhat routine Java image.
You need to do these two steps in the same image. If I was going to write your Dockerfile it might look like
FROM java:8
EXPOSE 8080
# (Prefer COPY to ADD unless you explicitly want its
# auto-unpacking semantics.)
COPY /target/juju-0.0.1.jar juju-0.0.1.jar
# Set up a non-root user context, after COPYing content
# in. (Prevents the application from overwriting
# itself as a useful security measure.)
RUN groupadd -g 61000 app
RUN useradd -g 61000 -l -m -s /bin/false -u 61000 app
USER app
# Set the main container command. (Generally prefer
# CMD to ENTRYPOINT if you’re only using one; it makes
# both getting debugging shells and later adopting the
# pattern of an initializing entrypoint script easier.)
CMD ["java","-jar","juju-0.0.1.jar"]

Can't add a user with a high UID in docker Alpine

I'm trying to create a new user with UID 1340816314 inside an Alpine Linux Docker container in order to have a user with an UID matching a specific user on the host.
The problem is that I'm facing adduser: number 1340816314 is not in 0..256000 range even if I redefine the value of UID_MAX inside /etc/login.defs by following adduser man page. I don't think by the way that it has any impact as the adduser command in Alpine is from BusyBox.
Here is the log of what I try to do:
$ docker run -it --rm alpine:3.4 sh
/ # adduser -D -g '' -u 1340816314 user
adduser: number 1340816314 is not in 0..256000 range
/ # echo "UID_MAX 1340816314" > /etc/login.defs
/ # adduser -D -g '' -u 1340816314 user
adduser: number 1340816314 is not in 0..256000 range
/ # echo "UID_MAX 1340816315" > /etc/login.defs
/ # adduser -D -g '' -u 1340816314 user
adduser: number 1340816314 is not in 0..256000 range
Do you know how to add a user with a large UID in Alpine Linux inside a Docker container?
There is a more elegant solution to the high UID/GID in Alpine.
The package shadow contains the useradd and groupadd utilities which in turn supports higher values. Not sure which is the upper bound of those utils and if the whole 2^32 space is supported, but I've tested with values over 600 million and it works.
For example the commands to achieve this would look something like this:
UID=666000666
GID=999000999
apk add shadow
/usr/sbin/groupadd -g ${GID} my_group
/usr/sbin/useradd -s /bin/sh -g ${GID} -u ${UID} my_user
Note that I'm passing the shell variable to useradd as by default it tries to use /bin/bash which is not installed.
Here is a working but dirty workaround, by manually creating the user, using $UID_TO_SET as the bash variable containing the high UID to set:
# Create user
echo "user:x:$UID_TO_SET:$UID_TO_SET::/home/user:" >> /etc/passwd
## thanks for http://stackoverflow.com/a/1094354/535203 to compute the creation date
echo "user:!:$(($(date +%s) / 60 / 60 / 24)):0:99999:7:::" >> /etc/shadow
echo "user:x:$UID_TO_SET:" >> /etc/group
mkdir /home/user && chown user: /home/user
This problem actually inspired me to solve it in a way, which is convenient and easy to use for this specific use case of getting long IDs to work on Alpine and BusyBox based Docker images.
https://github.com/theAkito/userdef
Example Usage:
## Get the binary.
## The default Docker Tag provides the Alpine (musl) based binary.
FROM akito13/userdef AS base
## Pull the image you want to modify the executing user of.
FROM gitea/gitea:1.16.5-linux-amd64-rootless
## We temporarily need to use the root user,
## as we are doing administrative tasks, like e.g. modifying an OS user.
USER root:root
COPY --from=base /userdef /userdef
## 1. Change the existing user.
## 2. Use that user to `chown` relevant folders.
## 3. Remove the binary, because the user has been changed,
## i.e. our job is done here.
RUN /userdef -h=/var/lib/gitea/git -n=git -u=9234 -g=9234 && \
chown git:git -R /var/lib/gitea /etc/gitea && \
rm -f /userdef
## Switch to the now relevant executing user.
USER 9234:9234
## Taken from https://github.com/go-gitea/gitea/blob/66f2210feca0b50d305a46a203c2b3d2f4d3790b/Dockerfile.rootless#L71-L72
ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"]
CMD []
Elaboration on the only working answer from #anthony-o
# FOR UID higher than 60000, users need to be added like this!
RUN export GUID_TO_SET=100 && \
export UID_TO_SET=66666 && \
export USER=youruser && \
echo "${USER}:x:${UID_TO_SET}:${GUID_TO_SET}:Linux User,,,:/home/${USER}:/bin/sh" >> /etc/passwd && \
echo "${USER}:!:$(($(date +%s) / 60 / 60 / 24)):0:99999:7:::" >> /etc/shadow && \
mkdir /home/${USER} && \
chown ${USER}:${GUID_TO_SET} /home/${USER}
While the "dirty" methods above do work, they are ugly and not easy for some people to use. It would be easy to make a mistake with copy and paste.
So given that this is related to Docker, I've got a better way using multi-stage builds.
## Busybox adduser doesn't allow UIDs over 60000
## So we'll use a debian image to make the user
## And then copy the files and grep out the new user into the busybox container
FROM debian as base
RUN useradd -D -g '' -u 1340816314 user
FROM alpine as image
COPY --from=base /etc/passwd /root/passwd
RUN grep user /root/passwd >> /etc/passwd && rm -f /root/passwd
USER user
While this example uses debian, you can use any container image you want in the first stage instead of Debian. As long as the container doesn't error out because of an arbitrarily low UID limit in the command you use, it should be fine, so I encourage you to play around with different containers as the base image and also check if both useradd and adduser commands are available and which one might support the UID number you need.

yocto/bitbake build attempts to chown files to root and fails

I am trying to use yocto to build an image for a zedboard. My first build failed when it attempted to chown a bunch of files to root. It failed as part of a do_install command in one of the meta layers. The command executed this chown line:
chown -R root:root ${D}
I run bitbake as a normal, non-root user. Shouldn't I be able to compile it as non-root?
Just to test I created a new file and tried to chown to root:root and it failed in exactly the same way.
What am I missing here?
UPDATE: Looks like this is related to the use pseudo. I tried building poky without any additional layers (no xilinx, openembedded, etc) and it still failed with the same error. I tried both the jethro and fido releases with the same error.
UPDATE 2: Apparently pseudo is disabled in meta/conf/bitbake.conf. I am not sure why or how to proceed knowing this:
# Use pseudo as the fakeroot implementation
PSEUDO_LOCALSTATEDIR ?= "${WORKDIR}/pseudo/"
PSEUDO_PASSWD ?= "${STAGING_DIR_TARGET}:${STAGING_DIR_NATIVE}"
export PSEUDO_DISABLED = "1"
#export PSEUDO_PREFIX = "${STAGING_DIR_NATIVE}${prefix_native}"
#export PSEUDO_BINDIR = "${STAGING_DIR_NATIVE}${bindir_native}"
#export PSEUDO_LIBDIR = "${STAGING_DIR_NATIVE}$PSEUDOBINDIR/../lib/pseudo/lib
FAKEROOTBASEENV = "PSEUDO_BINDIR=${STAGING_BINDIR_NATIVE} PSEUDO_LIBDIR=${STAGING_BINDIR_NATIVE}/../lib/pseudo/lib PSEUDO_PREFIX=${STAGING_BINDIR_NATIVE}/../../ PSEUDO_DISABLED=1"
FAKEROOTCMD = "${STAGING_BINDIR_NATIVE}/pseudo"
FAKEROOTENV = "PSEUDO_PREFIX=${STAGING_DIR_NATIVE}${prefix_native} PSEUDO_LOCALSTATEDIR=${PSEUDO_LOCALSTATEDIR} PSEUDO_PASSWD=${PSEUDO_PASSWD} PSEUDO_NOSYMLINKEXP=1 PSEUDO_DISABLED=0"
FAKEROOTNOENV = "PSEUDO_UNLOAD=1"
FAKEROOTDIRS = "${PSEUDO_LOCALSTATEDIR}"
PREFERRED_PROVIDER_virtual/fakeroot-native ?= "pseudo-native"
What recipe in what layer? do_install for target packages runs under pseudo (a fake-root utility) so it can chown to root as a non-root user.
You should not chown files to root this is most probably the reason you get such kind of errors.
Why you want to do so?
This happened to me many times when I use bitbake as a root or when compiling with sudo. You no need privilege user for building. Actually what you really need is a user within the sudo group.
Instead can you tried the following
create yocto build user
groupadd -g 1000 build && useradd -u 1000 -g 1000 -ms /bin/bash build && usermod -a -G sudo build && usermod -a -G root build && usermod -a -G staff build
useradd -u 1000 -g 1000 -ms /bin/bash 1001 && usermod -a -G sudo 1001 && usermod -a -G root 1001 && usermod -a -G staff 1001
Chown all your files to sudo group user e.g build.
Then, grant read and write permissions
Remove tmp and cache files in the build folder.
Source the bitbake
Finally try to build.

Resources