在 Security-Enhanced Linux (SELinux) 中实现的安全策略是位于基于角色的访问控制 (RBAC) 层之下的类型增强 (TE)(SELinux 还将垂直实现多层安全性 (MLS),这超出了本文的讨论范围)。TE 最为常见,也因而最为人熟知,由于服务器实施细粒度权限:当由于意外的访问拒绝而引起中断时,TE 最有可能对此负责。在 TE 中,进程的安全域(对系统的影响域)是由任务的历史记录和当前执行的程序确定。
RBAC 的概念并不像 TE 一样经常讨论,并且由于与 TE 集成在一起,因此十分容易混淆。一般情况下,可以将 RBAC 视为指定某些角色下的用户接收的访问。但是,SELinux 将按照 TE 指定基于角色的访问,因此 RBAC 在 SELinux 中的目的在于允许根据授权用户可能采用的角色管理权限,然后通过指定用于把角色与有效上下文绑定在一起的 TE 域来限定角色可以进入的影响域。
要了解上述原理如何工作,请查看使用 SELinux 提供安全保障的一个非常简单的收银机结算系统。您将在两个截然不同的环境中查看同一个解决方案(要查看适用于这两种环境的代码,请参阅 ):
- 查阅 developerWorks 文章 “” 了解如何从头开始构建 SELinux 系统。此系统将演示如何将内核与用户空间中的内容绑定在一起。
- Fedora Core 8 系统。Fedora Core 8 系统(撰写本文时的最新版本)将展示 SELinux 与 RBAC 是如何紧密集成在一起的。
使用角色假定一家商店委托您来实现一个安全的收银机结算会计系统。对于每台收银机,最终金额必须由收银员和经理一起计算。首先定义两个角色,收银员和经理。对员工分配角色并要求在收银员倒班时有一名收银员和一名经理同时确认收银机中的总额。
虽然两个系统中的策略文件可能显得有些不同,但是两个系统中使用了相同的数据布局和收银系统。所有数据都存储在 /data 目录下并且只能通过 /bin/register.py 程序访问。经理和收银员都可以使用 register.py 程序来存储值。为了使代码保持简单,它的功能比较有限。收银员只能存储当天自己使用的收银机值。经理可以存储其他员工的值,并且当经理和收银员都为当天的同一台收银机存储了相同的值时,经理可以提交这些值。
当收银员 Bob 使用 register.py bob 109.95 于 2007 年 12 月 12 日下午 9:00 存储值时,系统将创建内容为 “bob 09:00 109.95” 的文件 /data/cashier_r/bob/12-12-2007。接下来,经理 Mary 在下午 9:25 存储相同值,结果系统将创建内容为 “mary 09:25 109.95” 的文件 /data/mgr_r/bob/12-12-2007。最后,Mary 在下午 9:27 使用 register.py bob commit 命令提交这些值,这条命令将创建内容为 “mary 09:27 bob mary 109.95” 的文件 /data/final/bob/12-12-2007。
如果 Bob 和 Mary 的值不一致,则 Mary 将无法提交 Bob 的值。Mary 则必须通知 Bob,两人重新计算直至达成一致,然后可以再次运行以上 /bin/register.py 命令输入相同的值。新值将被追加到先前值中以辅助店主稍后查看,并且 /bin/register.py bob commit 命令将使用最后一次输入的值,而不是 /data/cashier_r/bob/12-12-2007 和 /data/mgr_r/bob/12-12-2007 中的值。
注:此处讨论的代码示例使用 SELinux 处理所有访问控制需求。我们的示例允许系统中的所有用户对 /data 下的所有文件和目录拥有完全的写访问权。但是,在理想部署中,您将需要应用一些 DAC 权限来实现进一步防御。所有经理有时候希望在 /data/mgr_r/bob/ 和 /data/final/bob/ 下创建文件,包括精确地使用 UNIX® 组权限。但是为了简单起见,让我们完全依赖 SELinux 来实施访问控制。 首先,确保经理和收银员只能通过 register.py 程序访问 /data 下的任何文件。例如,Bob 将登录到 cashier_t 类型中的 cashier_r 角色。但是 cashier_t 无法读取 /data 下的数据。为此,他必须进入 cashier_register_t 类型,而他只能通过执行 /bin/register.py 来进入该类型。类似地,Mary 将登录到 mgr_t 类型中的 mgr_r 角色,但是必须执行 /bin/register.py 来进入 mgr_register_t,才能拥有对 /data 下数据的任何访问权。
当 PAM 模块决定 Bob 必须登录到 cashier_r 角色中时,将实际发生访问控制的第一部分。当内核中的 SELinux 类型增强服务器拒绝 bob_u:cashier_r:cashier_t 进入 bob_u:cashier_r:cashier_register_t 时(除非执行 cashier_exec_t 文件类型,这是管理员只分配给 /bin/register.py 的类型),将继续进行访问控制。
当 register.py 拒绝允许收银员提交值或存储另一个用户的值时,将进一步对 register.py 本身进行增强。这是通过 SELinux 策略以及内核代码的策略增强实现的,这种增强不允许 cashier_register_t 访问 /data/mgr_r 或 /data/final 下的文件。
实现收银机系统收银机结算系统的第一个实现是在前面介绍的从头创建的 SELinux 系统之上实现的(可以在 下载 中获得)。下面介绍了在完全从头创建的系统之上实现收银机结算系统的步骤。
挂载磁盘映像(关闭了 qemu 映像):
1
| mount -oloop,offset=32256 -t ext2 gentoo.img /mnt
|
从 下载 部分获取 code_for_fromscratch.tgz 文件,并通过执行以下操作将其解压缩到磁盘映像下:
1
2
| tar zxf selinuxregister.tgz -C /mnt
umount /mnt
|
现在启动 qemu 映像:
1
2
| qemu -hda gentoo.img -m 512 -vnc :3 -kernel bzImage \
-append "ro root=/dev/hda1 -p"
|
登录后,必须编译并安装新策略,同时安装新的 PAM 模块:
1
2
3
4
5
6
| cd /usr/src
checkpolicy -c 19 -o policy.bin policy.conf
cp policy.bin /etc/
rc-update add selinuxenforce default
cp /etc/pam.d/system-auth /etc/pam.d/system-auth.orig
cp /etc/pam.d/system-auth.new /etc/pam.d/system-auth
|
SELinux 用户是在策略中创建的,但是必须创建与 SELinux 用户相对应的 Linux 用户:
1
2
3
4
5
6
7
8
9
10
11
12
| adduser mary
passwd mary
(passwd)
mkdir /home/mary
adduser boss
passwd boss
(passwd)
mkdir /home/boss
adduser bob
passwd bob
(passwd)
mkdir /home/bob
|
然后为数据存储创建目录结构:
1
2
3
4
5
| mkdir /data
mkdir /data/cashier_r
mkdir /data/mgr_r
mkdir /data/final
chmod 777 /data/*
|
最后,重新设置文件系统的标签:
1
2
| setfiles /usr/src/filecontexts /
poweroff
|
现在准备好了映像。在不使用 -p 标志的情况下重新启动映像,以便装载 SELinux 策略:
1
2
| qemu -hda gentoo.img -m 512 -vnc :3 -kernel bzImage \
-append "ro root=/dev/hda1"
|
然后以根用户身份登录,尝试执行以下命令:
权限被拒绝。登出,然后以收银员 bob 的身份登录。记录一个值,例如:
然后尝试执行以下操作欺骗系统:
不起作用。登出,然后重新以经理 Mary 的身份登录:
Mary 首先需要输入她自己的值:
1
2
| register bob 27
register bob commit
|
值不匹配。想知道 Bob 提交了什么值?
1
| cat /data/cashier_r/bob/(day)
|
系统不允许查看该值。您必须去与 Bob 讨论该值。您可能重新计算收银机中的总额并发现 Bob 输入的值无误。因此:
1
2
| register bob 25.22
register bob commit
|
这次可以了。现在可以以根用户身份登录并且:
1
| cat /data/final/bob/(day)
|
这将显示已经输入的所有值。 |