Richie
Richie

Reputation: 5199

Docker File Non Root User Theory Question

I've been reading today on the theory behind uid 1001 specifically in Docker where it is a best principle not to have your container running as the root user.

What I've been able to tell so far for a unix system is...

I've seen a lot of Dockerfile examples that will just try to use 1001.

USER 1001

Two questions

Is the theory 1001 is safe to use because it is above the uid allocations ranges for new users on the host i.e. dot point 2?

Is it best practice to specify user as 1001 or would it be best adding a new user?

RUN useradd -ms /bin/bash newuser
USER newuser
WORKDIR /home/newuser

thank you

Upvotes: 2

Views: 4191

Answers (1)

David Maze
David Maze

Reputation: 158908

If your container doesn't need to write data in a named volume or a directory bind-mounted from the host, it usually doesn't matter at all what user ID the container runs as. There are a couple of restrictions still (if you're trying to listen on a port number less than 1024 your user ID must be 0 or you must manually add a capability at startup time).

I would use your second form, except I would not switch users until the end of the Dockerfile.

FROM python:3.8 # arbitrary choice
# ... install OS packages ...

# Create the user.  This doesn't need to be repeated if the
# application code changes.  It is a "system" user without
# a home directory and a default shell.  We don't care what
# its numeric user ID is.
RUN useradd -r newuser

# WORKDIR creates the directory.  It does not need to be
# under /home.  It should be owned by root.
WORKDIR /app

# Copy the application in and do its installation, still as root.
COPY requirements.txt .
RUN pip3 install -r requirements.txt
COPY . .

# Switch USER only at the end of the file.
USER newuser
CMD ["./app.py"]

"Home directory" isn't usually a well-defined concept in Docker; I've created the user without a specific home directory here, and the application directory isn't under the normal Linux /home directory. Similarly, I haven't gone out of my way to specify a shell for this user or to specifically use GNU bash.

One important security point of this setup is that root owns the application files, but newuser is running the code. If there is some sort of compromise, this gives you an additional layer of protection: the compromised application code can't overwrite the application code or its fixed static data.


I started this with the caveat that this works fine if you don't need to persist data in the filesystem. If it does it will need to be somewhat adaptable, which probably means starting up as root but then dropping privileges. I'd support two modes of running:

  1. The container is started up initially with a totally empty directory, possibly owned by root (a named Docker volume; a Kubernetes named volume). In this case, create the data directory you need and make it owned by the user in the Dockerfile.

    docker run -v somevolume:/data myimage
    
  2. The container is started up with a bind-mounted host directory and also a -u option naming the host user ID to use.

    docker run -u $(id -u) "$PWD/data:data" myimage
    

You would need to use an entrypoint wrapper script to detect which case you're in, create the initial storage structure, set its permissions, and switch to a non-root user if required. There are lighter-weight tools like gosu or su-exec that specifically support this case. The Docker Hub consul image's entrypoint script has an example of doing this at startup time.

Upvotes: 3

Related Questions