ScanSkill
Sign up for daily dose of tech articles at your inbox.
Loading

Permission Denied Errors with Docker Files and Volumes

Permission Denied Errors with Docker Files and Volumes
Permission Denied Errors with Docker Files and Volumes

In this article, we’ll be discussing permission denied errors with docker files and volumes. Also, you will get to learn why you get a ‘Permission Denied’ error and how to solve it.

If you encountered a ‘Permission Denied’ problem when accessing a file on a mounted drive inside a Docker container or when copying a file to a Docker image, this is the article for you!

Let’s dive into it!!

Introduction

Before getting into the Permission Denied issue with Docker containers, it is wise to have a fundamental understanding of how Linux permissions work. You can skip this paragraph if you are already familiar with it.

For a better and fantastic explanation of Linux permissions, you can go and check out the official documentation: Ubuntu documentation and this excellent explanation about umask. Please continue reading, if you want a brief summary!

Let’s say you created a directory called articles and if you list the properties of that directory, you will see the following output in a terminal window:

$ mkdir articles
$ ls -la

drwxrwxr-x  2 user group 4096 Dec 02 02:15 articles/

Here, let’s talk about what these symbols means:

SymbolMeaning
dIt indicates that this is a directory.
rwxThe owner’s permissions. In this case, the owner has read, write and execute permissions.
rwxThe group’s permissions. A user belongs to one or more groups. In this case, the permissions are identical for the owner.
r-xThe other’s permissions. Anyone else, not being the owner or not belonging to the group, will have in this case read and execute permissions.
userThe directory is owned by this user. Under the hood, this logical name is mapped to a user id (uid). When you have only one user, this will probably be uid 1000.
group The directory is owned by this group. Under the hood, this logical name is mapped to a group id (gid). Your gid will probably be gid 1000.

Also when you create a file defaultpermissions.txt and list the properties of the file, you will see a similar output:

$ touch defaultfilepermissions.txt
$ ls -la

-rw-rw-r-- 1 user group    0 Dec 02 02:20 defaultfilepermissions.txt

The permissions are listed in a similar way as for the directory. There is no d as the first item because it is not a directory of course and the file does not have any execute permissions.

Prerequisites

  • Docker installed and set up on your machine or server or VM

Permission Denied Errors with Docker Files and Volumes

Container Running as Root

In this first test, a file will be copied from the local file system to the Docker image. The base image for the Docker image is the Alpine Linux image.

Also, create a directory 1-defaultcontainer, navigate to the directory, and create a example.txt file with some dummy content. Create a Dockerfile in the same directory with the following contents:

FROM alpine:3.16.2

COPY example.txt /tmp/example.txt

The FROM instruction will use the Alpine Linux 3.16.2 base Docker image and the COPY instruction will copy the local example.txt file into the Docker image at location /tmp/example.txt.

From a terminal window, build the Docker image:

$ sudo docker build -f Dockerfile -t dockerexample .

[sudo] password for osboxes:
Sending build context to Docker daemon  3.072kB
Step 1/2 : FROM alpine:3.16.2
3.16.2: Pulling from library/alpine
213ec9aee27d: Pull complete
Digest: sha256:bc41182d7ef5ffc53a40b044e725193bc10142a1243f395ee852a8d9730fc2ad
Status: Downloaded newer image for alpine:3.16.2
 ---> 9c6f07244728
Step 2/2 : COPY example.txt /tmp/example.txt
 ---> 842ef14a6a73
Successfully built 842ef14a6a73
Successfully tagged dockerexample:latest

Start the Docker container with an interactive mode in order to be able to use the shell:

$ sudo docker run --rm -it dockerexample /bin/sh

Navigate to directory /tmp and list the files:

# ls -la

-rw-rw-r--    1 root     root            23 Dec 02 02:33 example.txt

Notice that the file permissions are preserved, but the user/group is root/root. By default, a Docker container runs as the root user which is a security concern.

Try to execute cat example.txt and you will notice that the contents of the file are output. Try to edit the file by means of vi and save the file. This action is also allowed. These results are logical: the root user executes them and the root can do anything.

Now, exit the shell by typing exit.

In order to ensure that the tests are executed independently from each other, remove the Docker image as follows:

$ sudo docker rmi dockerexample

Container Running as User 1000

This test is similar to the first one, except that you will create a user for the Docker container. This way, the container will not run anymore as the root user, which is a more secure way of running a container.

Create a directory 2-containeruser1000, navigate to the directory, and create a example.txt file with some dummy content. Create a Dockerfile in the same directory with the following contents:

FROM alpine:3.16.2

RUN addgroup --g 1000 groupcontainer

RUN adduser -u 1000 -G groupcontainer -h /home/containeruser -D containeruser

USER containeruser

COPY example.txt /home/containeruser/example.txt

Here,

  • With RUN addgroup, a group groupcontainer is created with gid 1000;
  • With RUN adduser, a user containeruser is created with uid 1000, belonging to group groupcontainer and home directory /home/containeruser;
  • With USER containeruser, the container runs with user containeruser;
  • The local example.txt file is copied to the home directory of containeruser.

This Dockerfile can be made more efficient in order to reduce the number of layers. For more information about layers, read a previous post about this topic. For sake of simplicity, optimizing the Docker image is not considered here.

Build and run the container just like you did before. First check which user is running the container:

# whoami

containeruser

As expected, the container runs as user containeruser. Navigate to the home directory of containeruser and list the files:

# ls -la

-rw-rw-r--    1 root     root            23 Dec 02 02:58 example.txt

This might surprise you, but the owner of the file is still root/root.

Try to execute cat example.txt and you will notice that the contents of the file are output. This can be done because other has read permissions. Remember, the container runs as user containeruser now. Try to edit the file with vi and save the file. This is not possible: a warning is raised that the file is read-only. That is because other does not have write permissions.

When you are still not convinced, execute the same test but with uid/gid 1024. The results are the same. The files are available in the repository in directory 3-containeruser1024. Below the corresponding Dockerfile:

FROM alpine:3.16.2

RUN addgroup --g 1024 groupcontainer

RUN adduser -u 1024 -G groupcontainer -h /home/containeruser -D containeruser

USER containeruser

COPY example.txt /home/containeruser/example.txt

You can now remove the Docker image.

Container Running as User 1024 and Changed Ownership

In this paragraph, you will solve the permission issue. The trick is to change the ownership of the file to the user running the Docker container. Create a directory 4-containeruser1024changedowner. The Dockerfile is:

FROM alpine:3.16.23

RUN addgroup --g 1024 groupcontainer

RUN adduser -u 1024 -G groupcontainer -h /home/containeruser -D containeruser

USER containeruser

COPY --chown=containeruser:groupcontainer example.txt /home/containeruser/example.txt

The line containing COPY, the ownership of the example.txt file is changed to user containeruser and group groupcontainer.

Build and run the container just like you did before. Navigate to the home directory of user containeruser and list the files:

# ls -la

-rw-rw-r--    1 containe groupcon        23 Dec 02 04:49 example.txt

Try to execute cat example.txt and you will notice that the contents of the file are output. Try to edit the file with vi and save the file. This is allowed, because this time, containeruser owns the file and has the proper write permissions.

Now, you can remove the Docker image.

Volume Mappings

You can map a local directory to a directory inside a Docker container using volume mappings. Because you have to rely on some assumptions about the local system permissions, users, groups, etc., this can be trickier. And most of the time, this just works because your local uid/gid is usually 1000/1000 and this will be similar inside the container. The uid/gid of the owner must match both outside and inside the container when using volume mappings.

Explanation

Let’s create a directory 5-volumemapping and create a directory exampledir and a example.txt file with some dummy contents inside this directory.

Check the uid/gid of your local user:

$ id -u osboxes

1000
$ id -g osboxes

1000

The permissions of the directory are:

$ ll

drwxrwxr-x 2 osboxes osboxes 4096 Dec 02 03:19 exampledir/

The permissions of the file are:

$ ll

-rw-rw-r-- 1 osboxes osboxes   23 Aug 14 03:22 example.txt

Now, use the following Dockerfile:

FROM alpine:3.16.2

RUN addgroup --g 1024 groupcontainer

RUN adduser -u 1024 -G groupcontainer -h /home/containeruser -D containeruser

USER containeruser

RUN mkdir /home/containeruser/exampledir

Keep in mind that it is crucial for the test that your local user’s uid and gid differ from the user inside the container. This time, instead of copying the file to the container, you use RUN mkdir to create a directory that the local volume can be mapped to.

Again, build the Docker image as before and run the container from the inside directory 5-volumemapping as follows. The -v parameter will mount the local exmapledir directory to the exampledir directory into the home directory of user containeruser.

$ sudo docker run -v $(pwd)/exampledir:/home/containeruser/exampledir --rm -it dockerexample /bin/sh

Then, navigate to the directory /home/containeruser and list the contents:

# ls -la

drwxrwxr-x    2 1000     1000          4096 Dec 02 03:24 exampledir

As you can see, the uid/gid has the value 1000/1000 which is the uid/gid of the local system user who has created the directory.

Navigate to the directory exampledir and list the contents:

# ls -la

-rw-rw-r--    1 1000     1000            23 Dec 02 03:36 example.txt

Again, you notice the same ownership for the file as for the directory.

And try to read the contents of file example.txt, this succeeds. Try to create a new file exmaple2.txt, this returns a Permission Denied error because other does not have write permissions in this directory.

# cat example.txt

this is a test message
# touch example.txt

touch: example2.txt: Permission denied

You can find a lot of articles online on how to solve this.

Change the ownership of the directory in order that group 1024 has ownership on the local system.

$ sudo chown :1024 exampledir/

Ensure that new files get the group ownership.

$ chmod g+s exampledir/

Check the directory permissions from inside the container of the directory exampledir:

# ls -la

drwxrwxr-x    2 1000     groupcon      4096 Dec 02 04:28 exampledir
drwxrwxr-x    2 1000     groupcon      4096 Dec 02 04:32 exampledir

Now you notice that the group groupcontainer has ownership of this directory.

Navigate to the directory exampledir, create a file, edit it with vi and output the contents. All of this is possible now.

# touch example2.txt
# vi example2.txt
# cat example2.txt

another test message

Check the permissions of the files.

# ls -la

-rw-rw-r--    1 1000     1000            23 Dec 02 04:44 example2.txt

-rw-r--r--    1 containe groupcon         0 Dec 02 04:46 example2.txt

The file example.txt still has its original ownership for uid/gid 1000/1000, the new example2.txt file has ownership for containeruser/groupcontainer.

It will be possible to read the contents of example2.txt from the local system, but it will not be possible to change its contents because of the read-only permissions for other. Several options exist to tackle this depending on your use case, as stated in the linked blog post.

Remove the Docker image.

That’s it!

Conclusion

In this article, we talk about how permission denied error with docker files and volumes can be handled.

Moreover, when copying files into Docker images, Permission Denied problems can be simply resolved within the Dockerfile. Simply follow the solution outlined in this blog. Volume mappings between a local directory and a directory inside the container can cause Permission Denied errors. Hopefully, the information in this blog will assist you in understanding and resolving Permission Denied errors.

Thank you!

Sign up for daily dose of tech articles at your inbox.
Loading