理解 Linux 安全模块:SELinux、AppArmor 与 Landlock 的工程权衡

为什么你需要关心 LSM 而不仅仅是防火墙

很多团队在加固 Linux 系统时,第一反应是配置 iptables 或 firewalld。这确实能拦住网络层面的攻击,但如果攻击者已经通过某个漏洞拿到了一个普通 shell,或者一个容器应用因为漏洞开始尝试读写宿主机文件,传统的网络防火墙就无能为力了。这时,内核层面的访问控制就成了最后一道,也是至关重要的一道防线。

理解 Linux 安全模块:SELinux、AppArmor 与 Landlock 的工程权衡

Linux 安全模块(LSM)不是一个具体的工具,而是一个内核框架。它允许不同的安全模块“挂”在内核的关键操作路径上(比如打开文件、创建进程、绑定网络端口),在操作真正执行前进行安全检查。关键在于,这个框架支持多个模块叠加生效。这意味着你可以在一个系统上同时启用 SELinux 和 Landlock,让它们各司其职,共同构建纵深防御。

核心机制:LSM 如何实现多模块协同

理解叠加的前提是理解 LSM 的钩子(hook)机制。内核在执行敏感操作前,会遍历一个为该操作注册的模块链表。每个模块按顺序检查,只有所有模块都放行,操作才能继续。

以检查一个进程是否有权限读取某个文件(inode)为例,内核的检查链可能是这样的:

基础权限检查 (DAC) → capability 模块 → SELinux 模块 → AppArmor 模块 → Landlock 模块

这里有几个工程细节需要注意:

  • capability 模块是特殊的“基石”:它本质上是 POSIX Capabilities 的 LSM 实现,负责将 root 超级权限拆分成细粒度的能力(如 CAP_NET_BIND_SERVICE)。它总是第一个被调用,完成基础的权限划分。
  • 模块独立决策:每个模块基于自己的策略库做判断。SELinux 看的是文件的安全上下文标签,AppArmor 看的是进程名和文件路径,Landlock 看的是进程自己创建的规则集。它们互不知晓,也互不冲突。
  • 一票否决:链表中任何一个模块返回“拒绝”,整个操作就会被拒绝。这确保了安全策略的严格性。

三大模块的深度对比与选型逻辑

下面这个表格概括了 SELinux、AppArmor 和 Landlock 的核心差异,但表格背后是更复杂的工程取舍。

特性维度 SELinux AppArmor Landlock
策略模型 基于类型强制(TE)和角色访问控制(RBAC),依赖文件、进程、端口等的安全上下文标签。 基于路径的访问控制规则,配置文件与具体的应用程序绑定。 基于规则集的进程沙箱,规则由进程自身在运行时创建并应用。
管控粒度 极细,可控制到单个系统调用、网络端口、IPC对象。 较细,主要控制文件读写、执行、网络访问等。 聚焦于文件系统操作(读、写、执行、创建、重命名等)。
策略复杂度 非常高。需要理解策略语言,配置不当易导致服务崩溃。 中等。使用类自然语言的语法,学习曲线相对平缓。 低。使用简单的 API 和规则描述符,对开发者友好。
管理方式 全局集中式策略,修改后需重新加载标签或整个策略。 每个应用一个配置文件,可以单独加载、卸载。 每个进程(或进程树)一个规则集,在进程内动态管理。
典型应用场景 对安全性有强制合规要求的服务器、军事/金融系统。 桌面应用、服务器守护进程、容器化环境(如 Docker 默认支持)。 软件沙箱、不可信代码执行、提权后的权限收缩。
性能开销 较高(标签查询、策略匹配)。 较低(路径字符串匹配)。 极低(进程本地规则位图检查)。

SELinux:强安全但高维护成本的“重武器”

如果你管理的是一套需要满足严格安全等级(如等保四级)的认证服务器,要求“该服务只能访问特定端口的特定套接字,禁止 Fork 子进程,并且不能加载任何未签名的内核模块”,那么 SELinux 几乎是唯一选择。它的策略表达能力最强。

但麻烦也在这里。我曾见过一个团队为了一个自研的 Go 服务能正常写日志,花了三天时间调试 SELinux 的 AVC(访问向量缓存)拒绝日志,最终写了一个复杂的 .te 策略文件。这种经历让很多运维团队对 SELinux 望而却步,直接将其设置为 Permissive 模式,这等于放弃了它的强制保护能力。

AppArmor:以应用为中心的实用主义路径控制

AppArmor 的哲学更贴近运维直觉:限制“某个程序”能访问“哪些路径”。它的配置文件看起来像这样:

# /etc/apparmor.d/usr.bin.nginx
/usr/sbin/nginx {
  /etc/nginx/** r,
  /var/log/nginx/** rw,
  /var/run/nginx.pid w,
  deny /etc/shadow r,
  network tcp,
}

这种基于路径的模型,在容器时代获得了新生。Docker 等运行时可以自动为容器生成并加载一个基础的 AppArmor 配置文件,限制容器突破命名空间访问宿主机敏感路径。对于大多数业务场景,特别是微服务和容器部署,AppArmor 在安全收益和运维成本之间取得了很好的平衡。

它的一个潜在限制是,对于大量使用硬链接或复杂挂载命名空间的环境,纯路径匹配可能会遇到边界情况。

Landlock:无特权的进程自我约束沙箱

Landlock 代表了另一种思路:让进程自己限制自己。它不需要 root 权限,任何进程都可以为自己创建一个 Landlock 规则集,然后将其应用到自身及其未来子进程上。这个特性让它非常适合用于构建沙箱。

想象一个场景:你的 CI/CD 流水线需要执行用户提交的、未经验证的脚本。传统的做法是放在一个独立的容器或虚拟机里,但这仍有重量级隔离的开销。使用 Landlock,你可以在启动脚本解释器(如 Python)前,先创建一个规则集,规定它只能读取特定的输入目录,只能写入特定的输出目录,然后立即应用。这样,即使脚本存在恶意代码,其破坏也被限制在沙箱范围内。

Landlock 的规则是层次化的,可以叠加限制,但一旦应用,在当前进程命名空间内就无法移除,只能增加更多限制,这符合权限最小化原则。

现实场景中的组合与落地建议

在实际工程中,很少会只选一个。更常见的模式是组合使用:

  • 服务器环境:启用 SELinux 提供基础的系统级强制保护,同时为关键业务进程(如 Nginx、MySQL)定制 AppArmor 策略作为第二层防护。对于内部运行的临时任务脚本,可以考虑用 Landlock 进行约束。
  • 容器环境:宿主机层面可能使用 SELinux(如 OpenShift)或 AppArmor。在容器内部,对于需要执行用户代码的应用(如函数计算 FaaS),可以在启动用户代码时通过 Landlock 施加一层额外的、容器内的文件系统限制。
  • 桌面或嵌入式环境:AppArmor 因其易用性通常是首选,用于限制浏览器、邮件客户端等用户应用。对于从网络下载并运行的软件,可以探索用 Landlock 包装。

落地时绕不开的坑

在引入任何 LSM 时,都要避免几个典型误区:

  1. 不要在生产环境直接设为 Enforcing:务必先设置为 Permissive 或 Complain 模式,运行足够长时间,收集所有的策略拒绝日志,分析并调整策略,确认业务正常后再切换。
  2. 策略不要硬编码路径或 PID:特别是在容器动态调度的环境中,硬编码会失效。应使用通配符或通过安全上下文标签来识别对象。
  3. 善用审计日志auditd 或系统日志是排障的生命线。需要熟悉如何查看 SELinux 的 AVC 日志、AppArmor 的拒绝消息。
  4. 理解能力(Capability)的优先级:记住,Capability 检查在所有 LSM 模块之前。如果一个进程因为缺少某个 Capability 被拒绝,后面的 SELinux 策略再允许也没用。调整权限时需要从上到下通盘考虑。

总结:没有银弹,只有权衡

SELinux、AppArmor 和 Landlock 并非互相替代的关系,而是在 LSM 统一框架下,针对不同安全模型和运维成本的三种解决方案。选择哪一个,取决于你需要对抗的威胁模型、团队的技能储备以及系统的具体架构。

对于追求极致安全可控、且有专业团队支撑的环境,SELinux 是基石。对于追求快速落地、平衡安全与效率的云原生和业务系统,AppArmor 是务实的选择。而对于需要在应用程序内部实现精细、动态沙箱的开发者,Landlock 提供了前所未有的轻量级原生能力。更重要的是,Linux 内核允许它们协同工作,这让我们能够为复杂的现代系统设计出更坚固、更灵活的安全防线。

原创文章,作者:,如若转载,请注明出处:https://fudengji.cn/article/145/

(0)
上一篇 2026年7月31日 上午12:44
下一篇 2026年7月31日 上午12:47

相关推荐