首页 > 代码库 > SELinux 简单介绍

SELinux 简单介绍

在linux操作系统中,SELinux提供了一个安全精细化的策略规则,这个类似于网络中的ACL规则,用于对文件进行访问控制。但是对于大多数系统管理员来说,往往觉的SELinux过于繁琐而直接禁用,其实在安全性要求较高的场景,合理的使用SElinux可以使我们的系统更加稳固。

SELinux的目的是确保进程如何在Linux环境中访问文件。如果没有SELinux,像Apache守护程序这样的进程或应用程序使用root启动,当应用受到流氓程序的攻击,应用程序可以执行任何所需的操作,因为root对每个文件都具有全面的权限。而使用SELinux,对应用的行为进行限制,就可以避免这一问题。


SELinux尝试走一步,消除这种风险。 使用SELinux,进程或应用程序将只拥有其所需的权限,而不再需要。 应用程序的SELinux策略将确定它需要访问哪些类型的文件以及可以转换到哪些进程。 SELinux策略是由应用程序开发人员编写的,并附带在支持它的Linux发行版中。 一项政策基本上是将流程和用户映射到其权利的一套规则。


SELinux 策略

SELinux安全引擎的核心是其策略。 一个策略表示的其实是一组规则,用于定义系统中所有内容的安全性和访问权限。 SELinux使用 用户,角色,流程和文件对策略进行分类,并定义了每个实体如何相互关联。

用户(users):SELinux中所指的用户包含linux系统中的普通用户和系统用户,一个用户可以管理自己的文件,进程等,一个进程被叫做subject。

色(rolers): 角色就像一个位于用户和进程之间的网关。 角色定义哪些用户可以访问该进程。 角色不像组,但更像过滤器:用户可以在任何时候被授予角色的权限。 SELinux策略中角色的定义了哪些用户可以访问该角色。 它还定义了角色本身可以访问的进程域。 使用角色,使SELinux实现了所谓的基于角色的访问控制(RBAC)。

主题和对象(Subjects and Objects):Subject 就是一个进程,进程会对Object有潜在的影响。这里的对象(object)可以是一个文件、目录、端口,tcp套接字,甚至是一台服务器。一个subject对对象执行的动作,就是subject所拥有的权限。

域(Domains):域是SELinux主题(进程)可以运行的区域。 这个区域就像一个subject的活动范围。 它告诉进程可以做什么,不能做什么。 例如,域将定义主题可访问哪些文件,目录,链接,设备或端口。

类型(Types): Types 类似于元数据的概念,它用来描述对象(object)的属性,例如,它可以去描述一个网页,或者一个文件属于/ etc目录,或该文件的所有者是特定的SELinux用户等。


那么什么是SELinux策略呢?

SELinux策略定义用户被授权给角色,域授权给角色,类型授权给域。 首先,用户必须被授权才能具有角色,然后角色必须被授权才能访问该域。 该域又被限制为只访问某些类型的文件。


该策略本身是一系列规则,表示所有用户只能承担这样的角色,并且这些角色将被授权只能访问这样的域。 这些域又可以访问只有这样的文件类型。 下图显示了这个概念:

技术分享


回到策略主题,SELinux策略实现通常也是默认targeted类型。 在SELinux配置文件中,SELINUXTYPE指令默认设置为 targeted,这意味着,默认情况下,SELinux只会限制系统中的某些进程(即仅定义某些进程)。 未使用targeted标记的那些将在无约束的域中运行。在最严格的安全策略中,替代方案是默认拒绝模式,除非授权许可,否则每个访问都被拒绝。 这将是一个非常安全的实现,但这也意味着开发人员必须预期每一个进程可能需要每一个可能的对象的每一个可能的权限。 默认情况下,SELinux只关心某些进程。


SELinux策略行为

SELinux策略并不代替传统的自由访问控制(Discretionary Access Control)安全性。 如果DAC规则禁止用户访问文件,则不会评估SELinux策略规则,因为第一道防线已经阻止访问。 在DAC安全性被评估之后,SELinux的安全决策就会发挥作用。


启用SELinux的系统时,策略将加载到内存中。 SELinux策略采用模块化格式,与引导时加载的内核模块非常相似。 就像内核模块一样,它们可以在运行时被动态添加和从内存中删除。 SELinux使用的策略存储跟踪已加载的模块。 sestatus命令显示策略存储名称。 semodule -l命令列出当前加载到内存中的SELinux策略模块。

semodule模块可用于安装,删除,重新加载,升级,启用和禁用SELinux策略模块等其他任务。

虽然我们无法阅读策略模块文件,但有一种简单的方式来调整设置。 这是通过SELinux布尔值来完成的:

运行下面的命令:

semanage boolean -l | less

SELinux boolean                State  Default Description

privoxy_connect_any            (on   ,   on)  Allow privoxy to connect any
smartmon_3ware                 (off  ,  off)  Allow smartmon to 3ware
mpd_enable_homedirs            (off  ,  off)  Allow mpd to enable homedirs
xdm_sysadm_login               (off  ,  off)  Allow xdm to sysadm login
xen_use_nfs                    (off  ,  off)  Allow xen to use nfs
mozilla_read_content           (off  ,  off)  Allow mozilla to read content
ssh_chroot_rw_homedirs         (off  ,  off)  Allow ssh to chroot rw homedirs
mount_anyfile                  (on   ,   on)  Allow mount to anyfile
cron_userdomain_transition     (on   ,   on)  Allow cron to userdomain transition
xdm_write_home                 (off  ,  off)  Allow xdm to write home
openvpn_can_network_connect    (on   ,   on)  Allow openvpn to can network connect

可以使用setsebool命令来设置需要访问的值,首先使用getsetool来查看当前的属性:

# getsebool xen_use_nfs   
xen_use_nfs --> off

设置其为on:

# setsebool xen_use_nfs on
# getsebool xen_use_nfs   
xen_use_nfs --> on

改变的布尔不是永久的。 重新启动后,它们恢复为默认值。 为了使配置永久生效,我们可以使用setsebool命令时加上-p选项。


SELinux上下文

安全策略的第一部分在Linux系统中的每个实体上放置一个标签。 标签就像任何其他文件或进程的属性(所有者,组,创建日期等); 它显示了资源的上下文。 那是什么上下文呢? 简单地说,上下文是一些有助于SELinux进行访问控制决策的相关信息的集合。 Linux系统中的所有内容都可以具有安全上下文:用户帐户,文件,目录,守护程序或端口都可以具有安全上下文。 然而,安全上下文对于不同类型的对象来说意味着不同的内容。


文件上下文(file contexts)

文件独特的属性是role。

使用ls -Z命令查看部分文件:

# ls -Z /etc/*.conf

-rw-r--r--. root root system_u:object_r:etc_t:s0       /etc/asound.conf
-rw-r--r--. root root system_u:object_r:dnsmasq_etc_t:s0 /etc/dnsmasq.conf
-rw-r--r--. root root system_u:object_r:etc_t:s0       /etc/dracut.conf
-rw-r--r--. root root system_u:object_r:etc_t:s0       /etc/e2fsck.conf
-rw-r--r--. root root system_u:object_r:etc_t:s0       /etc/host.conf

可以发现多了一行system_u:object_r:etc_t:s0的内容。这里面的4个组成部分以冒号分隔,分别表示user,roler,type. system_u表示的是root用户,这里通过SELinux内部策略转换的。role部分不过多介绍。type这是定义文件或目录所属类型的部分。 我们可以看到大多数文件属于/etc目录中的etc_t类型。 可以将类型视为文件的“组”或属性:它是对文件进行分类的一种方法。s0的第四部分与多级安全性或MLS有关,这是执行SELinux安全策略的另一种方式,这部分显示了资源的灵敏度(s0)。 


进程上下文(Process Contexts)

进程的独特属性是domain.

使用命令ps -Z参数可以查看进程的上下文信息。

# ps -efZ |grep http

system_u:system_r:httpd_t:s0    root      8527     1  0 14:52 ?        00:00:00 /usr/sbin/httpd -DFOREGROUND
system_u:system_r:httpd_t:s0    apache    8528  8527  0 14:52 ?        00:00:00 /usr/sbin/httpd -DFOREGROUND
system_u:system_r:httpd_t:s0    apache    8529  8527  0 14:52 ?        00:00:00 /usr/sbin/httpd -DFOREGROUND
system_u:system_r:httpd_t:s0    apache    8530  8527  0 14:52 ?        00:00:00 /usr/sbin/httpd -DFOREGROUND
system_u:system_r:httpd_t:s0    apache    8531  8527  0 14:52 ?        00:00:00 /usr/sbin/httpd -DFOREGROUND
system_u:system_r:httpd_t:s0    apache    8532  8527  0 14:52 ?        00:00:00 /usr/sbin/httpd -DFOREGROUND

system_u:system_r:httpd_t:s0也有四部分内容: user, role,domain,敏感度。这里有一个domain,domain对于进程来说是唯一的,它定义了进程允许的操作范围,告诉进程什么能做,什么不能做。

使用这个方式,即使一个进程被另一个恶意进程或用户劫持,最糟糕的情况是损坏它可以访问的文件。 例如,vsftp守护程序将无法访问sendmail或samba使用的文件。 这种限制是从内核级别实现的:它被执行为SELinux策略加载到内存中,因此访问控制变为强制的。


进程访问资源方式

在我们进一步了解之前,以下是关于SELinux命名约定的说明。 SELinux用户后缀为“u”,角色后缀为“r”,类型(对于文件)或域(对于进程)后缀为“_t”。

我们已经看到文件和进程可以具有不同的上下文,并且它们仅限于它们自己的类型或域。 那么进程如何运行? 运行时,进程需要访问其文件并对其执行一些操作(打开,读取,修改或执行)。 每个进程只能访问某些类型的资源(文件,目录,端口等)。

SELinux在策略中规定了这些访问规则。 访问规则遵循标准的allow语句结构:

allow <domain> <type>:<class> { <permissions> };

这里的class主要定义了一些实际资源如 文件,目录,软连接,设备,端口等。

  • 如果进程是指定的域

  • 它试图访问的资源对象是指定的type或class类型

  • 然后允许访问

  • 否则拒绝访问


如在/var/www/html目录下创建一个网页文件:

# ls -lZ index.html 

-rw-r--r--. root root unconfined_u:object_r:httpd_sys_content_t:s0 index.html

我们可以使用sesearch命令来查看授权给httpd服务的类型信息:

# sesearch --allow --source httpd_t --target httpd_sys_content_t --class file
Found 5 semantic av rules:
   allow httpd_t httpd_content_type : file { ioctl read getattr lock open } ; 
   allow httpd_t httpd_sys_content_t : file { ioctl read getattr lock open } ; 
   allow httpd_t httpdcontent : file { ioctl read write create getattr setattr lock append unlink link rename open } ; 
   allow httpd_t httpdcontent : file { read getattr execute open } ; 
   allow httpd_t httpd_content_type : file { ioctl read getattr lock open } ;

这里表示httpd守护程序(Apache Web服务器)具有I / O控制,读取,获取属性,锁定和打开对httpdsyscontent类型文件的权限。 在这种情况下,我们的index.html文件具有相同的类型。

使用chcon命令来改变index.html的上下文配置:

# chcon --type var_t /var/www/html/index.html
# ls -Z index.html 
-rw-r--r--. root root unconfined_u:object_r:var_t:s0   index.html

此时再次访问网页时,会出现403 Forbidden报错,原因是没有权限读取现在的index.html文件内容了。

如果要恢复之前的设置,使用restorecon命令:

# restorecon -v /var/www/html/index.html

restorecon reset /var/www/html/index.html cobject_r:var_t:s0->unconfined_u:object_r:httpd_sys_content_t:s0ontext unconfined_u:

此时访问网页就恢复正常了。

要确保文件和目录具有正确的上下文,这对SELinux的行为是至关重要


文件和目录的上下文继承

SELinux执行我们可以称之为“上下文继承”的东西。 这意味着除非由策略,进程和文件指定,父目录的上下文会创建它们。

因此,如果我们有一个称为“proca”的进程,产生一个“procb”的进程,则生成的进程将在与“proc_a”相同的域中运行,除非SELinux策略另有规定。

类似地,如果我们有一个类型为“somecontextt”的目录,则在其下创建的任何文件或目录将具有相同的类型上下文,除非该策略另有说明。

当我们在一个目录创建或者从其他目录拷贝一个文件时,会自动修改上下文为当前目录的上下文类型。

如:

# ls -Z /var/www/html/index.html 
-rw-r--r--. root root unconfined_u:object_r:httpd_sys_content_t:s0 /var/www/html/index.html
# cp /var/www/html/index.html /etc/
# ls -Z /etc/index.html 
-rw-r--r--. root root unconfined_u:object_r:etc_t:s0   /etc/index.html

当使用mv命令移动文件时,文件的上下文属性是不会改变的:

# ls -Z /var/index.html 
-rw-r--r--. root root unconfined_u:object_r:etc_t:s0   /var/index.html


更改和恢复SELinux文件上下文

有这样一种情况:如果我们要修改http的根目录,将之前的文件拷贝到新建的如/www/html目录下,配置好配额日志文件之后重启httpd,依然是出现403的错误无法访问,原因是新的目录下上下文属性改变了,要解决这个问题我们可以手动修改,但是请注意,这里通过chcon命令修改的只是临时生效,文件系统重新标记或运行restorecon命令将使文件还原到其原始上下文。要永久修改我们需要修改他们的默认值。

此外,运行chcon需要您知道文件的正确上下文; --type标志指定目标的上下文。 restorecon不需要指定。 如果运行restorecon,文件将重新应用正确的上下文,并且更改将被永久保存。

系统为了方便SELinux“记住”服务器中每个文件或目录的上下文。 在CentOS 7中,系统中已存在的文件的上下文列在/etc/selinux/targeted/contexts/files/file_contexts文件中。 它是一个大文件,它列出了与Linux发行版支持的每个应用程序相关联的每个文件类型。 新目录和文件的上下文记录在/etc/selinux/targeted/contexts/files/file_contexts.local文件中。 因此,当我们运行restorecon命令时,SELinux将从这两个文件之一中查找正确的上下文,并将其应用于目标。


首先我们运行semanage fcontext命令。 这将写入新的上下文到/etc/selinux/targeted/contexts/files/file_contexts.local文件。 但它不会重新标记文件本身。

# semanage fcontext --add --type httpd_sys_content_t "/www(/.*)?"
# semanage fcontext --add --type httpd_sys_content_t "/www/html(/.*)?"

查看是否添加成功:

# cat /etc/selinux/targeted/contexts/files/file_contexts.local

# This file is auto-generated by libsemanage
# Do not edit directly.
/www(/.*)?    system_u:object_r:httpd_sys_content_t:s0
/www/html(/.*)?    system_u:object_r:httpd_sys_content_t:s0

接下来,我们将运行restorecon命令。 这将在上一步中记录的内容重新标记文件或目录:

restorecon -Rv /www
这应该在三个级别重置上下文:顶级/www目录,/www/html目录以及/www/html下的index.html文件

现在再尝试打开网页将会正常显示。


有一个matchpathcon的工具可帮助排除上下文相关的问题。 此命令将查看资源的当前上下文并将其与SELinux上下文数据库中列出的内容进行比较。 如果不同,它将提示需要更改:

# matchpathcon -V /www/html/index.html
/www/html/index.html verified.


参考链接:
https://www.digitalocean.com/community/tutorials/an-introduction-to-selinux-on-centos-7-part-2-files-and-processes 

本文出自 “Trying” 博客,请务必保留此出处http://tryingstuff.blog.51cto.com/4603492/1944819

SELinux 简单介绍