我有一个 Ansible 剧本,其中一个任务添加了 SELinux 文件上下文,并且以下任务应该使用该新上下文 - 即,如有必要,修复目录的文件上下文。
当我运行剧本时,看起来第二个任务仍然使用旧的文件上下文策略。这意味着它没有按预期修复目录的上下文。仅在我第二次运行播放后,上下文才被修复。
第一次运行的输出示例:
TASK [web : add file contexts] ****
# Addition to semanage file context mappings
+/srv/fubar(/.*)? a system_u:object_r:httpd_sys_content_t:s0
changed: [example.org]
TASK [create webroot] **********
--- before
+++ after
@@ -1,7 +1,7 @@
{
"path": "/srv/fubar",
"secontext": [
- "unconfined_u",
+ "system_u",
"object_r",
"var_t",
"s0"
changed: [example.org]
而立即重新执行剧本会产生:
TASK [web : add file contexts] ****
ok: [example.org]
TASK [create webroot] *******
--- before
+++ after
@@ -3,7 +3,7 @@
"secontext": [
"system_u",
"object_r",
- "var_t",
+ "httpd_sys_content_t",
"s0"
]
}
changed: [example.org]
正如预期的那样,进一步的执行不会产生任何变化。
Ansible 任务如下所示:
- name: add file contexts
sefcontext:
target: '/srv/fubar(/.*)?'
setype: httpd_sys_content_t
state: present
- name: create webroot
file:
state: directory
dest: /srv/fubar
owner: juser
group: juser
mode: '0755'
setype: _default
seuser: _default
我在这里缺少什么?
一般来说,更新 SELinux 文件上下文时是否存在一些竞争条件?
在查看日志文件时,有一些 SELinux 消息表明该策略已重新加载 - 但就在执行下一个任务之前。这也匹配sefcontext
模块文档其中指出默认情况下启用 SELinux 策略重新加载。
答案1
这实际上取决于 Ansible 的调用方式。
即使使用 SSH 多路复用(默认启用)和 SSH 管道(通常推荐),Ansible(自 2.9.11 起)也会重新登录并在新的 Python 进程中运行每个任务。
在该环境中,添加的文件上下文在文件任务中立即可见。
但是,当您使用以下命令运行剧本时Mitogen 连接插件启用后,连续任务将在同一个 Python 进程中执行。然后文件上下文更改实际上在进程级别进行缓存。
它被缓存是因为 Ansible 调用selinux.matchpathcon()
(in selinux_default_context()
, module_utils/basic.py
) 来获取默认文件上下文。事实证明,它matchpathcon()
已被弃用,并在第一次调用时在内部缓存所有文件上下文。一个可能的修复方法是让sefcontext
模块调用selinux.matchpathcon_fini()
在调用策略重新加载后。
这种情况发生在有丝分裂原连接插件,因为它非常擅长重用 ssh 连接和 python 进程。这是一件好事,因为这极大地加快了剧本的执行速度。
也可以看看
Puppet 中的类似问题- 由于 Puppet 作为代理运行 - 所有任务始终在同一进程中运行 -matchpathcon()
当系统的 SELinux 策略中的文件上下文发生更改时,Puppet 还使用 API,而不刷新其缓存。