Skip to content

Instantly share code, notes, and snippets.

@dsimunic
Created January 27, 2015 17:59
Show Gist options
  • Save dsimunic/33d4b53bded2b39aa7eb to your computer and use it in GitHub Desktop.
Save dsimunic/33d4b53bded2b39aa7eb to your computer and use it in GitHub Desktop.
Running as a non-root inside a container

Running as a non-root inside a container

Docker can start a container with a specific user by passing the id on the command line with -u. The parameter to the -u switch is either a username or id of a user existing inside the container. More precisely, the container must have valid /etc/passwd file with the defined user:

$ mkdir etc 
$ echo 'postgres:x:1000:1000::/home/postgres:/bin/sh' > etc/passwd

While not needed for this simple experiment, we might want to create group and shadow files for completeness:

$ echo 'postgres:x:1000:' > etc/group
$ echo 'postgres:!:16452:0:99999:7:::' > etc/shadow
$ echo 'postgres:!::' > etc/gshadow

The next step is to create a directory in our build folder and chown it to user 1000--we don't have to have the user with this id locally.

$ mkdir data
$ touch data/file
$ chown -R 1000:1000 data

We must tar the data directory with a p flag to preserve permissions. Otherwise, if we just ADD or COPY the folder in the Dockerfile, the Docker daemon will re-set ownership on all files back to the root user (0:0).

$ tar -cpf data.tar data

Finally, we build the container. Let's also ignore the data folder so it doesn't have to be uploaded to the docker daemon as part of the build environment:

$ echo 'data' > .dockerignore

$ echo 'FROM debian:jessie
COPY etc /etc
ADD data.tar /
VOLUME ["/data"]' > Dockerfile

$ docker build -t base .

And now we can verify that indeed the permissions are preserved:

$ docker run --rm -it base ls -l /data
total 0
-rw-r--r-- 1 postgres postgres 0 Jan 17 14:17 file

Let's run as user postgres:

$ docker run --rm -itu postgres  base id
uid=1000(postgres) gid=1000(postgres) groups=1000(postgres)

The volume itself also preserves the permissions when we attach it to another container. No need to run the container, just create it; the volume is usable even when the container is not running:

$ docker create --name datavolume base /bin/true   
$ docker run --rm -it --volumes-from datavolume debian:jessie ls -ln /data
total 0
-rw-r--r-- 1 1000 1000 0 Jan 17 14:17 file 

The permissions and ownership are preserved! Any container with user 1000:1000 will have ownership of this volume. We didn't need a full container to define ownership, nor gosu to run as a specific user.

This method will work for creating lightweight data volume containers as well--we don't need the /etc/passwd file in this volume container; preserve the permissions within the folder:

$ tar cpv data/ | docker import - minimal
$ docker create --name data-only minimal :

We need to specify some command for docker create; in our case a good choice is :, which does nothing.

We can also build the same thing with a Dockerfile:

$ echo 'FROM scratch
ADD data.tar /
VOLUME ["/data"]' > Dockerfile

$ docker build -t minimal .
$ docker create --name minimal minimal :

The container that mounts this minimal volume container needs to create the user with id 1000:

$ docker run --rm --volumes-from minimal  -it debian:jessie /bin/bash -c 'useradd postgres && ls -l /data'
total 0
-rw-r--r-- 1 postgres postgres 0 Jan 17 14:17 file
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment