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:
Symbol | Meaning |
---|---|
d | It indicates that this is a directory. |
rwx | The owner’s permissions. In this case, the owner has read, write and execute permissions. |
rwx | The group’s permissions. A user belongs to one or more groups. In this case, the permissions are identical for the owner. |
r-x | The other’s permissions. Anyone else, not being the owner or not belonging to the group, will have in this case read and execute permissions. |
user | The 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 groupgroupcontainer
is created with gid 1000; - With
RUN adduser
, a usercontaineruser
is created with uid 1000, belonging to groupgroupcontainer
and home directory/home/containeruser
; - With
USER containeruser
, the container runs with usercontaineruser
; - The local
example.txt
file is copied to the home directory ofcontaineruser
.
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!