简体   繁体   中英

How to run a cron job as a non-root user and log the job's output?

Docker best practices state:

If a service can run without privileges, use USER to change to a non-root user.

In the case of cron , that doesn't seem practical as cron needs root privileges to function properly. The executable that cron runs, however, does NOT need root privileges. Therefore, I run cron itself as the root user, but call my crontab script to run the executable (in this case, a simple Python FTP download script I wrote) as a non-root user via the crontab -u <user> command.

The cron/Docker interactability and community experience still seems to be in its infancy, but there are some pretty good solutions out there. Utilizing lessons gleaned from this and this great posts, I arrived at a Dockerfile that looks something like this:

FROM python:3.7.4-alpine

RUN adduser -S riptusk331
WORKDIR /home/riptusk331

... boilerplate not necessary to post here ...

COPY mycron /etc/cron.d/mycron
RUN chmod 644 /etc/cron.d/mycron
RUN crontab -u riptusk331 /etc/cron.d/mycron

CMD ["crond", "-f", "-l", "0"]

and the mycron file is just a simple python execution running every minute

* * * * * /home/riptusk331/venv/bin/python3 /home/riptusk331/ftp.py

This works perfectly fine, but I am unsure of how exactly logging is being handled here. I do not see anything saved in /var/log/cron . I can see the output of cron and ftp.py on my terminal, as well as in the container logs if I pull it up in Kitematic. But I have no idea what is actually going on here.

So my first question(s) are: how is logging & output being handled here (without any redirects after the cron job), and is this implementation method ok & secure?

VonC's answer to this post suggests appending > /proc/1/fd/1 2>/proc/1/fd/2 to your cron job to redirect output to Docker's stdout and stderr . This is where I both get a little confused, and run into trouble.

My crontab file now looks like this

* * * * * /home/riptusk331/venv/bin/python3 /home/riptusk331/ftp.py > /proc/1/fd/1 2>/proc/1/fd/2
  1. The output without any redirection appeared to be going to stdout/stderr already, but I am not entirely sure. I just know it was showing up on my terminal. So why would this redirect be needed?

  2. When I add this redirect, I run into permissioning issues. Recall that this crontab is being called as the non-root user riptusk331 . Because of this, I don't have root access and get the following error:

/bin/ash: can't create /proc/1/fd/1: Permission denied

The Alpine base images are based on a compact tool set called BusyBox and when you run crond here you're getting the BusyBox cron and not any other implementation. Its documentation is a little sparse, but if you look at the crond source (in C) what you'll find is that there is not any redirection at all when it goes to run a job (see the non-sendmail version of start_one_job ); the job's stdout and stderr are crond's stdout and stderr. In Docker, since crond is the container primary process, that in turn becomes the container's output stream.

Anything that shows up in docker logs definitionally went to stdout or stderr or the container's main process. If this cron implementation wrote your job's output directly there, there's nothing wrong or insecure with taking advantage of that.

In heavier-weight container orchestration systems, there is some way to run a container on a schedule (Kubernetes CronJobs, Nomad periodic jobs). You might find it easier and more consistent with these systems to set up a container that runs your job once and then exits, and then to set up the host's cron to run your container (necessarily, as root).

You need to allow the CAP_SETGID to run crond as user, this can be a security risk if it is set to all busybox binary but you can use dcron package instead of busybox's builtin crond and set the CAP_SETGID just on that program. Here is what you need to add for Alpine, using riptusk331 as running user

USER root
# crond needs root, so install dcron and cap package and set the capabilities 
# on dcron binary https://github.com/inter169/systs/blob/master/alpine/crond/README.md
RUN apk add --no-cache dcron libcap && \
    chown riptusk331:riptusk331 /usr/sbin/crond && \
    setcap cap_setgid=ep /usr/sbin/crond

USER riptusk331

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM