为什么 selinux 策略适用于从 cronjobs 运行的命令(例如:logrotate),但不适用于直接从命令行运行的命令?
当我从命令行手动运行 logrotate 时,它工作得很好。但是当它从 cronjob 运行时,我在audit.log 中收到一个错误,提醒我 selinux 阻止访问 www 等。
这是为什么?我怎样才能模拟它从 cronjob 运行来测试?
答案1
当cron
运行时logrotate
,SELinux 将其限制为 logrotate_t“类型”。该“类型”被限制不能修改其他文件类型(也称为“逃脱限制”)。
什么时候你运行 logrotate,您(很可能)从“无限制”类型开始,这意味着它所说的 -logrotate
允许进程修改文件。您可能还想logrotate
重新启动或向进程发送信号(例如,通过 postrotate);该活动也可能受到 SELinux 的限制。
我的建议是告诉 SELinux 允许(“允许”) logrotate_t 类型逃脱限制,方法是:
semanage permissive -a logrotate_t
这样做是一个温和的解决方案,介于两者之间关闭 SELinux并微调策略,以准确地允许您需要的限制逃脱(也许使用自定义标签)。要恢复此更改,请使用semanage permissive -d logrotate_t
.
模拟 cron 启动进程的最佳方法是将作业放入 cron 中。另外,我知道runcon
,虽然我没能成功使用它。
答案2
只是在@JeffSchaller 的好答案的基础上添加关于具体问题的内容:
我怎样才能模拟它从 cronjob 运行来测试?
我可以分享一个可行的替代方案,无需从 cronjob 运行测试命令。
首先,可能值得一提的是一个微妙的细节:
在传统的非 SELinux 环境中,当您以 root 身份(有效 UID = 0)操作时,您通常可以自由切换到您喜欢的任何其他 UID,以“获得”该 UID 的限制。
这与 SELinux 的上下文完全不同:成为 root(有效 UID = 0)通常确实会将您置于“不受限制”的上下文中,但不会自动允许您自由切换到其他上下文。您更需要一个明确的 SELinux 策略规则来授予“无限制”上下文执行特定“转换”操作的许可。安装此类规则后,该runcon
命令将成功将您置于该上下文中。
实际上,对于您的情况,您可能需要一个 SELinux 策略,例如简单的:
allow unconfined_t crond_t:process transition;
(假设是您的 守护进程运行的crond_t
SELinux 域)crond
完整模块的编译和安装规则是:
module unconfined-trans-crond 1.0;
require {
type unconfined_t;
type crond_t;
class process transition;
}
allow unconfined_t crond_t:process transition;
编译并安装该模块后,可以使用runcon
目标crond_t
域unconfined_t
。例如:
# id
uid=0(root) gid=0(root) groups=0(root) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
# runcon $(ps -q $(pgrep crond) -o context --no-header) sh
# id
uid=0(root) gid=0(root) groups=0(root) context=system_u:system_r:crond_t:s0
#
另请注意,您不需要 UID 0 即可使用runcon
,您“只”需要允许从当前 SELinux 上下文转换到目标 SELinux 上下文的正确策略规则。
事实上,我通常以 root 身份运行来测试守护进程(例如crond
)的完整命令是:
runuser $(ps -q $(pgrep crond) -o user --no-header) -c 'runcon $(ps -q $(pgrep crond) -o context --no-header) /bin/bash'
crond
它提供了一个以的用户及其 SELinux 上下文运行的 shell 。
要在完成测试后撤消该策略,只需删除自定义模块即可。
这当然没有考虑到可能的其他限制,例如不同的命名空间视图、资源限制 (ulimits)、cgroup 或 Linux 功能。这些将需要按顺序运行其他命令才能重新创建这些附加限制,除非 PAM 配置runuser
在某种程度上与为您重新创建它们时保持一致。
华泰
答案3
受到 @Jeff_Schaller 和 @LL3 的答案的启发,以下是为此过程提出正确的 sepolicy 模块的方法:
:; sudo semanage permissive -a logrotate_t
# turn off selinux for logrotate temporarily to allow the logrotate command to go through, while still logging the denied messages in audit.log
:; sudo runcon -u system_u -r system_r -t logrotate_t logrotate -f /etc/logrotate.conf
:; sudo semanage permissive -d logrotate_t # re-enable selinux
:; sudo grep denied /var/log/audit/audit.log | audit2allow -M logrotate
# create a selinux policy based on the denied messages
:; sudo semodule -i logrotate.pp
的内容logrotate.te
最终看起来像这样
module logrotate 1.0;
require {
type initrc_exec_t;
type default_t;
type policykit_t;
type logrotate_t;
class dbus send_msg;
class file { create getattr ioctl open read setattr unlink write };
class dir { add_name read remove_name write };
class service reload;
}
#============= logrotate_t ==============
allow logrotate_t default_t:dir { add_name read remove_name write };
#!!!! WARNING: 'default_t' is a base type.
allow logrotate_t default_t:file { create getattr ioctl open read setattr unlink write };
allow logrotate_t initrc_exec_t:service reload;
allow logrotate_t policykit_t:dbus send_msg;
答案4
我对 SElinux 没有深入的了解,我不确定它是否与其他答案相同。这是我的做法:在目录内。 crontab 的 semanage fcontext -a -t 'myCronTab' logrotate_exec_t
这使得 cronjob 和 处于logrotate
相同的上下文中,因此它应该就像是通过命令行执行的。