Docker entrypoint user switch - docker

I am creating a docker image to be used as base for other applications. The requirements are:
application must run as non root user
optionally, certificates must be loaded before executing the application
I created the following Dockerfile
FROM node:14.15.1-alpine3.11
# Specify node/npm related envs
ENV NPM_CONFIG_LOGLEVEL=warn \
NO_UPDATE_NOTIFIER=1
# Change cwd for next commands
WORKDIR /home/node/code
# Set local registry
RUN echo "registry=http://192.168.100.175:4873" > /home/node/.npmrc && \
chown -R node:node /home/node && \
apk add --update --no-cache tzdata=2021a-r0 ca-certificates=20191127-r2 su-exec=0.2-r1
# Need root to update CA certificates in entrypoint.sh and then switch back to restricted user
USER root
COPY entrypoint.sh entrypoint.sh
ENTRYPOINT [ "./entrypoint.sh" ]
# Execute the service entrypoint
CMD ["sh"]
and entrypoint.sh
#!/bin/sh
DIR_CRT="/home/node/certificates"
if [ "$(ls -A ${DIR_CRT})" ]; then
cp -r "${DIR_CRT}/." /usr/local/share/ca-certificates/
update-ca-certificates
echo "******* Updated CA certificates *******"
fi
exec su-exec node "$#"
This seems to cover the requirements but I noticed that if I open a shell inside the image it is always with node user even if I specify a different one from parameters:
$ docker run --rm -it -u root docker.repo.asts.com/scc-2.0/app-tg:1.6.0-beta50 whoami
node
Is it possible to have both the requirements and the possibility to execute a direct command with required user?

docker run -u xxx works only if you did not use exec in entrypoint to change PID1. E.g.
$ docker run --rm -it node:14.15.1-alpine3.11 whoami
root
$ docker run --rm -u node -it node:14.15.1-alpine3.11 whoami
node
After you use exec su-exec node "$#" to change the user to node, you won't have way to use -u xxx again. The only solution is override the entrypoint like next, but I don't see the meaning here:
docker run --rm -u root --entrypoint=/bin/sh xxx
But, you still could use docker exec -u root or docker exec -u node to get a shell for that user in exist container.

Related

How to run Docker-in-Docker in an alpine container as a non-root user?

As the title says, I'm trying to run docker compose as a non-root user on an alpine container.
I have the following Dockerfile:
FROM docker.io/jenkins/ssh-agent:4.4.0-alpine-jdk17
# SSH public key
ENV JENKINS_AGENT_SSH_PUBKEY "ssh-key"
# Install Docker CLI
RUN apk add --no-cache docker-cli docker-cli-compose
# Add docker permissions to Jenkins user
COPY docker-perms.sh /docker-perms.sh
RUN delgroup ping && sh /docker-perms.sh
# I have to delete ping group as it has the same GID as docker
and docker-perms.sh:
#!/bin/sh
set -e
DOCKER_SOCKET=/var/run/docker.sock
RUNUSER=jenkins
if [ -S ${DOCKER_SOCKET} ]; then
DOCKER_GID=$(stat -c '%g' ${DOCKER_SOCKET})
DOCKER_GROUP=$(getent group ${DOCKER_GID} | awk -F ":" '{ print $1 }')
if [ $DOCKER_GROUP ]
then
addgroup $RUNUSER $DOCKER_GROUP
else
addgroup -S -g ${DOCKER_GID} docker
addgroup $RUNUSER docker
fi
fi
I then mount the host's docker socket when I start the container. However, two things happen:
I have to re-run docker-perms.sh as root inside the container because running docker ps as jenkins user returns the permission denied error. After running the script, it no longer produces an error
When I run a job from the Jenkins controller, the permission denied error appears again anyway
What am I doing wrong?
I figured out what I was doing wrong: the docker.sock is only mounted after the image is built, so the script can't add the group.
This isn't a very pretty workaround, but I guess I can just add the group directly on the Dockerfile instead:
FROM docker.io/jenkins/ssh-agent:4.4.0-alpine-jdk17
# SSH public key
ENV JENKINS_AGENT_SSH_PUBKEY "ssh-key"
# Install Docker CLI
RUN apk add --no-cache docker-cli docker-cli-compose
# Add Docker permissions to Jenkins user
RUN DOCKER_GID=999 && \
delgroup $(grep $DOCKER_GID /etc/group | cut -d: -f1) && \
addgroup -S -g $DOCKER_GID docker && addgroup jenkins docker
This supposes that the docker group ID will be 999

run docker container as a arbitrary user passed to it while running the image

I want to run a docker container as an arbitrary user which is passed to the image while running it. For example docker run -u 1000 myimage.
The above is possible. However I want to create a home directory with this user 1000 while starting the container(possibly through CMD) and do my container service stuff within that directory.
Is this possible and some pointers would be useful on ways to achieve it.
First save your current user and group in variables:
export uid=$(id -u)
export gid=$(id -g)
Then to run your image,you have two options:
1) Run the image from the location of the app directory itself:
sudo docker run -d \
--user $uid:$gid \
-v $(pwd):/home/$USER \
--workdir="/home/$USER" \
myimage
2) Create a new directory for the app, e.g. at /home/$USER/app, but then you will have to write in command line your CMD from the docker file.
For example if this was your Dockerfile:
FROM node:7
WORKDIR /app
COPY package.json /app
COPY . /app
CMD node bin/www
Your would run it like that:
sudo docker run -d \
--user $uid:$gid \
-v $(pwd):/home/$USER \
--workdir="/home/$USER" \
hello-express \
bash -c "cp -rf /app/* /home/$USER/; node bin/www"
Here you pass the user to the container using $uid:$gid and you mount the user's home directory as a volume and then set it as the working directory.
I know it's quite complex, but it's the only way to achieve exactly what you want.
If you want a simpler solution, consider planning it differently. See this example for running a docker container as a non-root user.

Unable to find user root: no matching entries in passwd file in Docker

I have containers for multiple Atlassian products; JIRA, Bitbucket and Confluence. When I'm trying to access the running containers I'm usually using:
docker exec -it -u root ${DOCKER_CONTAINER} bash
With this command I'm able to access as usual, but after running a script to extract and compress log files, I can't access that one container anymore.
Excerpt from the 'clean up script'
This is the first point of failure, and the script is running once each week (scheduled by Jenkins).
docker cp ${CLEAN_UP_SCRIPT} ${DOCKER_CONTAINER}:/tmp/${CLEAN_UP_SCRIPT}
if [ $? -eq 0 ]; then
docker exec -it -u root ${DOCKER_CONTAINER} bash -c "cd ${LOG_DIR} && /tmp/compressOldLogs.sh ${ARCHIVE_FILE}"
fi
When the script executes these two lines towards the Bitbucket container the result is:
unable to find user root: no matching entries in passwd file
It's failing on the 'docker cp'-command, but only towards the Bitbucket container. After the script has ran, the container is unaccessible with both the 'bitbucket' (defined in Dockerfile) and 'root' users.
I was able to copy /etc/passwd out of the container, and it contains all of the users as expected. When trying to access by uid, I get the following error:
rpc error: code = 2 desc = oci runtime error: exec failed: process_linux.go:75: starting setns process caused "fork/exec /proc/self/exe: no such file or directory"
Dockerfile for Bitbucket image:
FROM java:openjdk-8-jre
ENV BITBUCKET_HOME /var/atlassian/application-data/bitbucket
ENV BITBUCKET_INSTALL_DIR /opt/atlassian/bitbucket
ENV BITBUCKET_VERSION 4.12.0
ENV DOWNLOAD_URL https://downloads.atlassian.com/software/stash/downloads/atlassian-bitbucket-${BITBUCKET_VERSION}.tar.gz
ARG user=bitbucket
ARG group=bitbucket
ARG uid=1000
ARG gid=1000
RUN mkdir -p $(dirname $BITBUCKET_HOME) \
&& groupadd -g ${gid} ${group} \
&& useradd -d "$BITBUCKET_HOME" -u ${uid} -g ${gid} -m -s /bin/bash ${user}
RUN mkdir -p ${BITBUCKET_HOME} \
&& mkdir -p ${BITBUCKET_HOME}/shared \
&& chmod -R 700 ${BITBUCKET_HOME} \
&& chown -R ${user}:${group} ${BITBUCKET_HOME} \
&& mkdir -p ${BITBUCKET_INSTALL_DIR}/conf/Catalina \
&& curl -L --silent ${DOWNLOAD_URL} | tar -xz --strip=1 -C "$BITBUCKET_INSTALL_DIR" \
&& chmod -R 700 ${BITBUCKET_INSTALL_DIR}/ \
&& chown -R ${user}:${group} ${BITBUCKET_INSTALL_DIR}/
${BITBUCKET_INSTALL_DIR}/bin/setenv.sh
USER ${user}:${group}
EXPOSE 7990
EXPOSE 7999
WORKDIR $BITBUCKET_INSTALL_DIR
CMD ["bin/start-bitbucket.sh", "-fg"]
Additional info:
Docker version 1.12.0, build 8eab29e
docker-compose version 1.8.0, build f3628c7
All containers are running at all times, even Bitbucket works as usual after the issue occurres
The issue disappears after a restart of the container
You can use this command to access to the container with root user:
docker exec -u 0 -i -t {container_name_or_hash} /bin/bash
try debug with that. i think the script maybe remove or disable root user.
This issue is caused by a docker engine bug but which is tracked privately, Docker is asking users to restart the engine!
It seems that the bug is likely to be older than two years!
https://success.docker.com/article/ucp-health-checks-fail-unable-to-find-user-nobody-no-matching-entries-in-passwd-file-observed
https://forums.docker.com/t/unable-to-find-user-root-no-matching-entries-in-passwd-file/26545/7
... what can I say, someone is doing his best to get more funding.
Its a Long standing issue, replicated on my old version 1.10.3 to at least 1.17
As mentioned by #sorin the the docker forum says Running docker stop and then docker start fixes the problem but is hardly a long-term solution...
The docker exec -u 0 -i -t {container_name_or_hash} /bin/bash solution also in the same forum post mentioned here by #ObranZoltan might work for you, but does not work for many. See my output below
$ sudo docker exec -u 0 -it berserk_nobel /bin/bash
exec: "/bin/bash": stat /bin/bash: input/output error

How to create and run docker container with new user other than root?

I met a problem while using docker.
Now I have a ubuntu based docker container. And in the container ,the user id is root by default which is not my expectation, I suppose the user id is like abc which is another user account on the HOST OS running docker.
I have tried the following ways but all fail:
su abc;
Then running docker run xxx to bring up a container, but login the container, the user in container is still root.
Then by adding the -u flag for docker run: like :
docker run -t -i -u abc ubuntu /bin/bash
the the docker show errors unable to find user abc
Can some one tell me how to fix it?
Or does docker support run a container in which the user is a specific one than the default root?
You can create User inside Docker images. But for that you will have to extend base image. For example you can create user abc in Ubuntu as below,
FROM ubuntu:14.04
RUN apt-get update
# Replace 1000 with your user / group id
RUN export uid=1000 gid=1000 && \
mkdir -p /home/abc && \
echo "abc:x:${uid}:${gid}:Abc,,,:/home/abc:/bin/bash" >> /etc/passwd && \
echo "abc:x:${uid}:" >> /etc/group && \
echo "abc ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/abc && \
chmod 0440 /etc/sudoers.d/abc && \
chown ${uid}:${gid} -R /home/abc
USER abc
ENV HOME /home/abc
WORKDIR $HOME
CMD /bin/bash
Then you build and run it,
docker build -t abc .
docker run -it abc bash
you should see bash prompt with user abc like below,
abc#<container-hostname>:~$
According to https://medium.com/redbubble/running-a-docker-container-as-a-non-root-user-7d2e00f8ee15, this is possibly, but you can only refer to HOST users by their numerical ids. Read that helpful article for more details and a fuller explanation.

Connect to docker container as user other than root

BY default when you run
docker run -it [myimage]
OR
docker attach [mycontainer]
you connect to the terminal as root user, but I would like to connect as a different user. Is this possible?
For docker run:
Simply add the option --user <user> to change to another user when you start the docker container.
docker run -it --user nobody busybox
For docker attach or docker exec:
Since the command is used to attach/execute into the existing process, therefore it uses the current user there directly.
docker run -it busybox # CTRL-P/Q to quit
docker attach <container id> # then you have root user
/ # id
uid=0(root) gid=0(root) groups=10(wheel)
docker run -it --user nobody busybox # CTRL-P/Q to quit
docker attach <container id>
/ $ id
uid=99(nobody) gid=99(nogroup)
If you really want to attach to the user you want to have, then
start with that user run --user <user> or mention it in your Dockerfile using USER
change the user using `su
You can run a shell in a running docker container using a command like:
docker exec -it --user root <container id> /bin/bash
As an updated answer from 2020. --user, -u option is Username or UID (format: <name|uid>[:<group|gid>]).
Then, it works for me like this,
docker exec -it -u root:root container /bin/bash
Reference: https://docs.docker.com/engine/reference/commandline/exec/
You can specify USER in the Dockerfile. All subsequent actions will be performed using that account. You can specify USER one line before the CMD or ENTRYPOINT if you only want to use that user when launching a container (and not when building the image). When you start a container from the resulting image, you will attach as the specified user.
The only way I am able to make it work is by:
docker run -it -e USER=$USER -v /etc/passwd:/etc/passwd -v `pwd`:/siem mono bash
su - magnus
So I have to both specify $USER environment variable as well a point the /etc/passwd file. In this way, I can compile in /siem folder and retain ownership of files there not as root.
My solution:
#!/bin/bash
user_cmds="$#"
GID=$(id -g $USER)
UID=$(id -u $USER)
RUN_SCRIPT=$(mktemp -p $(pwd))
(
cat << EOF
addgroup --gid $GID $USER
useradd --no-create-home --home /cmd --gid $GID --uid $UID $USER
cd /cmd
runuser -l $USER -c "${user_cmds}"
EOF
) > $RUN_SCRIPT
trap "rm -rf $RUN_SCRIPT" EXIT
docker run -v $(pwd):/cmd --rm my-docker-image "bash /cmd/$(basename ${RUN_SCRIPT})"
This allows the user to run arbitrary commands using the tools provides by my-docker-image. Note how the user's current working directory is volume mounted
to /cmd inside the container.
I am using this workflow to allow my dev-team to cross-compile C/C++ code for the arm64 target, whose bsp I maintain (the my-docker-image contains the cross-compiler, sysroot, make, cmake, etc). With this a user can simply do something like:
cd /path/to/target_software
cross_compile.sh "mkdir build; cd build; cmake ../; make"
Where cross_compile.sh is the script shown above. The addgroup/useradd machinery allows user-ownership of any files/directories created by the build.
While this works for us. It seems sort of hacky. I'm open to alternative implementations ...
For docker-compose. In the docker-compose.yml:
version: '3'
services:
app:
image: ...
user: ${UID:-0}
...
In .env:
UID=1000
Execute command as www-data user: docker exec -t --user www-data container bash -c "ls -la"
This solved my use case that is: "Compile webpack stuff in nodejs container on Windows running Docker Desktop with WSL2 and have the built assets under your currently logged in user."
docker run -u 1000 -v "$PWD":/build -w /build node:10.23 /bin/sh -c 'npm install && npm run build'
Based on the answer by eigenfield. Thank you!
Also this material helped me understand what is going on.

Resources