如何以非 root 用户身份 运行 执行 cron 作业并记录作业的输出?

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

Docker best practices 状态:

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

cron 的情况下,这似乎不切实际,因为 cron 需要 root 权限才能正常运行。然而,cron 运行s 的可执行文件不需要 root 权限。因此,我 运行 cron 本身作为 root 用户,但调用我的 crontab 脚本来 运行 可执行文件(在这种情况下,一个简单的 Python FTP 下载我写的脚本)作为非 root 用户通过 crontab -u <user> 命令。

cron/Docker 交互性和社区体验似乎仍处于起步阶段,但已经有一些非常好的解决方案。利用从 and this 优秀帖子中收集的经验教训,我得到了一个 Docker 文件,看起来像这样:

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"]

并且 mycron 文件只是一个简单的 python 执行 运行ning 每分钟

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

这工作得很好,但我不确定这里是如何处理日志记录的。我没有看到 /var/log/cron 中保存的任何内容。我可以在我的终端上看到 cronftp.py 的输出,如果我在 Kitematic 中将其拉出,也可以在容器日志中看到。但是我不知道这里到底发生了什么。

所以我的第一个问题是:这里如何处理日志记录和输出(cron 作业后没有任何重定向),这个实现方法是否安全?

VonC 对 的回答建议将 > /proc/1/fd/1 2>/proc/1/fd/2 附加到您的 cron 作业以将输出重定向到 Docker 的 stdoutstderr。这就是我俩都有些困惑的地方,并且 运行 遇到了麻烦。

我的 crontab 文件现在看起来像这样

* * * * * /home/riptusk331/venv/bin/python3 /home/riptusk331/ftp.py > /proc/1/fd/1 2>/proc/1/fd/2
  1. 没有任何重定向的输出出现已经去stdout/stderr,但我不完全确定。我只知道它出现在我的终端上。那么为什么需要这个重定向呢?

  2. 当我添加这个重定向时,我 运行 遇到了权限问题。回想一下,这个 crontab 是作为 非根用户 riptusk331 调用的。因此,我没有 root 访问权限并收到以下错误:

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

Alpine 基础镜像基于一个名为 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 的紧凑工具集(在 C 中),您会发现当它转到 运行 a 时根本没有任何重定向作业(参见 start_one_job 的非 sendmail 版本);作业的 stdout 和 stderr 是 crond 的 stdout 和 stderr。在 Docker 中,由于 crond 是容器的主要进程,因此它又成为容器的输出流。

docker logs 中出现的任何内容都定义为 stdout 或 stderr 或容器的主进程。如果此 cron 实现直接将您的作业输出写入那里,那么利用它并没有错或不安全。

在较重的容器编排系统中,有一些方法可以 运行 容器按计划(Kubernetes CronJobs,Nomad 周期性作业)。您可能会发现设置一个容器 运行 完成您的工作然后退出,然后设置 主机的 cron 到 运行 你的容器(必须是 root)。

您需要允许 CAP_SETGID 到 运行 crond 作为用户,如果将其设置为所有 busybox 二进制文件,这可能存在安全风险,但您可以使用 dcron 包而不是 busybox 的内置 crond 并在该程序上设置 CAP_SETGID 。这是您需要为 Alpine 添加的内容,使用 riptusk331 as 运行ning 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