nextcloud / docker

⛴ Docker image of Nextcloud
https://hub.docker.com/_/nextcloud/
GNU Affero General Public License v3.0
6.06k stars 1.83k forks source link

Make cron.php be executed by UID provided at startup. #1740

Open Moltey opened 2 years ago

Moltey commented 2 years ago

Expectation:

Cron should execute cron.php with the UID the container is started with (in case a UID is provided).

Status Quo:

Cron.php is executed with www-data, which is UID 33 / 34 (depends on distribution) in the container.

Result: Cron fails to execute cron.php withe the appropriate user.

Details:

Due to security reasons, I am running all my containers rootless and with seperated user accounts. I think rootless non-root execution will be the future of containerization anyways.

I utilize user 1008 for nextcloud.

Nextcloud recognizes this fact and reminds the user that cron is to be executed by the same user in the web interface:

Use system cron service to call the cron.php file every 5 minutes. The cron.php needs to be executed by the system user "1008".

Therefore, I want to start the cron container with the same UID as the app:

$ podman run -d \
  --name=nextcloud-cron \
  --pod=nextcloud \
  --restart unless-stopped \
  --runtime crun \
  --user 1008:1008 \
  -v ~/nc/html:/var/www/html:z \
  -v ~/nc/data:/var/www/data:z \
  --cap-add=CAP_NET_BIND_SERVICE \
  --cap-add=CAP_SETGID \
  --cap-add=CAP_SETUID \
  --entrypoint=/cron.sh \
  docker.io/library/nextcloud:latest

The containers works, file access is fine for UID 1008 - however, the execution of cron.php fails:

crond: USER www-data pid   4 cmd php -f /var/www/html/cron.php
Could not open input file: /var/www/html/cron.php

Nevermind, as "www-data" would be UID 33 and not the appropriate user anyways (should be 1008, as announced by nextcloud). File access for UID 1008 is working fine though.

If I change the UID of www-data in passwd to the designated UID 1008 and passthrough the passwd to the container, the execution fails:

Passwd line:

www-data:x:1008:33:www-data:/var/www:/usr/sbin/nologin

Additional passthrough of passwd for the start of podman:

  -v ~/nc/passwd:/etc/passwd:ro \

Output of the cron-log:

crond: USER www-data pid   2 cmd php -f /var/www/html/cron.php
This account is currently not available.

There is a solution, but it is crap: The execution of cron-php via host works fine:

$ podman exec --user 1008 -t nextcloud-cron php -f /var/www/html/cron.php

Desperate users could execute this line via crond of the host but hopefully you agree that this is not what we want to see ;)

J0WI commented 2 years ago

This might be a duplicate of https://github.com/nextcloud/docker/issues/359

vicky-bs commented 2 years ago

I have a similar issue and I have tried different images, removed and reinstalled multiple times and cron doesn't run as it's supposed to. Here are the details of my setup (please excused me as I'm new to self hosting but have spent huge number of hours trying to solve this issue)

OS - Windows Distro - WSL2 kernel and Ubuntu Nextcloud - Latest version with mariadb and redis Issue - Selecting Cron in setting doesn't do anything Solutions tried -

  1. Removed and reinstalled nextcloud, Ubuntu, WSL - Still no solution
  2. Install an image along with cron container - Didn't help
  3. Tried sudo crontab -u www-data -e and adding the cron line + service cron start - service cron status shows running but didn't help
  4. Tried docker exec -u 33 -t nextcloud php -f /var/www/html/cron.php - It runs but this is a manual one time activity post which cron is not running
  5. Tried crontab -e on ubuntu and adding cron line */5 **** php -f /var/www/html/cron.php - No help it doesn't run
  6. in all cases tried provide absolute php path - Still didn't work
  7. Tried system timer as mentioned in doc however systemd doesn't work as it gives an error about PID. Tried alternate command for init and still didn't work
  8. I still tried few other's that I forgot to document to review but none helped run cron

I'm finally reaching out here to see if anyone could help

Thanks,

SaswatPadhi commented 2 years ago

@J0WI: #359 fixes the UID/GID issue with apache (in the "app" container), but the "cron" container that runs the cron jobs, the user is hard coded as www-data:

https://github.com/nextcloud/docker/blob/6e7695e4439e18900ce4435de359d8ece6b6a35f/Dockerfile-alpine.template#L10-L11

So what ends up happening is, apache runs as a non-root user as per the UID:GID, but cron runs as www-data and fails repeatedly with permission errors.

@Moltey: I have implemented another solution:

I override the cron.sh to change the www-data hardcoding:

#!/bin/sh
set -eu

adduser --disabled-password --gecos "" --uid "$APACHE_UID" user

mv /var/spool/cron/crontabs/www-data /var/spool/cron/crontabs/user
exec busybox crond -f -l 0 -L /dev/stdout

then I mount it (read-only) within my "app" container, and pass the appropriate APACHE_UID to my "cron" container:

services:
  ...
  app:
    ...
    volumes:
    - ./cron.sh:/cron.sh:ro
    ...
  cron:
    ...
    volumes_from:
    - app:rw
    environment:
      APACHE_UID: 1008

That's the key idea, but I implemented a couple of other hacks to be able to edit the crontab file directly from the host -- it's reloaded automatically in the "cron" container.

@J0WI: I think the app (not cron) entrypoint should create a new user with the UID:GID and add move the cron job (from www-data) to that user. Then the cron container would work as expected without any additional hacks

J0WI commented 1 year ago

I tried to move a simple echo "*/5 * * * * php -f /var/www/html/cron.php" | busybox crontab - script to the cron.sh entrypoint itself, but unfortunately busybox does not allow to run crontab as non-root: https://git.busybox.net/busybox/tree/miscutils/crontab.c?h=1_35_stable#n110

SaswatPadhi commented 1 year ago

Yes, busybox requires crond to run as root.

The current entrypoint script does run it as root. The problem is just that the crontab file (at /var/spool/cron/crontabs) is under the wrong user (www-data). When the nextcloud container runs with a non-root UID (using --user), the crontab file should actually be renamed to that user's name in place of www-data, to avoid permission issues.

As you have noticed, it's currently not possible to run the cron container as a non-root user, although nextcloud container can run as a non-root user. Currently, even when the cron container is run as root, the cron jobs fail with permission errors.

As for security, the cron container only runs the crond process as root. The actual cron tasks (php) are run with the respective user's UID, which is www-data currently.

J0WI commented 1 year ago

At this point, I think it's easier to just run your own docker run -v my_nextcloud:/var/www/html --user my_user nextcloud:fpm-alpine sh -c 'while true; do php -f /var/www/html/cron.php; sleep 5m; done'. Or, as already mentioned above, just use a timer on your host that runs docker exec ....

There is no trivial way to run the cron script as non-root and detect whatever user is used in the other container.

SaswatPadhi commented 1 year ago

The bug report is about making cron.php be executed by the right UID, not crond.

I think you are mixing up the cron daemon with cron scripts (or crontabs).

There is no trivial way to run the cron script as non-root

False. They (var/spool/cron/crontabs/www-data) already do, just as the wrong user.

J0WI commented 1 year ago

If you run the cron container as root, it can run crond and manage crontabsfor all users. However, the cron container has no knowledge of the user that runs in the other PHP container. You have to specify the user. The above example executes cron.php as my_user.

Moltey commented 1 year ago

At this point, I think it's easier to just run your own docker run -v my_nextcloud:/var/www/html --user my_user nextcloud:fpm-alpine sh -c 'while true; do php -f /var/www/html/cron.php; sleep 5m; done'. Or, as already mentioned above, just use a timer on your host that runs docker exec ....

There is no trivial way to run the cron script as non-root and detect whatever user is used in the other container.

Can we please agree that this is a very nasty workaround? 😄

I ended up calling cron.php via the crontab of the host machine which is not satisfying, neither.

IMHO, this is a design issue you might want to consider in one of the next major releases.

J0WI commented 1 year ago

This is somewhat covered in https://github.com/nextcloud/docker/pull/1901

SaswatPadhi commented 1 year ago

Running crond (the daemon) as non-root and running the cron.php file (the cron job) as non-root are two different things.

remus-selea commented 1 year ago

I attempted to use the nextcloud cron container, but it didn't work as described in this issue. The container was configured to run as a non-root user using the user option with a specific UID and GID, but the cronjob failed. I believe it is not worth using it as it needs to run as root. Running containers as root is generally not recommended due to security reasons.

I decided to set up a cronjob on my LXC host. I added a cronjob for a non-root user who is also not part of the sudo group, to run the cron script inside the nextcloud container using docker exec.

*/5 * * * * docker exec -u 1000:1000 nextcloud_container  php ./cron.php

To check that the cronjob ran successfully, I searched the syslog for the cron script using this command:

grep -a "cron.php" /var/log/syslog

This solution will work for me until Nextcloud decides to address the issue.

chylex commented 1 year ago

I ended up building a custom image with supercronic, couldn't get crond to work as non-root either.

ARG NEXTCLOUD_VERSION
FROM nextcloud:${NEXTCLOUD_VERSION}-apache

ENV SUPERCRONIC_VERSION="v0.2.25"
ENV SUPERCRONIC_PACKAGE="supercronic-linux-amd64"
ENV SUPERCRONIC_SHA1SUM="642f4f5a2b67f3400b5ea71ff24f18c0a7d77d49"

ENV SUPERCRONIC_URL="https://github.com/aptible/supercronic/releases/download/$SUPERCRONIC_VERSION/$SUPERCRONIC_PACKAGE"

RUN curl --fail --silent --show-error --location --output /supercronic "${SUPERCRONIC_URL}" && \
    echo "${SUPERCRONIC_SHA1SUM}  /supercronic" | sha1sum -c -                              && \
    chmod +x /supercronic

RUN echo "${CRON:-"*/10 * * * *"} php -f /var/www/html/cron.php" > /crontab

ENTRYPOINT ["/supercronic", "/crontab"]
IceflowRE commented 3 months ago

To summarize this, it is currently impossible to run the docker container as a different user?