Home > Software design >  Permissions best-practices when using docker exec
Permissions best-practices when using docker exec

Time:10-21

I am going through a docker course and have a simple Docker script which sets up an image:

FROM node:14.16.0-alpine3.13
RUN addgroup app && adduser -S -G app app
USER app
WORKDIR /app
ENV PATH /app/node_modules/.bin:$PATH
COPY package*.json ./
RUN npm install
COPY . .
ENV APP_URL=http://api.myapp.com
EXPOSE 3000
CMD ["npm", "start"]

Now, in the script it switches to USER app but when I log in to Docker exec using docker exec -it 187 sh I can ask it whoami and get the response: app which is correct. The problem comes when I try to write a file using the echo command:

echo data > data.txt

sh: can't create data.txt: Permission denied

So then I run ls -la to view files and perms:

/app $ ls -la
total 1456
drwxr-xr-x    1 root     root          4096 Oct 20 16:38 .
drwxr-xr-x    1 root     root          4096 Oct 20 19:54 ..
-rw-rw-r--    1 root     root            13 Oct 20 13:46 .dockerignore
drwxr-xr-x    7 root     root          4096 Mar  9  2021 .git
-rw-r--r--    1 root     root           310 Mar  5  2021 .gitignore
-rw-rw-r--    1 root     root           311 Oct 20 16:38 Dockerfile
-rw-r--r--    1 root     root          3362 Mar  5  2021 README.md
drwxr-xr-x    1 root     root          4096 Oct 20 16:38 node_modules
-rw-rw-r--    1 root     root       1434378 Oct 20 16:10 package-lock.json
-rw-r--r--    1 root     root           814 Oct 20 16:10 package.json
drwxr-xr-x    2 root     root          4096 Mar  9  2021 public
drwxr-xr-x    2 root     root          4096 Oct 20 13:22 src

Which shows that root is the user and group set for these files/dirs. This was obviously intended as we don't want to be logging in as root. So what should I do to be able to add this file to the container? What is the best practice here? Maybe I missed a step somewhere?

Edit: Should the /app be owned by the USER app? If so, what is the point in adding a new user? should I add this to the docker script:

RUN chown app /app

Thanks!

CodePudding user response:

Should the /app be owned by the USER app?

Definitely not. You want to prevent the application from overwriting its own code and static assets, intentionally or otherwise.

So what should I do to be able to add this file to the container?

Create a dedicated directory to hold your application's data. This should be a different directory from the directory with the source code; a subdirectory of your normal application directory is fine. In the Dockerfile, make this directory (only) be owned by your non-root user.

FROM node:14.16.0-alpine3.13
RUN addgroup app && adduser -S -G app app
# don't switch to this user quite yet
WORKDIR /app
# usual setup and build stuff
COPY package*.json ./
RUN npm ci
COPY . ./
RUN npm build
# create the data directory and set its owner
RUN mkdir data && chown app data
# _now_ switch to the non-root user when running the container
EXPOSE 3000
USER app
CMD ["npm", "start"]

In practice, you probably want to persist the application's data beyond the lifespan of a single container. One approach to this is to use a Docker named volume. If you do this, the volume will be initialized from the image, including its ownership, and so you don't need any special setup here.

docker volume create app-data
docker run -v app-data:/app/data ...

For several reasons you may prefer to use a bind mount (if you need to directly access the files from outside of Docker; it may be easier to back up and restore the files; ...). You can also use the docker run -v option to bind-mount a host directory into a container, but it brings along its host-system numeric uid owner. However, notice that the only thing in the image that has the app owner is the data directory, and the code is otherwise world-readable, so if we set the container to run with the same uid as the host user, this will still work.

docker run -v "$PWD/data:/app/data" -u $(id -u) ...

You should not normally need Docker volumes for your application code (it is contained in the image), nor should you need to build a specific host uid into the image.

  • Related