「译」Linux下SELinux卡通图解,豁然开悟
本文翻译自: https://opensource.com/business/13/11/selinux-policy-guide 原文作者: Daniel J Walsh 本文真是不错,本文作者是看到这篇文章后才比较清楚的理解了SELinux的基本原理。希望对大家有所帮助。
我们正在庆祝SELinux发布十周年。这个很难相信。SELinux首先在Fedora Core 3总被引入,而后又被引入到Red Hat Enterprise Linux 4中。本文针对那些还没有使用过SELinux的人或者期望得到解释的人。
SELinux是一个标签系统。每一个进程具有一个标签,每一个文件或者目录对象在操作系统中也有一个标签。甚至网络端口、设备和签字的主机名都有与之对应的标签。我们书写规则来控制一个进程标签对诸如文件对象标签的访问。操作系统内核执行上述规则。有时,该执行被称作强制访问控制(Mandatory Access Control ,简称MAC)。
对象的所有者无权决定对象的安全属性。形如rwx的所有者/组+允许旗标的标准Linux访问控制通常称为自主访问控制(Discretionary Access Control,简称DAC)。SELinux没有UID或者文件所属关系的概念。所有事情都是通过标签加以控制。这意味着SELinux系统不必通过一个超级用户进行设置。
注意:SELinux并不是让你摈弃DAC控制。SELinux是一个并行的控制模型。一个应用可以同时受SELinux和DAC的控制。
强制类型
让我们再进一步看一下标签。SELinux主模型或执行称为类型强制。基本上这意味着我们根据进程的类型定义进程的标签,并根据其类型定义文件系统对象的标签。
类比
想象一个系统,我们在诸如猫和狗这样的对象(物体)上定义类型。猫和狗是进程类型。
我们有一类他们(猫和狗)想与之互动的对象,我们称为食物(food)。并且,我想在食物上添加类型,cat_food和dog_food。
作为策略作者,我说,狗具有吃dog_chow 食物的权限,而猫具有吃cat_chow 食物的权限。在SELinux中我们通过策略的方式书写规则。
allow cat cat_chow:food eat;
allow dog dog_chow:food eat;
基于这些规则,内核将允许猫进程吃标签为cat_chow标签的食物,且允许狗进程吃标签为dog_chow的食物。
但是在SELinux系统当中,一切事情的默认设置是拒绝的。也就是说,如果狗进程试图吃cat_chow的食物,那么内核将阻止它。
同样,猫进程也不允许吃标签为dog_chow的食物。
现实世界
我们在Apache进程加一个名为httpd_t的标签,同时为Apache的内容添加httpd_sys_content_t和httpd_sys_content_rw_t标签。想象一下,我们在MySQL数据库中存储着信用卡数据,同时打上了名为msyqld_data_t的标签。如果Apache进程被黑客攻击,黑客获得了httpd_t进程的控制器,此时黑客可以读httpd_sys_content_t 文件并且写httpd_sys_content_rw_t。但是,即使Apache进程以root用户运行的情况下,黑客并没有权限读取信用卡数据(mysqld_data_t)。在这种情况下,SELinux减轻了被闯入的风险。
MCS安全(Multi-Category Security)
类比
如上,我们有狗进程和猫进程。但是如果我们有Fido和Spot等多个狗进程会发送什么呢?你想阻止Fido吃Spot的dog_chow。
一个解决方案就是创建大量的新类型,比如Fido_dog和Fido_dog_chow。但是这将很快变得不规则,因为所有狗都具有几乎相同的权限。
为了处理上述问题,我们开发了一个新的控制形式,该控制形式称为多策略安全(MCS)。在MCS中,我们添加了一个可以应用在狗进程和dog_chow食物的标签字段。现在我们为狗进程打上dog:random1 (Fido)的标签和dog:random2 (Spot)的标签。
我们将狗的食物打上dog_chow:random1 (Fido) 和 dog_chow:random2(Spot)的标签。
MCS规则认为如果类型强制规则是正确的,并且随机MCS标签匹配的话,此时访问将被允许,否则访问将被拒绝。
Fido (dog:random1)想去吃cat_chow:food,由于类型强制将被拒绝。
Fido (dog:random1) 允许吃 dog_chow:random1的食物。
Fido (dog:random1) 不允许吃spot's (dog_chow:random2) 的食物。
现实世界
在计算机系统中,我们经常有大量具有相同访问权限的进程,但是我们期望它们之间彼此隔离。有时我们称之为多租户环境(multi-tenant environment)。最好的例子就是虚拟机。如果我有一个运行很多虚拟机的服务器,而其中一个被劫持,我希望能够阻止它去攻击其它虚拟机和虚拟机镜像。但是在一个类型强制系统中 KVM 虚拟机被标记为 svirt_t 而镜像被标记为 svirt_image_t。 我们允许 svirt_t 可以读/写/删除标记为 svirt_image_t 的上下文。通过使用 libvirt 我们不仅实现了类型强制隔离,而且实现了 MCS 隔离。当 libvirt 将要启动一个虚拟机时,它会挑选出一个 MCS 随机标签如 s0:c1,c2,接着它会将 svirt_image_t:s0:c1,c2 标签分发给虚拟机需要去操作的所有上下文。最终,虚拟机以 svirt_t:s0:c1,c2 为标签启动。因此,SELinux 内核控制 svirt_t:s0:c1,c2 不允许写向 svirt_image_t:s0:c3,c4,即使虚拟机被一个黑客劫持并接管,即使它是运行在 root 下。
我们在 OpenShift 中使用类似的隔离策略。每一个 gear(user/app process)都有相同的 SELinux 类型(openshift_t)。策略定义的规则控制着 gear 类型的访问权限,而一个独一无二的 MCS 标签确保了一个 gear 不能影响其他 gear。
MLS enforcement
另外一种使用比较少的SELinux增强称为多层级安全(Multi Level Security,简称MLS)。它开发于上世纪 60 年代,并且主要使用在诸如Trusted Solaris等受信操作系统上。
其主要思想是基于其所访问的数据等级来控制进程。一个安全等级的进程不能读高级别的数据。
MLS与MCS非常像,有一个例外是它在增强策略中增加了支配的概念。MCS标签必须精确匹配,但是MLS标签可以通过支配另外一个MLS标签并获得访问权限。
类比
不同于两只不同的狗,我们现在看看两种不同品种狗的情况。我们可以能有一只灰猎犬和一只花瓦瓦。
我们可能要允许灰猎犬(Greyhound)吃任何狗粮,但是奇瓦瓦(Chihuahua)将被阻止,如果它试图灰狗吃狗粮。
我们为灰猎犬打上dog:Greyhound的标签,同时为其狗粮打上dog_chow:Greyhound的标签。奇瓦瓦打上dog:Chihuahua的标签,而其食物打上dog_chow:Chihuahua的标签。
基于MLS策略,我们允许Greyhound标签支配Chihuahua标签。也就是说dog:Greyhound允许吃dog_chow:Greyhound和dog_chow:Chihuahua。
但是dog:Chihuahua不允许吃dog_chow:Greyhound。
当然,基于类型强制,dog:Greyhound和dog:Chihuahua仍然不允许吃cat_chow:Siamese, 即使在MLS类型Greyhound支配Siamese的情况下也是如此。
现实世界
我们有两个Apache服务,一个以httpd_t:TopSecret方式运行,另外一个以httpd_t:Secret方式运行。如果Apache进程httpd_t:Secret被黑客攻击,黑客可以读httpd_sys_content_t:Secret相关的内容,但是不能读httpd_sys_content_t:TopSecret相关的内容。
但是如果Apache服务的httpd_t:TopSecret进程被黑客攻击,那么他既可以读httpd_sys_content_t:Secret的数据,又可以读httpd_sys_content_t:TopSecret的数据。
We use the MLS in military environments where a user might only be allowed to see secret data, but another user on the same system could read top secretdata.
Conclusion
SELinux 是一个功能强大的标签系统,控制着内核授予每个进程的访问权限。最主要的特性是类型强制,策略规则定义的进程访问权限基于进程被标记的类型和客体被标记的类型。也引入了另外两个控制手段,分离有着同样类型进程的叫做 MCS,而 MLS,则允许进程间存在支配等级。