我们的开发机器有多个用户,他们的各种站点都存储在 中/home/username/apache
。这些文件夹中有子文件夹,如conf
包含虚拟主机配置、logs
包含日志、public
包含实际的 Web 文件等。
我想更改日志,以便不再使用单个日志文件:
CustomLog "/home/user/apache/domain.tld/logs/web.log" combined
我们将日志分为每日日志:
CustomLog "|/usr/sbin/rotatelogs -l /home/user/apache/domain.tld/logs/%Y%m%d_web.log 86400" combined
但是,当我输入此配置、重新启动 apache、然后重新加载页面并在尾随时audit.log
,ausearch
我看到如下错误:
----
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
我以为我可以通过更改类型来修复此问题,就像修复其他 SELinux 问题(例如允许 apache 写入文件)一样,但尝试了几次后,仍然出现上述错误。我试过了httpd_log_t
,httpd_rotatelogs_exec_t
但var_log_t
无济于事。
我正在使用chcon
命令执行此操作。
我错过了什么?
答案1
实际问题
翻译您提供的日志的第二行:
这rotatelogs 进程PID 为 64617 的进程尝试在主目录,位于设备 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 没有 setsebool 参数。
这还不是全部!您还需要允许 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 };
现在编译它:
make -f /usr/share/selinux/devel/Makefile homelogs.pp
并安装它:
semodule -i homelogs.pp
现在 rotatelogs 应该具有在用户主目录的子目录中执行其任务所需的所有权限。
如何撰写本地政策
这是为那些想了解我如何制定本地政策的更多细节的人准备的。你有两种选择来制定政策。
audit2allow
如果您对编写本地策略完全陌生,那么一种选择是使用 包audit2allow
中提供的工具policycoreutils-python
来帮助您编写策略。
要修复运行 rotatelogs 时 SELinux 权限拒绝的问题,你可以运行以下命令
grep rotatelogs /var/log/audit/audit.log | audit2allow -M homelogs
将包含“rotatelogs”的审计日志输入到audit2allow
。该工具将自动分析 SELinux 权限拒绝并创建类型强制文件以及编译的策略包 ( .pp
) 文件。此时,您只需运行以下命令即可安装创建的策略包:
semodule -i homelogs.pp
就这样,您就修复了所有与 rotatelogs 相关的 SELinux 问题……对吗?
这种方法的问题是audit2allow
无法预测需要什么权限;它只能分析哪些权限已经被拒绝。
到目前为止,只/home
遇到了主目录(字面意思为 )中的搜索拒绝,因此audit2allow
只能修复该问题。想想每次遇到下一个被拒绝的权限时,您将需要重新运行该工具多少次。并且根据 rotatelogs 配置,拒绝和记录特定权限可能需要数周时间。例如,rotatelogs 尝试删除旧日志文件并遇到取消链接权限拒绝需要多长时间?
Michael Hampton 在评论中指出,可以通过将 SELinux 更改为 Permissive 模式来缓解此问题:
setenforce 0
在此模式下,SELinux 将发出警告并记录操作,但不强制执行策略。这允许 rotatelogs 执行其所有任务,而 SELinux 仍会记录所有权限拒绝。然后,可以audit2allow
在审计日志上运行,安装自动创建的策略,setenforce 1
返回到强制模式,然后完成。
由于之前不知道可以这样使用 Permissiive 模式,我手动编写了本地策略,如下所述。不需要手动编写,但希望阅读后能有所启发。
手动创建
了解了 Type Enforcement 文件后,您可以通过手动编写来解决权限问题,防患于未然。我创建了一个 Type Enforcement 文件(带有扩展名.te
)。Type Enforcement 文件位于何处并不重要。
类型执行文件有三个部分。
模块部分
module homelogs 1.0;
模块部分列出了您将使用本地策略创建的模块的名称和版本。名称应该是唯一的,否则您将替换同名的现有模块。您可以使用 检查已安装模块的名称semodule -l
。
require 部分
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 };
}
如上所述这里:
此 [部分] 告知策略加载器在安装此模块之前系统策略中需要哪些类型、类和角色。如果任何这些字段未定义,semodule 命令将失败。
在你的情况下,rotatelogs将与几个类型。在 rotatelogs 可执行文件和所需路径的目录上运行后ls -Z
,我发现需要以下类型:
httpd_rotatelogs_t
home_root_t
user_home_t
user_home_dir_t
你还需要与一些类. 完整的类别及其权限列表如下这里。对于您的情况,我们将只与class file
和合作class 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 };
这规则部分读起来相当容易。例如:
allow httpd_rotatelogs_t user_home_t:dir { add_name getattr open read remove_name search write };
大致意思是:
允许命令使用 httpd_rotatelogs_t 类型来执行运营add_name、geattr、open、read、remove_name、search 和 write 的目录类型为 user_home_t。
请注意,每个类别都需要单独的规则,因为不同的类别具有与之相关的不同权限。
编译和安装
这是多余的,但我还是要再提一下。您需要将 Type Enforcement 文件编译成 Policy Package。运行时make
,Type Enforcement 文件需要位于您当前的工作目录中。
make -f /usr/share/selinux/devel/Makefile homelogs.pp
最后,将策略包作为模块安装:
semodule -i homelogs.pp
编写自定义策略的有用资源:
答案2
无法在上面的优秀答案中添加评论,所以我必须添加一个新的“答案”:
如果由于缺少文件而无法编译新创建的模块/usr/share/selinux/devel/Makefile
,请确保安装该selinux-policy-devel
软件包:
yum install selinux-policy-devel
现在该文件将存在并且您可以继续其余的操作。