【问题标题】:Why is crond failing to run a non-root crontab on alpine linux?为什么 crond 无法在 alpine linux 上运行非 root crontab?
【发布时间】:2020-04-11 01:29:44
【问题描述】:

我在 Alpine Linux 上运行非根 crontab 文件时遇到了麻烦。

我已经浏览了另外两个与 cron 相关的帖子,但我没有答案:

https://askubuntu.com/questions/23009/why-crontab-scripts-are-not-working

https://serverfault.com/questions/449651/why-is-my-crontab-not-working-and-how-can-i-troubleshoot-it

这是设置。

我的 crontab 看起来像这样:

PATH=/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/sbin:/opt/aws/bin:/home/ec2-user/bin
SHELL=/bin/bash

* * * * * /opt/monitor/monitor.sh >> /var/log/monitor.log 2>&1
0 3 * * * /opt/monitor/monitor-log-clean.sh >> /var/log/monitor.log 2>&1

我的 Dockerfile 现在有点乱,但这只是因为我一直在拼命地试图解决这个问题。它看起来像这样。简而言之,我为 crontab -e 添加了 SUID 以像其他用户一样工作,我创建了我的用户,我导入了我的 crontab 文件,然后我提供了我能想到的所有内容的权限。

FROM alpine:3.5

# DEPENDENCY TO ALLOW USERS TO RUN crontab -e
RUN apk add --update busybox-suid

# I LIKE BASH
RUN apk --no-cache add bash bash-doc
RUN apk --no-cache add util-linux pciutils usbutils coreutils binutils findutils grep

#... lots of custom stuff ...    

# CREATE USER
RUN adduser -S robuser && \
    mkdir -p /home/robuser

# ADD ENTRY POINT
ADD src/entrypoint.sh /home/robuser/entrypoint.sh

# GIVE MY USER ACCESS
RUN mkdir /etc/cron.d
RUN echo "robuser" > /etc/cron.allow
RUN echo "" >> /etc/cron.allow
RUN chmod -R 644 /etc/cron.d

# ADD MY CRONTAB
RUN mkdir -p /var/spool/cron/crontabs
ADD ./src/crontab.conf /tmp/cloudwatch/crontab.conf
RUN crontab -u robuser /tmp/cloudwatch/crontab.conf

# DEBUG... GIVE MY USER ACCESS TO EVERYTHING
RUN chown -R robuser /etc/cron.d
RUN chmod -R 755 /etc/cron.d
RUN chown -R robuser /var/spool/cron
RUN chmod -R 744 /var/spool/cron
RUN chown robuser /var/spool/cron/crontabs
RUN chmod 744 /var/spool/cron/crontabs
RUN chown -R robuser /etc/crontabs
RUN chmod -R 744 /etc/crontabs
RUN chown robuser /etc/crontabs/robuser
RUN chmod -R 744 /etc/crontabs/robuser
RUN chmod 600 /var/spool/cron/crontabs/robuser

# ADD MY MONITORING PROGRAM
RUN mkdir -p /opt/monitor
ADD src/monitor /opt/monitor
RUN mkdir -p /opt/monitor/.tmp && \
    chown -R robuser /opt/monitor && \
    chmod -R 700 /opt/monitor

RUN touch /var/log/entrypoint.log && \
    touch /var/log/monitor.log && \
    touch /var/log/cron.log && \
    touch /var/log/awslogs.log && \
    chown -R robuser /var/log

USER robuser

ENTRYPOINT /home/robuser/entrypoint.sh

同时,我的 entrypoint.sh 中有这个。我将 cron 守护进程作为后台服务启动并详细记录到 cron.log。我也尝试指定 -d 0 以获得更多调试,但并没有真正向输出添加任何内容。

#!/bin/bash

crond -b -l 0 -L /var/log/cron.log

#... lots of other startup stuff ...

重要的一点:如果我不切换到 robuser一切都可以以 root 身份运行

如果我检查 cron.log,它非常空:

crond: crond (busybox 1.25.1) started, log level 0
crond: wakeup dt=45
crond: wakeup dt=60
crond: wakeup dt=60

同时,/var/log/monitor.log 完全为空(参见文章开头的 crontab)。

所以 crond 没有打印任何错误。

我已经尝试了我能想到的一切来调试它。没有错误信息。它只是运行,从不打印。一个好的建议是简单地使用我的 crontab .. 但这也不起作用:

PATH=/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/sbin:/opt/aws/bin:/home/ec2-user/bin
SHELL=/bin/bash

* * * * * touch /tmp/test.txt

我已经尝试搜索其他使用非 root cron 的 alpine 容器,但大多数人不会遇到让他们的 alpine 容器以非 root 运行的麻烦。

有没有人有任何进一步的建议来帮助调试这个?

【问题讨论】:

  • 这是一个开发问题(DevOps)。我正在开发一个 docker 容器,并且该 docker 容器正在使用 Alpine。请在 Stack Overflow 上查看大量其他与 docker 相关的问题:stackoverflow.com/search?q=docker

标签: linux docker cron alpine


【解决方案1】:

cron 本身应该以root 运行,无论您要使用哪个用户来运行作业。

确实,当你运行时:

RUN crontab -u robuser /tmp/cloudwatch/crontab.conf

这将为用户robuser 安装crontab。当cron 从这个特定的crontab 执行作业时,它会自动将用户切换到robuser但是,如果cron 不是以root 运行,则cron 不能像那样切换用户,这就是为什么您需要以root 身份运行cron

所以,要让 cron 在这里工作,您需要从 Dockerfile 中删除此指令:

USER robuser

请注意,一旦您解决了这个问题,您可能不会摆脱困境:如果您使用环境变量将 AWS 凭证传递给您的监控脚本(您似乎在这里使用 AWS),这将不会t 工作,因为cron 将在切换用户之前删除那些。这在很大程度上是cron 中的一项安全功能,以避免环境变量泄漏给非特权用户。

顺便说一句:我写了一个开源的 crontab 运行器 Supercronic,专门为容器用例设计,它解决了这个问题(你可以作为非特权用户运行它就好了)。如果您对常规的cron 感到沮丧,您可以随时试一试。

【讨论】:

  • 很好的答案,谢谢。但是,您删除 USER robuser 的建议意味着我的整个容器将不会作为 robuser 运行。这包括我的 jboss 服务器。正如您所描述的,听起来以 root 身份运行 cron 并以 robuser 身份运行我的 jboss 服务器是不可能的。
  • @user3460784 如果您想使用普通的cron,那么您确实可能无法以非特权用户的身份运行。但是,您可以以特权用户身份运行它,然后使用gosu 以非特权用户身份运行 jboss!
  • 对于仍在与这个主题作斗争的任何其他人,我已经通过安装 sudo 并为 robuser 设置 sudoer 条目,允许他们只运行一个启动 crond 的 shell 脚本,从而获得了预期的结果。我让它通过 sudo 从 nginx 运行 ngnix 作为 nginx 和 crond 作为 root。
【解决方案2】:

将修复程序编码为以非root身份运行crond,基本上crond是在busybox代码库中实现的,它调用函数'change_identity'调用系统调用setgroups(通常需要linux CAP_SETGID功能),以切换作业权限转换为普通用户/组权限,与用户作业相同,因此crond进程必须以root身份运行。

我将修补的 alpine 推送到 docker hub:

geekidea/alpine-cron:3.7
geekidea/alpine-cron:3.8
geekidea/alpine-cron:3.9
geekidea/alpine-cron:3.10

一个示例 dockerfile:

FROM geekidea/alpine-cron:3.10

USER nobody
RUN mkdir /tmp/crontabs \
    && echo 'SHELL=/bin/sh' > /tmp/crontabs/nobody \
    && echo '* * * * * /tmp/nobody.sh' >> /tmp/crontabs/nobody \
    && echo 'echo "$(date) blahblahblah nobody" >> /tmp/nb-cron.log' > /tmp/nobody.sh \
    && chmod 0755 /tmp/nobody.sh \
    && chown -R nobody.nobody /tmp/crontabs/nobody

CMD ["crond", "-c", "/tmp/crontabs", "-l", "0", "-d", "0", "-f"]

查看更多:https://github.com/inter169/systs/blob/master/alpine/crond/README.md

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-11-12
    • 2015-08-01
    • 2013-02-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多