如何修复 NetworkManager-dispatcher 脚本权限被拒绝错误?

如何修复 NetworkManager-dispatcher 脚本权限被拒绝错误?

我有一个完全更新的 RockyLinux 9.2 服务器,其中通过 Systemd 运行几个网络服务。

按照以下说明操作,例如这里这里,我创建了一个 shell 脚本,该脚本会在特定网络接口在线时触发,并systemctl restart在这些服务上运行。这对于在网络中断后重新启动这些服务非常有用。

因此,我创建了/etc/NetworkManager/dispatcher.d/10-restart-network-services.sh以下内容,重新启动zerotier-one服务:

DEVICE=${1}
STATE=${2}

if [ "$DEVICE" = "[interface name]" ]; then
   if [ "$STATE" = "up" ]; then
      /usr/bin/systemctl restart zerotier-one.service
   fi
fi

我将其替换interface name为从中获得的实际接口名称ifconfig

当我通过手动从该网络接口拔下以太网电缆并重新连接或仅通过重新启动来测试脚本时,我在日志中看到以下错误systemctl status NetworkManager-dispatcher

Oct 15 15:26:31 [hostname] nm-dispatcher[2433]: /etc/NetworkManager/dispatcher.d/10-restart-network-services.sh: line 6: /usr/bin/systemctl: Permission denied
Oct 15 15:26:31 [hostname] nm-dispatcher[2353]: req:12 'up' [interface name], "/etc/NetworkManager/dispatcher.d/10-restart-network-services.sh": complete: failed with Script '/etc/NetworkManager/dispatcher.d/10-restart-network-services.sh'  exited with status 126.

看起来我的脚本已成功启动,但systemctl restart命令出现“权限被拒绝”错误。

以下是我迄今为止尝试过的方法:

  1. 使用sudo chmod 700脚本上的权限。
  2. 使用sudo chmod 755脚本上的权限。
  3. 在 shell 脚本中,既有普通systemctl命令,也有其完整路径/usr/bin/systemctl。当脚本只有命令systemctl而没有完整路径时,错误是“命令未找到”,而不是“权限被拒绝”。
  4. 跑步restorecon /etc/NetworkManager/dispatcher.d/10-restart-network-services.sh

他们都没有解决问题。

有什么建议吗?提前谢谢您。

答案1

我遇到了完全相同的问题(使用不同的服务),简而言之,SELinux 阻止 NetworkManager 调度程序脚本重新启动 zerotier-one.service。您需要创建一个新的 SELinux 策略,以允许调度程序 SELinux 文件“类型”访问 zerotier-one 服务“类型”。免责声明:我无法让它工作,所以请谨慎对待我的建议。我是 SELinux 的新手,在解决自己的问题时学到了这一切。

欲了解详细答案,请继续阅读:

您可以通过使用以下命令搜索调度程序 SELinux 错误来确认根本原因:

ausearch -m AVC,USER_AVC,SELINUX_ERR,USER_SELINUX_ERR | grep dispatcher

您还可以将 SELinux 设置为宽容,然后重新启动 NetworkManager 以确认是否允许您的调度程序脚本正常工作。

setenforce 0
getenforce
service NetworkManager restart
setenforce 1
getenforce

SELinux 文件“类型”基本上只是一组允许相互执行操作的文件的 SELinux 标签,假设常规文件权限首先允许它。

您可以运行ll -Z查看文件的 SELinux 上下文,以 _t 结尾的字符串是文件类型描述符,如 etc_t 或 bin_t。

ll -Z /
dr-xr-xr-x.   2 root root system_u:object_r:mnt_t:s0            6 Mar 25  2022 afs
lrwxrwxrwx.   1 root root system_u:object_r:bin_t:s0            7 Mar 25  2022 bin -> usr/bin
dr-xr-xr-x.   5 root root system_u:object_r:boot_t:s0        4096 Mar 23 22:54 boot

SELinux 权限 (MAC) 与与文件关联的典型 rwx 权限 (DAC) 是分开的,并且仅当基本 DAC 权限首先允许用户操作时,才会随后检查 SELinux 权限。

https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/6/html/security-enhanced_linux/sect-security-enhanced_linux-working_with_selinux-selinux_contexts_labeling_files

它旨在防止受感染的进程破坏整个文件系统。使用 SELinux,受感染的进程只能破坏具有相同文件类型的文件,这些文件应该是进程运行所需的任何文件。

https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/9/html-single/using_selinux/index#introduction-to-selinux_getting-started-with-selinux

大多数情况下,您只需要修改 SELinux 策略以允许一种文件类型访问另一种文件类型,但 systemctl 略有不同。让调度程序脚本访问 systemctl 并不理想,因为这样它将控制 systemctl 可以控制的所有内容,也就是您的整个系统。因此,还有另一个名为“service”的 SELinux 类,它允许脚本调用特定的 systemd 服务,在您的情况下是 zerotier-one.service。

我最终找到了一种可以满足我的需求的方法,但我尝试使用 NM 调度程序脚本重新启动 atd.service 来测试您的用例,但不幸的是,我无法让它工作。

有工具 audit2why 和 audit2allow 可以帮助您根据审计日志中的 SELinux 故障编写 SELinux 策略,但人们似乎建议不要使用它们。我注意到他们没有建议像 systemd 那样使用服务类。我确实发现 audit2allow 有助于创建一个基本的 SELinux 策略模板文件,然后我可以对其进行自定义。

我也尝试盲目遵循 audit2allow 的所有自动建议,但每次修改策略后都会出现新的失败,最终 audit2why 工具说“是的,此操作应该按照您当前的策略允许,我不知道该告诉您什么”:

# ausearch -i | awk '/dispatcher/ && /systemctl/' | tail -5 | audit2why
type=AVC msg=audit(03/25/2024 15:29:17.520:748) : avc:  denied  { map } for 
pid=37569 comm=systemctl path=/usr/bin/systemctl dev="dm-0" ino=402765363 
scontext=system_u:system_r:NetworkManager_dispatcher_t:s0 
tcontext=system_u:object_r:systemd_systemctl_exec_t:s0 tclass=file permissive=0

Was caused by:
            Unknown - would be allowed by active policy
            Possible mismatch between this policy and the one under which the audit message was generated.

            Possible mismatch between current in-memory boolean settings vs. permanent ones.

不幸的是,在我放弃之前,我只能做到这些,但我将分享我制定自定义 SELinux 策略的步骤,因为这有点难以理解。希望您能让它工作,如果可以的话,请告诉我您是如何做到的。我正在运行 Almalinux 9.3,它应该与 Rocky Linux 几乎完全相同,因为它们都是 Redhat 的克隆版。

SELinux 自定义策略创建

SELinux 服务策略:https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/selinux_users_and_administrators_guide/chap-security-enhanced_linux-systemd_access_control

一般政策文件:https://selinuxproject.org/page/PolicyStatements

实用指南:https://billauer.co.il/selinux-policy-module-howto.html

根据自动建议创建自定义模块包(这不会改变 SELinux 策略,直到您导入它)

grep dispatcher /var/log/audit/audit.log | tail -5 | audit2allow -M custom_NM_dispatcher_policy

回顾新模块:

cat custom_NM_dispatcher_policy.te

输出:

module custom_NM_dispatcher_policy 1.0;

require {
        type NetworkManager_dispatcher_t;
        type systemd_systemctl_exec_t;
        class file getattr;
}

#============= NetworkManager_dispatcher_t ==============
allow NetworkManager_dispatcher_t systemd_systemctl_exec_t:file getattr;

如您所见,audit2allow 建议我们允许对具有 systemd_systemctl_exec_t 文件类型的文件执行 NetworkManager_dispatcher_t 的 getattr 操作,但这不起作用。在我创建并导入推荐的自定义策略后,它在下一个必需的操作上失败,并且每次我添加下一个推荐操作时都会失败,直到它最终显示“未知”。

那时我做了更多研究,了解到如何使用 :service 类而不是 :file 来处理 systemd 服务。我尽可能地遵循文档,但我的调度程序脚本仍然失败;我不确定为什么。

https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/selinux_users_and_administrators_guide/chap-security-enhanced_linux-systemd_access_control

以下是我修改 audit2allow 生成的文件以尝试允许访问 atd 服务的方法:

找到 atd 服务文件

find / -iname atd.service
/usr/lib/systemd/system/atd.service

获取 SELinux 文件类型(以 _t 结尾)

ll -Z /usr/lib/systemd/system/atd.service
-rw-r--r--. 1 root root system_u:object_r:crond_unit_file_t:s0 274 Oct 14  2022 /usr/lib/systemd/system/atd.service

自定义 policy.te 文件

vim custom_NM_dispatcher_policy.te

module custom_NM_dispatcher_policy 1.0;

# reference pre-defined SELinux types and service actions
require {
        type NetworkManager_dispatcher_t;
        type crond_unit_file_t;
        class service { start }; # the documentation says "restart" action only requires start permissions
}

#============= NetworkManager_dispatcher_t ==============
# Allow NetworkManager dispatcher script to restart atd service
allow NetworkManager_dispatcher_t crond_unit_file_t : service { start };

安装 SElinux 开发工具以获取 Makefile,这是我们构建 .pp 文件所需的。setools-console 提供了 sesearch 等有用工具来搜索当前的 SELinux 策略操作

dnf -y install policycoreutils-devel setools-console

查找 SELinux Makefile(最有可能位于 /usr/share/selinux/devel/Makefile)

find / -iname Makefile

将其链接到当前目录

ln -s /usr/share/selinux/devel/Makefile

将.te 文件构建为二进制.pp 文件(覆盖 audit2allow 生成的.pp 文件)

make custom_NM_dispatcher_policy.pp

Compiling targeted custom_NM_dispatcher_policy module
Creating targeted custom_NM_dispatcher_policy.pp policy package
rm tmp/custom_NM_dispatcher_policy.mod.fc tmp/custom_NM_dispatcher_policy.mod

导入自定义策略模块

semodule -i custom_NM_dispatcher_policy.pp

确认导入成功

semodule -l | grep custom

确认政策行动

sesearch -A -s NetworkManager_dispatcher_t -c service

测试调度程序脚本

systemctl restart NetworkManager

检查服务日志

journalctl -e --unit atd.service

journalctl -e --unit NetworkManager-dispatcher.service

检查 SELinux 故障

ausearch -i | awk '/dispatcher/ && /atd/' | tail -5

根据失败获取建议

ausearch -i | awk '/dispatcher/ && /atd/' | tail -5 | audit2allow

您可以将上述命令中的新建议添加到 custom_NM_dispatcher_policy.te 文件中,然后重复步骤重建 .pp 文件并导入它。这就是我所做的,最终 audit2allow 用完了建议,但 SELinux 仍然阻止了我的脚本。


祝你好运,我希望这能给你一个好的开始!

相关内容