您的位置:首页 > 运维架构 > Linux

SELinux 简介

2015-08-18 11:18 691 查看


14.4. SELinux 简介


14.4.1. 原理

SELinux (安全增强-Security Enhanced Linux)是一种基于Linux LSM(Linux 安全模块)的强制访问控制系统。实际上,内核在执行系统调用前会询问 SELinux 进程是否获得了执行操作的授权。

SELinux 使用一套规则-合称为策略-来授权或禁止操作。这些规则较难创建。幸好,有两种标准策略(针对-targeted 和严格-strict)可以避免大量的配置工作。

在 SELinux 中,权限的管理完全不同于传统的 Unix 系统。进程的权限取决于它的安全上下文。上下文由唤起该进程的用户身份定义,即该时刻用户具有的角色和域。权限实际上取决于域,但是在域之间转换由角色控制。角色之间的转换取决于身份。



图 14.3. 安全上下文和 Unix 用户

实际上,在登录期间,用户被赋予默认的安全上下文(取决于它们的角色)。这定义了当前域,以及所有新的子进程的域。如果想要改变当前角色和相关联的域,就必须调用
newrole
 -r role_r -t 
domain_t
(一个指定角色通常只能被赋予一个域,
-t
参数可以忽略)。该命令需要口令授权。这个特性可以禁止程序自动切换角色。在
SELinux 策略中,这种改变只能是显式的。

Obviously the rights do not apply to all objects (files, directories, sockets, devices, etc.). They can vary from object to object. To achieve this, each object is associated to a type (this
is known as labeling). Domains' rights are thus expressed with sets of (dis)allowed operations on those types (and, indirectly, on all objects which are labeled with the given type).

补充域和类型等效

Internally, a domain is just a type, but a type that only applies to processes. That's why domains are suffixed with
_t
just
like objects' types.

By default, a program inherits its domain from the user who started it, but the standard SELinux policies expect many important programs to run in dedicated domains. To achieve this, those executables are labeled with a dedicated type (for example
ssh
is
labeled with
ssh_exec_t
, and when the program starts, it automatically
switches to the
ssh_t
domain). This automatic domain transition
mechanism makes it possible to grant only the rights required by each program. It is a fundamental principle of SELinux.



图 14.4. 域之间的自动转换

实践找到安全上下文

要找到指定进程的安全上下文,就要在
ps
命令中使用
Z
选项。
[code]$
ps axZ | grep vstfpd
system_u:system_r:ftpd_t:s0   2094 ?    Ss  0:00 /usr/sbin/vsftpd


第一个区段包含了身份,角色,域和 MCS 等级,使用冒号分隔。MCS 等级(多类别安全-Multi-Category Security)是一个参数,它会影响保护策略的机密性,进而基于敏感性管制对文件的访问。本书中,此特性将不做详细解释。

要在命令行中显示当前的安全上下文,应当调用
id -Z

[code]$
id -Z
unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023


要显示赋予文件的类型,使用
ls -Z

[code]$
ls -Z test /usr/bin/ssh
unconfined_u:object_r:user_home_t:s0 test
     system_u:object_r:ssh_exec_t:s0 /usr/bin/ssh


注意要将身份和角色赋予不是特别重要的文件(从未使用过),但是为了统一,所有的对象都被赋予完整的安全上下文。


14.4.2. 设置 SELinux

SELinux 支持嵌入到 Debian 提供的标准内核中。Unix 核心工具无需修改就支持 SELinux。因此,启用 SELinux 也相对容易。

aptitude install selinux-basics selinux-policy-default
命令会自动安装配置
SELinux 系统所需要的软件包。

The selinux-policy-default package contains a set of standard rules. By default, this policy only restricts access for a few widely exposed services. The user sessions are not restricted and it is thus unlikely that SELinux would
block legitimate user operations. However, this does enhance the security of system services running on the machine. To setup a policy equivalent to the old “strict” rules, you just have to disable the
unconfined
module
(modules management is detailed further in this section).

一旦策略安装,就要标识全部有效文件(即给它们赋予类型)。该操作必须使用
fixfiles relabel
命令手工启动。

SELinux 系统现在已经准备好了。要给内核添加
selinux=1
参数来启用它。
audit=1
参数会使
SELinux 记录所有被拒绝的操作。
enforcing=1
参数使规则起作用:不使用该参数的话,SELinux 工作在默认许可模式,该模式下拒绝行为会被记录但是仍然可以执行。可以修改
GRUB 启动加载器的配置文件来附加需要的参数。一个简单的方法是修改
/etc/default/grub
文件中的
GRUB_CMDLINE_LINUX
变量并运行
update-grub
。在重启之后
SELinux 就生效了。

注意在下次启动时,用
selinux-activate
脚本自动化这些操作并强制标识(避免无标识的文件在 SELinux 未生效或正在标识的时候被创建)。


14.4.3. 管理 SELinux 系统

SELinux 策略是一系列的模块化规则集合,安装时它会基于已经安装的服务自动探测并启用相关模块。系统立即可操作。然而,如果一个服务是在 SELinux 策略之后安装的,就要手动启用相应模块了。
semodule
命令可以实现该目的。还必须用
semanage
命令,定义每个用户可用的角色。

这两个命令可以用于修改当前 SELinux 存储在
/etc/selinux/default/
的配置。不像其他配置文件,可以在
/etc/
中的其他配置文件,这些文件不能手工修改。应当使用相应的程序来修改。

进阶更多文档

由于 NSA 没有提供任何官方文档,社区设置了 wiki 来弥补。里面收集了很多信息,但是要意识到大多数 SELinux 贡献者是 Fedora 用户(其中 SELinux 默认启用)。因此,文档趋于处理该发行版的问题。
http://www.selinuxproject.org

应该看一看 Debian 中专门的 wiki 页面和 Russell Coker 的博客,他是 Debian 上致力于 SELinux 最活跃的开发者。
http://wiki.debian.org/SELinux
http://etbe.coker.com.au/tag/selinux/


14.4.3.1. 管理 SELinux 模块

可用的 SELinux 模块存储在
/usr/share/selinux/default/
目录。要在当前配置中启用其中的一个模块,使用
semodule
 -i module.pp
命令。pp 扩展名代表 策略软件包-policy package。

从当前配置中移除模块使用
semodule -r
module
命令。
semodule
 -l
列出当前已经启用的模块清单。同时也输出版本号。
[code]#
semodule -i /usr/share/selinux/default/aide.pp
#
semodule -l
aide    1.4.0
apache  1.10.0
apm     1.7.0
[...]

#
semodule -r aide
#
semodule -l
apache  1.10.0
apm     1.7.0
[...]


semodule
立即加载新配置,除非使用了
-n
选项。需要注意的是在当前配置默认启用的程序(由在
/etc/selinux/config
文件中的
SELINUXTYPE
变量指明),可以使用
-s
选项来修改和储存其他的。注意不同版本支持的选项可能不同。


14.4.3.2. 管理身份

每次用户登录,就会被赋予一个 SELinux 身份。该身份定义了他们可以使用的角色。这两种映射(从用户到身份,从该身份到角色)使用
semanage
命令配置。

一定要阅读 semanage(8) 手册页,即使命令语法和所管理的所有概念相似。你会发现所有子命令的通用选项:
-a
添加,
-d
删除,
-m
修改,
-l
列表,
-t
指明类型(或域)。

semanage login -l
列出当用户身份和 SELinux 身份之间的映射。没有指明登记项的用户会使用
__default__
登记项。
semanage
 login -a -s user_u user
命令会关联 user_u 身份到指定用户。
semanage
 login -d user
会移除赋予用户的映射登记项。
[code]#
semanage login -a -s user_u rhertzog
#
semanage login -l

Login Name SELinux User MLS/MCS Range

__default__ unconfined_u s0-s0:c0.c1023
rhertzog user_u None
root unconfined_u s0-s0:c0.c1023
system_u system_u s0-s0:c0.c1023
#
semanage login -d rhertzog[/code]

semanage user -l
列出 SELinux 用户身份和允许的角色之间的映射。添加一个新的身份需要定义相应的角色和用于给个人文件赋予类型的标识前缀(
/home/user/*
)。前缀必须从
user
staff
,和
sysadm
之间挑选。
staff
前缀生成
staff_home_dir_t
类型文件。创建新的用户身份使用
semanage
 user -a -R roles -P 
prefix identity
。使用
semanage user -d
identity
移除用户身份。
[code]#
semanage user -a -R 'staff_r user_r' -P staff test_u
#
semanage user -l

Labeling MLS/ MLS/
SELinux User Prefix MCS Level MCS Range SELinux Roles

root sysadm s0 s0-s0:c0.c1023 staff_r sysadm_r system_r
staff_u staff s0 s0-s0:c0.c1023 staff_r sysadm_r
sysadm_u sysadm s0 s0-s0:c0.c1023 sysadm_r
system_u user s0 s0-s0:c0.c1023 system_r
test_u staff s0 s0 staff_r user_r
unconfined_u unconfined s0 s0-s0:c0.c1023 system_r unconfined_r
user_u user s0 s0 user_r
#
semanage user -d test_u[/code]


14.4.3.3. 管理文件上下文,端口和布尔值

每个 SELinux 模块提供了一套标识规则,但是也可以添加定制的标识规则来满足特殊情况。例如,如果想要网页服务器能读取
/srv/www/
里面的文件,就要执行
semanage
 fcontext -a -t httpd_sys_content_t "/srv/www(/.*)?"
restorecon
 -R /srv/www/
。前者注册新的标识规则,后者根据当前标识规则重置文件类型。

类似地,TCP/UDP 端口被标识,以确保只有相对应的守护进程可以监听它们。譬如,如果想要网页服务器能监听8080端口,就要运行
semanage
 port -m -t http_port_t -p tcp 8080


有些 SELinux 模块导出布尔选项,可以用来改变默认规则。
getsebool
程序可以用于检查此类选项(
getsebool
boolean
显示一个选项,
getsebool
 -a
显示所有选项)。
setsebool
boolean value
命令改变当前布尔选项值。
-P
选项使更改永久生效,就意味着新规则成为默认规则,重启之后也会保留。下面的例子授予网页服务器对用户主目录的访问权限(当用户在
~/public_html/
中有个人网页的时候,这是很有用的)。
[code]#
getsebool httpd_enable_homedirs
httpd_enable_homedirs --> off
#
setsebool -P httpd_enable_homedirs on
#
getsebool httpd_enable_homedirs
httpd_enable_homedirs --> on



14.4.4. 适应规则

既然 SELinux 策略是模块化的,那么为(定制化)新应用开发新模块是很有趣的。这些新模块会完善参考策略。

要创建新模块,需要 selinux-policy-dev 软件包,还有 selinux-policy-doc。后者包含了标准规则的文档(
/usr/share/doc/selinux-policy-doc/html/
)和可用于创建新规则的模板示例文件。安装这些文件并更深入的研究:
[code]$
zcat /usr/share/doc/selinux-policy-doc/Makefile.example.gz >Makefile
$
zcat /usr/share/doc/selinux-policy-doc/example.fc.gz >example.fc
$
zcat /usr/share/doc/selinux-policy-doc/example.if.gz >example.if
$
cp /usr/share/doc/selinux-policy-doc/example.te ./[/code]

.te
文件是最重要的一个。它定义规则。
.fc
文件定义“文件上下文”,即与模块相关的文件被赋予的类型。
.fc
文件里的数据将在文件标识时使用。
.if
文件定义了模块接口:它是一套“公用函数”,以便其他模块可以同你所创建的模块交互。


14.4.4.1. 写一个
.fc
文件

阅读下面的例子足可以理解此类文件的结构。可以使用正则表达式给多个文件,甚至是整个目录树赋予相同的安全上下文。

例 14.2.
example.fc
文件


#myapp executable will have:
#label: system_u:object_r:myapp_exec_t
#MLS sensitivity: s0
#MCS categories: <none>

/usr/sbin/myapp -- gen_context(system_u:object_r:myapp_exec_t,s0)



14.4.4.2. 写一个
.if
文件

在下面的例子中,第一个接口(
myapp_domtrans
)控制谁可以执行程序。第二个(
myapp_read_log
)授予程序日志文件的读权限。

每个接口必须有一套规则并嵌入到
.te
文件。因此必须声明所有使用的类型(使用
gen_require
宏),并使用标准指令授予权限。也可以使用其他模块提供的接口。如何表示这些权限将在下节给出更详细的解释。

例 14.3.
example.if
文件


##<summary>Myapp example policy</summary>
##<desc>
##<p>
## More descriptive text about myapp. The <desc>
## tag can also use <p>, <ul>, and <ol>
## html tags for formatting.
##</p>
##<p>
## This policy supports the following myapp features:
## <ul>
## <li>Feature A</li>
## <li>Feature B</li>
## <li>Feature C</li>
## </ul>
##</p>
##</desc>
#

########################################
##<summary>
##Execute a domain transition to run myapp.
##</summary>
##<param name="domain">
##Domain allowed to transition.
##</param>
#
interface(`myapp_domtrans',`
gen_require(`
type myapp_t, myapp_exec_t;
')

domtrans_pattern($1,myapp_exec_t,myapp_t)
')

########################################
##<summary>
##Read myapp log files.
##</summary>
##<param name="domain">
##Domain allowed to read the log files.
##</param>
#
interface(`myapp_read_log',`
gen_require(`
type myapp_log_t;
')

logging_search_logs($1)
allow $1 myapp_log_t:file r_file_perms;
')


文档关于参考策略的解释

参考策略像其他任何自由软件一样演变:基于志愿者的贡献。该项目有 Tresys 托管,它是在 SELinux 领域最活跃的公司之一。他们的 wiki 页面包含了如何构建规则的解释以及如何创建新规则。
http://oss.tresys.com/projects/refpolicy/wiki/GettingStarted


14.4.4.3. 写一个
.te
文件

看一看
example.te
文件:

进阶
m4
宏语言


要恰当的构建策略,SELinux 开发者使用宏命令处理器。他们创建了“宏功能”,而非重复使用很多相似的允许(allow)指令,来使用高级别的逻辑生成更加可读的策略。

实际上,
m4
用于编译这些规则。它进行反方向地操作:将所有高级别的逻辑扩展为由允许(allow)指令组成的巨型数据库。

SELinux“接口”只是宏功能,在编译时它会被一套规则替代。类似地,有些权限其实是一套权限集合,它们在编译时会被实际值取代。

policy_module(myapp,1.0.0) 


########################################
#
#Declarations
#

type myapp_t;


type myapp_exec_t;
domain_type(myapp_t)
domain_entry_file(myapp_t, myapp_exec_t)


type myapp_log_t;
logging_log_file(myapp_log_t)


type myapp_tmp_t;
files_tmp_file(myapp_tmp_t)

########################################
#
#Myapp local policy
#

allow myapp_t myapp_log_t:file { read_file_perms append_file_perms };


allow myapp_t myapp_tmp_t:file manage_file_perms;
files_tmp_filetrans(myapp_t,myapp_tmp_t,file)





模块必须通过名字和版本号标识。此指令是必须的。



如果模块引入了新类型,它们必须使用类似的指令声明。不要害怕需要创建的类型过多,这总胜过赋予过多无用权限。



这些接口定义
myapp_t
类型为进程域,它可以被标识为
myapp_exec_t
的可执行程序使用。这隐式地给这些对象添加
exec_type
属性,反过来允许其他模块授予权限执行这些程序:例如,
userdomain
模块允许具有
user_t
staff_t
,和
sysadm_t
域的进程执行。其他受限域将无权运行,除非规则赋予它们类似的权限(在此例中,
dpkg
和域
dpkg_t
)。



logging_log_file
是一个有参考策略提供的接口。它指明具有某些标识的文件是日志文件并从相关联的规则中获取权限(例如赋予
logrotate
权限,以便于处理它们)。



allow
指令是授予操作权限的基本指令。第一个参数是允许执行操作的进程域。第二个定义前面的域进程可以操作的对象。参数的形式是:“type:class”此处 type 是
SELinux 类型,class 描述对象(文件,目录,套接字,fifo,等等)属性。最后的参数描述许可权限(即允许的操作)。

许可权限由一套允许操作集合组成,并按照这个模板:
{
operation1 operation2 }
。可以使用宏来代表最常用的许可。
/usr/share/selinux/default/include/support/obj_perm_sets.spt
中一一列举。

后面的网页提供了一个比较详尽的对象类列表,以及可以授予的权限。
http://www.selinuxproject.org/page/ObjectClassesPerms

现在需要找到能确保目标程序或服务正常工作的最小规则集合。要做到这一点,就要很好的理解应用程序是如何工作的,它需要处理或生成什么样的数据。

然而,实验方法也可以。一旦相关的对象被正确标识,可以在许可模式下使用应用程序:应该禁止的操作会被记录但是仍然会运行。通过分析日志,就能识别那些操作应该允许。这里有一个此类日志条目示例:
avc:  denied  { read write } for  pid=1876 comm="syslogd" name="xconsole" dev=tmpfs ino=5510 scontext=system_u:system_r:syslogd_t:s0 tcontext=system_u:object_r:device_t:s0 tclass=fifo_file


为了更好的理解这条信息,我们逐一分析。

表 14.1. SELinux 追踪记录分析

消息描述
avc:
 denied
一个操作被拒绝。
{
 read write }
该操作需要
读-read
写-write
许可。
pid=1876
进程号为1876的进程执行的操作(或者试图执行)。
comm="syslogd"
该进程是
syslogd
程序的一个实例。
name="xconsole"
目标对象名称是
xconsole
dev=tmpfs
承载目标对象的设备是
tmpfs
(一个内存文件系统)。对于真实磁盘,可以看到承载对象的分区(例如:“hda3”)。
ino=5510
对象的节点(inode)号码是5510。
scontext=system_u:system_r:syslogd_t:s0
这是执行操作进程的安全上下文。
tcontext=system_u:object_r:device_t:s0
这是执行操作对象的安全上下文。
tclass=fifo_file
目标对象是一个 FIFO 文件。
通过观察日志条目,就可以创建允许操作的规则。例如:
allow syslogd_t device_t:fifo_file { read write
 }
。这一过程可以自动化,这正是
audit2allow
(在 policycoreutils 软件包)命令所提供的功能。这种方法只在各种对象根据其限制已被正确标识时有用。任何情况下,都要仔细审阅创建的规则并根据对应用程序的认识验证它们。实际上,这种方法通常会授予比实际需求更多的权限。恰当的方案是创建新的类型并且只授予针对这些类型的权限。有时候,拒绝操作对应用程序并不是致命的,这种情况下,可以添加一条“
忽略-dontaudit
”规则来避免记入日志。

补充无角色的策略规则

在创建新规则时,完全看不到角色是比较怪异的。SELinux 只使用域来确定哪些操作允许。角色只是通过允许用户切换到另外的域间接起作用。SELinux 是基于被称为类型增强-Type Enforcement 的理论,类型是唯一影响授权的元素。


14.4.4.4. 编译文件

Once the 3 files (
example.if
,
example.fc
,
and
example.te
) match your expectations for the new rules, just
run
make
to generate a module in the
example.pp
file
(you can immediately load it with
semodule -i example.pp
). If
several modules are defined,
make
will create all the corresponding
.pp
files.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: