Switching users inside Docker image to a non-root user
Asked Answered
L

6

163

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 doing su 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?

Lucila answered 3/7, 2014 at 9:18 Comment(8)
Are you aware of the USER Dockerfile instruction?Drinkwater
Nope, what do you suggest I use it for?Lucila
Would it be possible to generate certificates via the Dockerfile using the USER instruction?Lucila
Everything you RUN after a USER 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.Drinkwater
@Drinkwater not everything, unfortunately. COPY creates files as uid 0, which means they are not writable by the non-root user, and running RUN 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.Retract
So 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 myuserSquinteyed
split the chain, that's the only way.Lucila
You should note that the user tomcat7 has a login shell of /bin/false, which means that normally a su would fail, however a sudo may succeed. Either way, the USER tomcat7 command would be the best way.Scrod
W
178

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.

Wring answered 3/7, 2014 at 13:59 Comment(3)
I'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.Silence
You might need COPY --chown=myuser ... down the road.Pastry
How to run multiple commands as different users in a single RUN? Will RUN sudo su user && command1 && sudo su user2 && command2 work?Deflective
K
64

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/

Knowitall answered 26/8, 2016 at 19:50 Comment(0)
S
31

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>
Serai answered 29/8, 2020 at 4:14 Comment(1)
I had problems using USER ${uid}:${gid}. If you add the user to other groups, the memberships are lost like this (say if you the flag -G video,sudo,dialout). Using just USER ${uid} solves the issue.Tessie
S
13

Add this line to docker file

USER <your_user_name>

Use docker instruction USER

Shatterproof answered 3/12, 2019 at 5:52 Comment(0)
I
6

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.

Ionize answered 14/5, 2019 at 20:9 Comment(0)
M
-12

There's no real way to do this. As a result, things like mysqld_safe fail, and you can't install mysql-server in a Debian docker container without jumping through 40 hoops because.. well... it aborts if it's not root.

You can use USER, but you won't be able to apt-get install if you're not root.

Mohr answered 24/11, 2015 at 19:19 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.