redis / docker-library-redis

Docker Official Image packaging for Redis
http://redis.io
BSD 3-Clause "New" or "Revised" License
1.11k stars 560 forks source link

Cannot run redis container as a non-root user #356

Closed mickel8 closed 1 year ago

mickel8 commented 1 year ago

When I am trying to run redis as non-root user with

# (fish shell)
docker run -u (id -u):(id -g) -v ./myredis3:/data --name myredis3 redis

I cannot close the container. The error is as follows:

1:signal-handler (1682528872) Received SIGINT scheduling shutdown...
1:M 26 Apr 2023 17:07:52.576 # User requested shutdown...
1:M 26 Apr 2023 17:07:52.576 * Saving the final RDB snapshot before exiting.
1:M 26 Apr 2023 17:07:52.576 # Failed opening the temp RDB file temp-1.rdb (in server root dir /data) for saving: Permission denied
1:M 26 Apr 2023 17:07:52.576 # Error trying to save the DB, can't exit.
1:M 26 Apr 2023 17:07:52.576 # Errors trying to shut down the server. Check the logs for more information.

I believe that this is because /data directory is always chown to redis:redis no matter we are running as root or non-root. In case of running as non-root, some user (who is running docker) will try to write to the /data where only redis user can write.

tianon commented 1 year ago

I believe that this is because /data directory is always chown to redis:redis no matter we are running as root or non-root. In case of running as non-root, some user (who is running docker) will try to write to the /data where only redis user can write.

We actually can't chown as non-root :sweat_smile: That's why this check makes sure id -u returns 0:

https://github.com/docker-library/redis/blob/1609d202febf50daa01c8effab2a72e2fab1c2b5/docker-entrypoint.sh#L10-L14

My guess is that you probably ran this line without -u in the past, and thus your myredis3 folder was already pre-chown'd, so you need to run something like sudo chown -R (id -u):(id -g) myredis3 to fix it before this command will work.

mickel8 commented 1 year ago

What about this line

https://github.com/docker-library/redis/blob/master/7.0/Dockerfile#L112

Here, we chown to redis:redis :thinking: Shouldn't we write RUN mkdir /data ?

tianon commented 1 year ago

The directory in the image, yes, but that shouldn't "chown" your local directory.

mickel8 commented 1 year ago

But when I run redis with -u and -v, isn't this like I am trying to write something as host user to a directory owned by redis user?

I don't fully get why we have to chown /data to redis:redis in the Dockerfile :thinking: . When we run redis as root, then every file is chown to redis in the entrypoint. When we run redis as non-root then only /data is chown to redis in the dockerfile.

tianon commented 1 year ago

Because the entrypoint does a chown on /data if you run the image as root, if you ever did that before this line you've shared with us, it would've run chown on it and you'd have to fix that before you run it again. I've just verified that this does work correctly and nothing is chown'd if you run as non-root:

$ mkdir redis
$ docker run -it --rm --user "$(id -u):$(id -g)" -v "$PWD/redis":/data --name redis redis
Unable to find image 'redis:latest' locally
latest: Pulling from library/redis
26c5c85e47da: Already exists 
39f79586dcf2: Pull complete 
79c71d0520e5: Pull complete 
60e988668ca1: Pull complete 
873c3fc9fdc6: Pull complete 
50ce7f9bf183: Pull complete 
Digest: sha256:f50031a49f41e493087fb95f96fdb3523bb25dcf6a3f0b07c588ad3cdbe1d0aa
Status: Downloaded newer image for redis:latest
1:C 26 Apr 2023 22:56:24.435 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
1:C 26 Apr 2023 22:56:24.435 # Redis version=7.0.11, bits=64, commit=00000000, modified=0, pid=1, just started
1:C 26 Apr 2023 22:56:24.435 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf
1:M 26 Apr 2023 22:56:24.435 * monotonic clock: POSIX clock_gettime
                _._                                                  
           _.-``__ ''-._                                             
      _.-``    `.  `_.  ''-._           Redis 7.0.11 (00000000/0) 64 bit
  .-`` .-```.  ```\/    _.,_ ''-._                                  
 (    '      ,       .-`  | `,    )     Running in standalone mode
 |`-._`-...-` __...-.``-._|'` _.-'|     Port: 6379
 |    `-._   `._    /     _.-'    |     PID: 1
  `-._    `-._  `-./  _.-'    _.-'                                   
 |`-._`-._    `-.__.-'    _.-'_.-'|                                  
 |    `-._`-._        _.-'_.-'    |           https://redis.io       
  `-._    `-._`-.__.-'_.-'    _.-'                                   
 |`-._`-._    `-.__.-'    _.-'_.-'|                                  
 |    `-._`-._        _.-'_.-'    |                                  
  `-._    `-._`-.__.-'_.-'    _.-'                                   
      `-._    `-.__.-'    _.-'                                       
          `-._        _.-'                                           
              `-.__.-'                                               

1:M 26 Apr 2023 22:56:24.436 # Server initialized
1:M 26 Apr 2023 22:56:24.436 # WARNING Memory overcommit must be enabled! Without it, a background save or replication may fail under low memory condition. Being disabled, it can can also cause failures without low memory condition, see https://github.com/jemalloc/jemalloc/issues/1328. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.
1:M 26 Apr 2023 22:56:24.436 * Ready to accept connections
^C1:signal-handler (1682549859) Received SIGINT scheduling shutdown...
1:M 26 Apr 2023 22:57:39.067 # User requested shutdown...
1:M 26 Apr 2023 22:57:39.067 * Saving the final RDB snapshot before exiting.
1:M 26 Apr 2023 22:57:39.074 * DB saved on disk
1:M 26 Apr 2023 22:57:39.074 # Redis is now ready to exit, bye bye...
$ ls -lan redis/
total 12
drwxr-xr-x 2 1000 1000 4096 Apr 26 15:57 .
drwxr-xr-x 6 1000 1000 4096 Apr 26 15:55 ..
-rw------- 1 1000 1000   89 Apr 26 15:57 dump.rdb
yosifkit commented 1 year ago

If you change the user that the container runs as, then you also have to provide a directory that the chosen user can write to (since we aren't running as root, we can't chown anything). A few scenarios of how docker works with a bind mount local directory (and a name volume). All these tests are on Docker Desktop using WSL2 but have the same results on a regular Linux distribution.

Running as-is, no user specified. This is where the entrypoint chown comes in.

$ ls -l
total 0
$ docker run -it --rm -v "$PWD/myredis:/data" redis
...
^C1:signal-handler (1682548431) Received SIGINT scheduling shutdown...
1:M 26 Apr 2023 22:33:51.366 # User requested shutdown...
1:M 26 Apr 2023 22:33:51.366 * Saving the final RDB snapshot before exiting.
1:M 26 Apr 2023 22:33:51.371 * DB saved on disk
1:M 26 Apr 2023 22:33:51.371 # Redis is now ready to exit, bye bye...
$ ls -ln
total 4
drwxr-xr-x 2 999 0 4096 Apr 26 15:33 myredis

Running as my user, without creating a directory first. The failure happens because dockerd will create the source directory if it doesn't exist and it will be root owned.

$ ls -l
total 0
$ docker run -it --rm -u "$(id -u):$(id -g)" -v "$PWD/myredis:/data" redis
...
^C1:signal-handler (1682548603) Received SIGINT scheduling shutdown...
1:M 26 Apr 2023 22:36:43.336 # User requested shutdown...
1:M 26 Apr 2023 22:36:43.336 * Saving the final RDB snapshot before exiting.
1:M 26 Apr 2023 22:36:43.336 # Failed opening the temp RDB file temp-1.rdb (in server root dir /data) for saving: Permission denied
1:M 26 Apr 2023 22:36:43.336 # Error trying to save the DB, can't exit.
1:M 26 Apr 2023 22:36:43.336 # Errors trying to shut down the server. Check the logs for more information.
$ ls -l
total 4
drwxr-xr-x 2 root root 4096 Apr 26 15:36 myredis
$ ls -ln
total 4
drwxr-xr-x 2 0 0 4096 Apr 26 15:36 myredis

Running as my user, but create the directory first.

$ ls -n
total 0
$ mkdir myredis
$ ls -ln
total 4
drwxr-xr-x 2 1000 1000 4096 Apr 26 15:48 myredis
$ docker run -it --rm -u "$(id -u):$(id -g)" -v "$PWD/myredis:/data" redis
...
^C1:signal-handler (1682549348) Received SIGINT scheduling shutdown...
1:M 26 Apr 2023 22:49:08.349 # User requested shutdown...
1:M 26 Apr 2023 22:49:08.349 * Saving the final RDB snapshot before exiting.
1:M 26 Apr 2023 22:49:08.357 * DB saved on disk
1:M 26 Apr 2023 22:49:08.357 # Redis is now ready to exit, bye bye...
$ ls -ln
total 4
drwxr-xr-x 2 1000 1000 4096 Apr 26 15:49 myredis

Running with a new named volume. This doesn't work as a different user, since the permissions of a new named volume get inherited from the image (this is where the Dockerfile chown comes into play).

$ docker volume create myredis-vol
myredis-vol
$ docker run -it --rm -u "$(id -u):$(id -g)" -v "myredis-vol:/data" redis
...
^C1:signal-handler (1682549865) Received SIGINT scheduling shutdown...
1:M 26 Apr 2023 22:57:45.440 # User requested shutdown...
1:M 26 Apr 2023 22:57:45.440 * Saving the final RDB snapshot before exiting.
1:M 26 Apr 2023 22:57:45.440 # Failed opening the temp RDB file temp-1.rdb (in server root dir /data) for saving: Permission denied
1:M 26 Apr 2023 22:57:45.440 # Error trying to save the DB, can't exit.
1:M 26 Apr 2023 22:57:45.440 # Errors trying to shut down the server. Check the logs for more information.
$ docker run -it --rm -u "$(id -u):$(id -g)" -v "myredis-vol:/data" redis bash
I have no name!@43913f565087:/data$ ls -lna
total 8
drwxr-xr-x 2 999 999 4096 Apr 17 22:51 .
drwxr-xr-x 1   0   0 4096 Apr 26 22:58 ..
mickel8 commented 1 year ago

Then what is the purpose of chown in RUN mkdir /data && chown redis:redis /data?

Assuming we always mount host directory (using -v):

When we run without mounting host directory but as a non-root user e.g. docker run -it --rm -u "$(id -u):$(id -g)" redis this also fails.

So I cannot find the reason of RUN mkdir /data && chown redis:redis /data instead of RUN mkdir /data.

yosifkit commented 1 year ago

So I cannot find the reason of RUN mkdir /data && chown redis:redis /data instead of RUN mkdir /data.

The chown is there for the named volume (with -v myredis-vol:/data) or anonymous volume (no -v or --mount). It is applicable if starting as root (and the find | chown skips it because it is already the right user). It is also there when running as the redis user: docker run --user redis:redis redis.

mickel8 commented 1 year ago

Thank you! That is really helpful! . Do you know any resources where I can read more about permissions of docker volumes and dockerd? I believe that this kind of info is missing in the docummentation of volumes