技术摘要| 从自主到强制——浅谈Linux 强制访问控制 AppArmor

2020-05-22 coding AppArmor linux

AppArmor 是 Linux 系统中提供的强制访问控制 (MAC) 的安全控件,能够为我们的服务器提供更多的安全保障。但凡提起强制访问控制,我就会想起《计算器安全》这门课上学到的一堆枯燥的名词、概念和模型。仿佛强制访问控制离我们太远,很无趣,也没什么用。且慢,不妨让我们从 Linux 原生的访问控制说起。

Linux 权限是不完备的?

Linux 系统原生控制机制(DAC) 相比大家都已经了解了。自主访问控制最大的特点就是由文件所有者来对文件进行访问控制。文件所有者可以对文件的权限进行设置,比如 Linux 系统下,就将一个文件的权限设置为 属主权限 (u)属组权限 (g) 以及其他人权限 (o) 三类来进行控制。当一个进程要读写一个文件的时候, Linux 内核就要充当看门老大爷的角色,判断这个进程是否有读写的权限。如果进程的有效所有者文件所有者相同,则根据属主权限 (u)进行判断;如果有效用户组文件属组相同,则根据属组权限(g)进行判断;否则根据其他人权限(o)进行判断。

就好比张三和李四是同一间寝室的同学。张三有张三柜子的钥匙,他可以对柜子里的东西进行处置(属主权限)。张三和李四都拥有寝室的钥匙(张三和李四都属于同一个用户组)。但是隔壁寝室的老王却没有办法进入张三的寝室,也没有办法大概张三的柜子。这时候一切都很美好、很和谐。但是有一天,张三想把柜子里的大宝贝分享给隔壁寝室的老王。他应该怎么做呢?

  1. 修改柜子的属者,把柜子交给老王?不行,这个柜子还是张三的,他可不想随便把柜子里的大宝贝送给别人。
  2. 将老王加入到寝室的用户组里?不行,李四不愿意把钥匙交给隔壁老王。
  3. 修改柜子的其他人权限?不错,老王是能够访问柜子了,可是隔壁的隔壁的老陈也能偷瞟柜子里的大宝贝了。

张三没有办法,他只能再新建一个用户组(比如叫做“大宝贝分享组”),然后把老王添加到这个组中,然后再修改柜子的用户组为“大宝贝分享组”。很麻烦,对吧? 其实还有一个困难。就是张三根本就没有办法使用 groupadd 命令,这一个命令是管理员命令,只能由班长来使用,可惜张三他并不是班长。因此这个办法也不能行得通。上面说了这么多,其实只是想吐槽一下 Linux 自主访问控制的设计是不完备的,不能满足很多需求。

Windows NT 内核下的权限设计就要完备得多。Windows 下的文件权限控制不再分为属主、属组和其他人三类,而是可以为系统中的每一个用户、每一个用户组单独的分配权限。这些权限构成了一个叫做 ACL 的访问控制列表。

从自主访问控制到强制访问控制

上面这个所说的这个问题其实对于普通用户来说,或许还并不关键。但是对于 root 用户来说,却变成了一个非常致命的问题。root 用户经常要下方一些权限给特定的用户或者特定用户组,这些操作往往是非常复杂且 dirty 的,最关键的是稍有不慎就可能导致严重的安全问题。

Linux 内核后续强制访问控制模块,强制访问控制就是集中式的控制每一个进程的能力(比如能访问哪些文件、拥有哪些权限、可以监听什么网络地址等等)。这时候对于进程的限制不再是由文件所有者进行控制了,而是直接由系统管理员进行控制,也可以进行更加精细的设计

最早的 Linux 强制访问控制是 SeLinux 模块,想必各位 Centos 管理员都听说过。这个模块配置太复杂了,因此很多人上手的第一件事就是关闭这个模块。在 Debian/Ubuntu 下,使用 AppArmor 更为原生、更加简单易用。虽然没有 SeLinux 那么强,但是也能提供不错的安全防护。

另一个不使用 SeLinux 的原因是很多人认为美国国家安全局 NSA 主导的 SeLinux 不靠谱,可能有·后门。

安装 AppArmor

其实安装起来很简单,在很早的 Debian 和 Ubuntu 发行版内核中,就自带了 AppArmor 模块。因此只需要使用 apt 安装用户空间的命令组件即可。apparmor-utils 是一组用户空间的命令行实用工具,可以帮助我们很好的管理 AppArmor 。后两者是一些预先配置的配置文件,这些配置文件一般来说是比较完善的,但是也需要根据实际需要进行修改

apt install apparmor-utils apparmor-profiles apparmor-profiles-extra

之后使用命令 aa-enabled 可以查看 AppArmor 是否开启,也可以使用 aa-status 来查看 AppArmor 的运行状态(包括了加载的配置以及受控制的进程)。

aa-enabled
> Yes

AppArmor 通过配置文件来管理各个程序的权限。配置文件的文件名通常是其控制的程序的完整路径名(比如 /etc/apparmor.d/usr.sbin.nginx 是控制 Nginx 的配置文件) 。生效的配置文件的位置是 /etc/apparmor.d,而提供的一些可选配置文件夹位于 /usr/share/apparmor/profiles 里。可以通过软连接的方法,将这些配置连接到 /etc/apparmor.d,从而启用配置。

ln -s /usr/share/apparmor/extra-profiles/usr.sbin.sshd /etc/apparmor.d

使用 AppArmor

在 AppArmor 中,每一个配置文件都有三种状态:enforce、complain 以及 disable。分别使用 aa-enforce <程序名>, aa-complain <程序名> 以及 aa-disable <程序名> 来切换对应程序的配置文件。

  • enforce: 强制模式,这种模式下,所有没有被授权的行为都会被禁止并且记录。
  • complain: 抱怨模式,此时未授权行为会被放行,但是也会被记录。
  • disable: 此时对应配置文件不加载,没有对程序行为进行限制。

下面我们来看一个典型的配置文件 /etc/apparmor.d/usr.sbin.nginx

# Last Modified: Thu May 21 22:05:25 2020
#include <tunables/global>

/usr/sbin/nginx {
  #include <abstractions/apache2-common>
  #include <abstractions/base>

  capability dac_override,
  capability setgid,
  capability setuid,

  deny /srv/private/** rw,
  /etc/nginx/** r,
  /srv/www/** r,
  /var/lib/nginx/ rw,
  /var/log/nginx/* w,
  /var/www/html r,
  /etc/group r,
  /etc/nginx/cert.d/* r,
  /etc/nginx/conf.d/* r,
  /etc/nsswitch.conf r,
  /etc/passwd r,
  /etc/ssl/openssl.cnf r,
  /run/nginx.pid rw,
  /usr/lib/nginx/** m,
  /usr/share/nginx/modules-available/* r,
  /var/lib/nginx/** rw,
}

其实配置文件还是比较容易读懂的,每一个 block 里面都是其对应的一条权限。

  • #include 指令可以用于包含其他的配置文件和预先定义规则,便于实现规则的架构化。
  • capability 指令可以用于授权一系列特殊权限,比如在这个例子里就授权了 dac_override (修改DAC 列表) suid 和 guid 权限。
  • network 指令可以对于网络的报文和地址绑定进行限制。(比如 network raw)
  • 还可以对于文件系统进行限制。可以写出文件系统中文件和目录的读写权限。规则是 [audit] [deny] filename rights,也就是是否开启审计、禁止、文件名以及对应的权限。有下面这些说明:
    1. audit 表示开启审计
    2. deny 表示对匹配该条规则的行为直接禁止
    3. filename 可以使用 * 和 ** 通配符, * 表示目录下的所有文件,而 ** 则进行了递归。
    4. filename 还可以使用如下一些预先定义的变量,比如 @{HOME} 和 @{PROC} 等
    5. AppArmor 对读写权限进行了进一步细化,包括了: ‘r’ (r), ‘w’ (write), ’m' (memory map as executable), ‘k’ (file locking), and ‘l’ (creation hard links) 等等。

一些最佳实践

1. 如何配置符合自己需求的配置文件呢?(个人感觉非常有用

首先使用 aa-autodep <程序名,比如 nginx> 来生成一个初始化的配置文件。这个文件目前没有任何规则。

第二步,使用 aa-complain <程序名> 来将这个配置文件启动抱怨模式,这时候会记录所有需要授权的行为。

第三步,过一段时间后,使用 aa-logprof。这一步非常关键,这个命令会读取日志中所有操作,然后逐条询问之后是否允许这样的操作。(A 运行,D 不允许, I 忽略,G 改用通配符,N 修改规则)。然后把你的要求写入到对应的配置文件中去,从而形成了符合你需求的配置文件。

第四步,根据你的预期可以直接修改规则配置文件。

第五步,测试一段时间且规则没有问题后,可以使用 aa-enforce <程序名> 开启 enforce 模式。

2. 如何查询未受控的进程(unconfined)?

当 AppArmor 启动后,先前启动的进程则处于未受控 unconfined 状态。可以使用命令 aa-unconfined 来查询当前处于未受控的进程。然后重启这些进程,这样这些进程再次启动后即可受到 AppArmor 的控制。

3. 如何配置桌面审计通知?(摘抄自 Debian Wiki)

发生策略违规时,apparmor-notify 软件包可以使用 aa-notify 程序发送桌面通知,该程序您登录时自动启动。

  • 如果软件包 auditd 没有安装, 则桌面用户应该作为 adm Group 组的成员。
  • 如果软件包 auditd 已经安装 ,则应将 /etc/xdg/autostart/apparmor-notify.desktop 修改为 Exec=sudo aa-notify -p -f /var/log/audit/audit.log

4. 其他指导和参考文献

Debian Wiki

Ubuntu Wiki

ArchLinux Wiki

本人保留对侵权者及其全家发动因果律武器的权利

版权提醒

如无特殊申明,本站所有文章均是本人原创。转载请务必附上原文链接:https://www.laytonchen.com/post/tech/apparmor/

如有其它需要,请邮件联系!版权所有,违者必究!