Switching users inside Docker image to a non-root user
Solution 1
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.
Solution 2
As a different approach to the other answer, instead of indicating the user upon image creation on the Dockerfile, you can do so via command-line on a particular container as a per-command basis.
With docker exec
, use --user
to specify which user account the interactive terminal will use (the container should be running and the user has to exist in the containerized system):
docker exec -it --user [username] [container] bash
See https://docs.docker.com/engine/reference/commandline/exec/
Solution 3
In case you need to perform privileged tasks like changing permissions of folders you can perform those tasks as a root user and then create a non-privileged user and switch to it.
FROM <some-base-image:tag>
# Switch to root user
USER root # <--- Usually you won't be needed it - Depends on base image
# Run privileged command
RUN apt install <packages>
RUN apt <privileged command>
# Set user and group
ARG user=appuser
ARG group=appuser
ARG uid=1000
ARG gid=1000
RUN groupadd -g ${gid} ${group}
RUN useradd -u ${uid} -g ${group} -s /bin/sh -m ${user} # <--- the '-m' create a user home directory
# Switch to user
USER ${uid}:${gid}
# Run non-privileged command
RUN apt <non-privileged command>
Solution 4
Add this line to docker file
USER <your_user_name>
Use docker instruction USER
Solution 5
You should also be able to do:
apt install sudo
sudo -i -u tomcat
Then you should be the tomcat user. It's not clear which Linux distribution you're using, but this works with Ubuntu 18.04 LTS, for example.
Related videos on Youtube
Jan Vladimir Mostert
Updated on June 24, 2021Comments
-
Jan Vladimir Mostert almost 3 years
I'm trying to switch user to the tomcat7 user in order to setup SSH certificates.
When I do
su tomcat7
, nothing happens.whoami
still ruturns root after doingsu tomcat7
Doing a
more /etc/passwd
, I get the following result which clearly shows that a tomcat7 user exists:root:x:0:0:root:/root:/bin/bash daemon:x:1:1:daemon:/usr/sbin:/bin/sh bin:x:2:2:bin:/bin:/bin/sh sys:x:3:3:sys:/dev:/bin/sh sync:x:4:65534:sync:/bin:/bin/sync games:x:5:60:games:/usr/games:/bin/sh man:x:6:12:man:/var/cache/man:/bin/sh lp:x:7:7:lp:/var/spool/lpd:/bin/sh mail:x:8:8:mail:/var/mail:/bin/sh news:x:9:9:news:/var/spool/news:/bin/sh uucp:x:10:10:uucp:/var/spool/uucp:/bin/sh proxy:x:13:13:proxy:/bin:/bin/sh www-data:x:33:33:www-data:/var/www:/bin/sh backup:x:34:34:backup:/var/backups:/bin/sh list:x:38:38:Mailing List Manager:/var/list:/bin/sh irc:x:39:39:ircd:/var/run/ircd:/bin/sh gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/bin/sh nobody:x:65534:65534:nobody:/nonexistent:/bin/sh libuuid:x:100:101::/var/lib/libuuid:/bin/sh messagebus:x:101:104::/var/run/dbus:/bin/false colord:x:102:105:colord colour management daemon,,,:/var/lib/colord:/bin/false saned:x:103:106::/home/saned:/bin/false tomcat7:x:104:107::/usr/share/tomcat7:/bin/false
What I'm trying to work around is this error in Hudson:
Command "git fetch -t git@________.co.za:_______/_____________.git +refs/heads/*:refs/remotes/origin/*" returned status code 128: Host key verification failed.
This is my Dockerfile, it takes an existing hudson war file and config that is tarred and builds an image, hudson runs fine, it just can't access git due to certificates not existing for user tomcat7.
FROM debian:wheezy # install java on image RUN apt-get update RUN apt-get install -y openjdk-7-jdk tomcat7 # install hudson on image RUN rm -rf /var/lib/tomcat7/webapps/* ADD ./ROOT.tar.gz /var/lib/tomcat7/webapps/ # copy hudson config over to image RUN mkdir /usr/share/tomcat7/.hudson ADD ./dothudson.tar.gz /usr/share/tomcat7/ RUN chown -R tomcat7:tomcat7 /usr/share/tomcat7/ # add ssh certificates RUN mkdir /root/.ssh ADD ssh.tar.gz /root/ # install some dependencies RUN apt-get update RUN apt-get install --y maven RUN apt-get install --y git RUN apt-get install --y subversion # background script ADD run.sh /root/run.sh RUN chmod +x /root/run.sh # expose port 8080 EXPOSE 8080 CMD ["/root/run.sh"]
I'm using the latest version of Docker (Docker version 1.0.0, build 63fe64c/1.0.0), is this a bug in Docker or am I missing something in my Dockerfile?
-
icecrime almost 10 yearsAre you aware of the
USER
Dockerfile instruction? -
Jan Vladimir Mostert almost 10 yearsNope, what do you suggest I use it for?
-
Jan Vladimir Mostert almost 10 yearsWould it be possible to generate certificates via the Dockerfile using the USER instruction?
-
icecrime almost 10 yearsEverything you
RUN
after aUSER
instruction is done under the corresponding uid, so although I'm not sure I perfectly understand your problem, it looks it might be what you're looking for. -
davidA about 8 years@icecrime not everything, unfortunately.
COPY
creates files as uid 0, which means they are not writable by the non-root user, and runningRUN chown ...
on those files won't work unless the current user is also root. So one ends up switching back and forth between root and the other user throughout the Dockerfile. -
David over 7 yearsSo what is the approach to take if you need to switch user in the middle of a RUN command that contains a chain of unix commands? e.g.
RUN start some service && su myuser && other cmds to run while service is running but need to run as myuser
-
Jan Vladimir Mostert over 7 yearssplit the chain, that's the only way.
-
-
Spencer Williams about 8 yearsI'm curious about how to make sure previously run commands are available to the user set in the Dockerfile. I have a question where folders and permissions previously set by root are not available after switching to another user with the
USER
instruction. -
x-yuri over 5 yearsYou might need
COPY --chown=myuser ...
down the road. -
Noname almost 3 yearsHow to run multiple commands as different users in a single RUN? Will
RUN sudo su user && command1 && sudo su user2 && command2
work?