如何允许 apache 在启用 SELinux 的情况下轮换用户主目录中的日志?

Leo*_*lis 3 selinux apache-2.2 log-rotation

我们的开发机器有多个用户,他们的各种站点都存储在/home/username/apache. 在这些文件夹中是子文件夹,例如conf包含虚拟主机配置、logs包含日志、public包含实际 Web 文件等。

我想更改日志,而不是单个日志文件:

CustomLog "/home/user/apache/domain.tld/logs/web.log" combined
Run Code Online (Sandbox Code Playgroud)

我们将日志分成每日日志:

CustomLog "|/usr/sbin/rotatelogs -l /home/user/apache/domain.tld/logs/%Y%m%d_web.log 86400" combined
Run Code Online (Sandbox Code Playgroud)

但是,当我放入此配置时,重新启动 apache,然后重新加载页面,同时拖尾audit.logausearch,我看到如下错误:

----
type=SYSCALL msg=audit(06/06/2014 14:16:51.401:406272) : arch=x86_64 syscall=open success=no exit=-13(Permission denied) a0=7fff70a92460 a1=80441 a2=1b6 a3=7fff70a92110 items=0 ppid=64542 pid=64617 auid=root uid=root gid=root euid=root suid=root fsuid=root egid=root sgid=root fsgid=root tty=(none) ses=1193 comm=rotatelogs exe=/usr/sbin/rotatelogs subj=unconfined_u:system_r:httpd_rotatelogs_t:s0 key=(null)
type=AVC msg=audit(06/06/2014 14:16:51.401:406272) : avc:  denied  { search } for  pid=64617 comm=rotatelogs name=home dev=md2 ino=7208961 scontext=unconfined_u:system_r:httpd_rotatelogs_t:s0 tcontext=system_u:object_r:home_root_t:s0 tclass=dir
Run Code Online (Sandbox Code Playgroud)

我以为我可以通过更改类型来解决这个问题,就像我已经修复了其他 SELinux 问题(例如允许 apache 写入文件)一样,但是在尝试了一些之后,我仍然遇到上述相同的错误。我试过httpd_log_thttpd_rotatelogs_exec_t而且var_log_t无济于事。

我是用chcon命令来做这件事的。

我错过了什么?

bil*_*lyw 12

实际问题

要翻译您提供的日志的第二行:

PID 为 64617的rotatelogs 进程尝试在设备 md2 和 inode 7208961 上的主目录中进行搜索。访问被拒绝。

rotatelogs 进程的安全上下文是:unconfined_u:system_r:httpd_rotatelogs_t:s0

主目录的安全上下文是: system_u:object_r:home_root_t:s0

您需要允许rotatelogs 读取主目录。允许 httpd 这样做很容易 ( setsebool -P httpd_enable_homedirs=1),但不幸的是,rotatelogs 没有从 httpd 继承它的类型。更糟糕的是,rotatelogs 没有 setebool 参数。

这还不是全部!您还需要允许rotatelogs 一直搜索到所需目录,并允许它执行其任务所需的所有操作——包括文件本身和包含它们的目录。

简而言之,您需要编写本地策略。

分步解决方案

在任何地方创建一个类型强制文件,名为homelogs.te,内容如下:

module homelogs 1.0;

require {
        type httpd_rotatelogs_t;
        type home_root_t;
        type user_home_t;
        type user_home_dir_t;
        class dir { add_name getattr open read remove_name search write };
        class file { create getattr open read rename unlink write };
}

#============= httpd_rotatelogs_t =============
allow httpd_rotatelogs_t home_root_t:dir search;
allow httpd_rotatelogs_t user_home_dir_t:dir search;
allow httpd_rotatelogs_t user_home_t:dir { add_name getattr open read remove_name search write };
allow httpd_rotatelogs_t user_home_t:file { create getattr open read rename unlink write };
Run Code Online (Sandbox Code Playgroud)

现在编译它:

make -f /usr/share/selinux/devel/Makefile homelogs.pp

并安装它:

semodule -i homelogs.pp

现在rotatelogs 应该拥有在用户home 的子目录中执行其任务所需的所有权限。


如何编写本地策略

这是为那些想要了解我如何编写本地策略的更多详细信息的人准备的。您有两种选择来编写策略。

审计2允许

如果您完全不熟悉编写本地策略,一种选择是使用包中audit2allow提供的 工具policycoreutils-python来帮助您编写。

要在运行 rotatelogs 时修复 SELinux 权限拒绝,您可以运行以下命令

grep rotatelogs /var/log/audit/audit.log | audit2allow -M homelogs
Run Code Online (Sandbox Code Playgroud)

将包含 'rotatelogs' 的审计日志提供给audit2allow. 该工具将自动分析 SELinux 权限拒绝并创建类型强制文件,以及编译后的策略包 ( .pp) 文件。此时,您可以通过运行以下命令简单地安装创建的策略包:

semodule -i  homelogs.pp
Run Code Online (Sandbox Code Playgroud)

就这样,您已经解决了与rotatelogs 相关的所有SELinux 问题……对吗?

这种方法的问题audit2allow无法预测需要什么权限;它只能分析哪些权限已经被拒绝。

到目前为止,只/home遇到了 home(字面意思)目录中的搜索拒绝,因此audit2allow只能解决这个问题。想想每次遇到下一个被拒绝的权限时,您必须重新运行该工具多少次。并且根据rotatelogs 配置,拒绝和记录特定权限可能需要数周时间。例如,rotatelogs 尝试删除旧日志文件并遇到取消链接权限拒绝需要多长时间?

Michael Hampton 在评论中指出,可以通过将 SELinux 更改为 Permissive Mode 来缓解此问题:

setenforce 0
Run Code Online (Sandbox Code Playgroud)

在这种模式下,SELinux 会发出警告并记录操作,但不会强制执行该策略。这允许rotatelogs 执行其所有任务,而SELinux 仍然记录所有权限拒绝。然后可以audit2allow在审计日志上运行,安装自动创建的策略,setenforce 1返回到强制模式,然后完成。

之前不知道 Permissiive 模式可以这样使用,我手动编写了本地策略,如下所述。没有必要手工完成,但希望阅读具有一定的教育意义。

手动创建

对 Type Enforcement 文件有一定的了解后,您可以通过手写来解决权限问题。我创建了一个类型强制文件(带有.te扩展名)。类型强制文件在哪里并不重要。

类型强制文件分为三个部分。

模块部分

module homelogs 1.0;
Run Code Online (Sandbox Code Playgroud)

模块部分列出了您将使用本地策略创建的模块的名称和版本。该名称应该是唯一的,否则您将替换已存在的同名模块。您可以使用semodule -l.

要求部分

require {
        type httpd_rotatelogs_t;
        type home_root_t;
        type user_home_t;
        type user_home_dir_t;
        class dir { add_name getattr open read remove_name search write };
        class file { create getattr open read rename unlink write };
}
Run Code Online (Sandbox Code Playgroud)

正如这里提到的:

此 [部分] 通知策略加载器,在安装此模块之前,系统策略中需要哪些类型、类和角色。如果这些字段中的任何一个未定义,semodule 命令将失败。

在您的情况下,rotatelogs 将与多种类型交互。在ls -Zrotatelogs 可执行文件和所需路径的目录上运行后,我发现需要以下类型:

  • httpd_rotatelogs_t
  • home_root_t
  • user_home_t
  • user_home_dir_t

您还需要与一些进行交互。类及其权限的完整列表在这里。对于您的情况,我们将只使用class fileclass dir。您还必须列出您将与之交互的每个类的权限。根据完整列表,我选择需要这些类和权限(一些可能不是必需的,但我在允许方面犯了错误):

班级目录:

  • add_name - 将文件添加到目录
  • getattr- 获取文件的文件属性,例如访问模式。(例如 stat,一些 ioctl。...)
  • open - 打开一个目录
  • read - 读取文件内容
  • remove_name - 从目录中删除文件
  • search - 搜索访问
  • write- 一般写访问;添加或删除所需

类文件:

  • create ——
  • getattr- 获取文件的文件属性,例如访问模式。(例如 stat,一些 ioctl。...)
  • open - 打开文件
  • read - 读取文件内容
  • rename - 重命名文件
  • unlink - 删除硬链接(删除)
  • write - 写入文件

规则部分

allow httpd_rotatelogs_t home_root_t:dir search;
allow httpd_rotatelogs_t user_home_dir_t:dir search;
allow httpd_rotatelogs_t user_home_t:dir { add_name getattr open read remove_name search write };
allow httpd_rotatelogs_t user_home_t:file { create getattr open read rename unlink write };
Run Code Online (Sandbox Code Playgroud)

规则的部分很容易读取。例如:

allow httpd_rotatelogs_t user_home_t:dir { add_name getattr open read remove_name search write };

大致意思是:

允许命令类型httpd_rotatelogs_t执行操作add_name,geattr,开放,阅读,remove_name,搜索,并写上目录与类型为user_home_t。

请注意,每个类都需要一个单独的规则,因为不同的类将具有与之关联的不同权限。

编译安装

这是多余的,但我会再次提及。您需要将类型强制文件编译为策略包。运行时make,Type Enforcement 文件需要位于您当前的工作目录中。

make -f /usr/share/selinux/devel/Makefile homelogs.pp

最后,将策略包安装为模块:

semodule -i homelogs.pp


编写自定义策略的有用资源:

  • 好的。但是您不知道将 SELinux 设置为许可模式然后立即收集所有拒绝吗? (2认同)