CentOS 7 上的 SELinux 简介 – 第 1 部分:基本概念
介绍
Security Enhanced Linux 或 SELinux 是大多数现代 Linux 发行版中内置的高级访问控制机制。它最初由美国国家安全局开发,用于保护计算机系统免受恶意入侵和篡改。随着时间的推移,SELinux 在公共领域发布,并且各种发行版已将其合并到他们的代码中。
许多系统管理员发现 SELinux 是一个有点未知的领域。这个话题似乎令人生畏,有时甚至令人困惑。但是,正确配置 SELinux 系统可以大大降低安全风险,了解它可以帮助您排查与访问相关的错误消息。在本教程中,我们将了解 SELinux 背后的概念——它的包、命令和配置文件——以及它在访问被拒绝时记录的错误消息。我们还将看到一些将 SELinux 付诸实践的实际例子。
笔记
在本教程中,除非另有说明,否则我们将以 root 用户身份运行命令。如果您无权访问 root 帐户并使用另一个具有 sudo 权限的帐户,则需要在命令前加上 sudo
关键字。
为什么选择 SELinux
在我们开始之前,让我们了解一些概念。
SELinux 实现了所谓的 MAC(强制访问控制)。这是在每个 Linux 发行版中已经存在的 DAC(自主访问控制)之上实现的。
要了解 DAC,我们首先要考虑传统 Linux 文件安全性的工作原理。
在传统的安全模型中,我们有三个实体:用户、组和其他 (u,g,o),他们可以对文件或目录拥有读取、写入和执行 (r,w,x) 权限的组合。如果用户 jo 在其主目录中创建文件,则该用户将具有对该文件的读/写访问权限,jo 组也是如此。 \other 实体可能无法访问它。在下面的代码块中,我们可以考虑 jo 的主目录的假设内容。
您不需要设置这个 jo 用户 - 我们将在本教程的后面部分设置大量用户。
运行这样的命令:
ls -l /home/jo/
可以显示如下输出:
total 4
-rwxrw-r--. 1 jo jo 41 Aug 6 22:45 myscript.sh
现在 jo 可以更改此访问权限。 jo 可以授予(和限制)其他用户和组对此文件的访问权限或更改文件的所有者。这些操作可能会将关键文件暴露给不需要此访问权限的帐户。 jo 也可以限制以提高安全性,但这是自行决定的:系统管理员无法对系统中的每个文件强制执行它。
考虑另一种情况:当一个 Linux 进程运行时,它可能以 root 用户或另一个具有超级用户权限的帐户运行。这意味着如果黑帽黑客控制了应用程序,他们可以使用该应用程序访问用户帐户有权访问的任何资源。对于以 root 用户身份运行的进程,基本上这意味着 Linux 服务器中的一切。
考虑一个场景,您希望限制用户从他们的主目录执行 shell 脚本。当您有开发人员在生产系统上工作时,就会发生这种情况。您希望他们查看日志文件,但不希望他们使用 su
或 sudo
命令,并且您不希望他们运行任何脚本主目录。你是怎样做的?
SELinux 是一种微调此类访问控制要求的方法。使用 SELinux,您可以定义用户或进程可以做什么。它将每个进程限制在自己的域中,因此该进程只能与特定类型的文件和来自允许域的其他进程进行交互。这可以防止黑客劫持任何进程以获得系统范围的访问权限。
设置测试系统
为了帮助我们学习这些概念,我们将构建一个同时运行 Web 和 SFTP 服务器的测试服务器。我们将从 CentOS 7 的裸安装开始,安装最少的软件包,并在该服务器上安装 Apache 和 vsftp 守护进程。但是,我们不会配置这些应用程序中的任何一个。
我们还将在我们的云服务器中创建一些测试用户帐户。在整个课程中,我们将在不同的地方使用这些帐户。
最后,我们将安装所需的 SELinux 相关包。这是为了确保我们可以使用最新的 SELinux 命令。
安装 Apache 和 SFTP 服务
首先,我们以root用户登录服务器,运行如下命令安装Apache:
yum install httpd
输出将显示正在下载的包并询问您是否允许安装:
Loaded plugins: fastestmirror, langpacks
...
...
================================================================================
Package Arch Version Repository Size
================================================================================
Installing:
httpd x86_64 2.4.6-18.el7.centos updates 2.7 M
Transaction Summary
================================================================================
Install 1 Package
Total download size: 2.7 M
Installed size: 9.3 M
Is this ok [y/d/N]:
按 y 将安装 Apache Web 服务器守护程序。
Downloading packages:
httpd-2.4.6-18.el7.centos.x86_64.rpm | 2.7 MB 00:01
Running transaction check
Running transaction test
Transaction test succeeded
Running transaction
Installing : httpd-2.4.6-18.el7.centos.x86_64 1/1
Verifying : httpd-2.4.6-18.el7.centos.x86_64 1/1
Installed:
httpd.x86_64 0:2.4.6-18.el7.centos
Complete!
手动启动守护进程:
service httpd start
运行 service httpd status
命令将显示服务正在运行:
Redirecting to /bin/systemctl status httpd.service
httpd.service - The Apache HTTP Server
Loaded: loaded (/usr/lib/systemd/system/httpd.service; disabled)
Active: active (running) since Tue 2014-08-19 13:39:48 EST; 1min 40s ago
Main PID: 339 (httpd)
...
...
接下来我们将安装vsftp:
yum install vsftpd
输出应类似于以下内容:
Loaded plugins: fastestmirror, langpacks
...
...
==============================================================================================================
Package Arch Version Repository Size
==============================================================================================================
Installing:
vsftpd x86_64 3.0.2-9.el7 base 165 k
Transaction Summary
==============================================================================================================
Install 1 Package
Total download size: 165 k
Installed size: 343 k
Is this ok [y/d/N]:
按 y 安装包。
接下来,我们将使用 service vsftpd start
命令启动 vsftpd 守护进程。输出应显示如下内容:
Redirecting to /bin/systemctl status vsftpd.service
vsftpd.service - Vsftpd ftp daemon
Loaded: loaded (/usr/lib/systemd/system/vsftpd.service; disabled)
Active: active (running) since Tue 2014-08-19 13:48:57 EST; 4s ago
Process: 599 ExecStart=/usr/sbin/vsftpd /etc/vsftpd/vsftpd.conf (code=exited, status=0/SUCCESS)
Main PID: 600 (vsftpd)
...
...
安装 SELinux 软件包
SELinux 中使用了许多包。有些是默认安装的。以下是基于 Red Hat 的发行版的列表:
- policycoreutils(提供用于管理 SELinux 的实用程序)
- policycoreutils-python(提供用于管理 SELinux 的实用程序)
- selinux-policy(提供 SELinux 参考政策)
- selinux-policy-targeted(提供 SELinux 目标策略)
- libselinux-utils(提供一些管理 SELinux 的工具)
- setroubleshoot-server(提供用于解密审计日志消息的工具)
- setools(提供用于审计日志监控、查询策略和文件上下文管理的工具)
- setools-console(提供用于审计日志监控、查询策略和文件上下文管理的工具)
- mcstrans(将不同级别转换为易于理解的格式的工具)
其中一些已经安装。要检查您的 CentOS 7 系统上安装了哪些 SELinux 软件包,您可以以 root 用户身份运行如下几个命令(在 grep
后使用不同的搜索词):
rpm -qa | grep selinux
输出应如下所示:
libselinux-utils-2.2.2-6.el7.x86_64
libselinux-2.2.2-6.el7.x86_64
selinux-policy-targeted-3.12.1-153.el7.noarch
selinux-policy-3.12.1-153.el7.noarch
libselinux-python-2.2.2-6.el7.x86_64
您可以继续使用以下命令安装所有软件包(yum 只会更新您已有的任何软件包),或者仅安装您发现系统中缺少的软件包:
yum install policycoreutils policycoreutils-python selinux-policy selinux-policy-targeted libselinux-utils setroubleshoot-server setools setools-console mcstrans
现在我们应该有一个加载了所有 SELinux 包的系统。我们还有以默认配置运行的 Apache 和 SFTP 服务器。除了 root 帐户之外,我们还有四个常规用户帐户可供测试。
SELinux 模式
是时候开始使用 SELinux 了,所以让我们从 SELinux 模式开始。在任何时候,SELinux 都可以处于三种可能模式中的任何一种:
- 执行
- 宽容
- 残疾
在强制模式下,SELinux 将强制其在 Linux 系统上的策略,并确保拒绝用户和进程的任何未经授权的访问尝试。拒绝访问也会写入相关的日志文件。稍后我们将讨论 SELinux 策略和审计日志。
宽容模式就像半启用状态。 SELinux 不在宽容模式下应用其策略,因此不会拒绝任何访问。但是,任何违反政策的行为仍会记录在审核日志中。这是在执行 SELinux 之前测试它的好方法。
禁用模式是不言自明的——系统不会以增强的安全性运行。
检查 SELinux 模式和状态
我们可以运行 getenforce
命令来检查当前的 SELinux 模式。
getenforce
SELinux 当前应该被禁用,因此输出将如下所示:
Disabled
我们还可以运行 sestatus
命令:
sestatus
当 SELinux 被禁用时,输出将显示:
SELinux status: disabled
SELinux 配置文件
SELinux 的主要配置文件是/etc/selinux/config。我们可以运行以下命令来查看其内容:
cat /etc/selinux/config
输出看起来像这样:
# This file controls the state of SELinux on the system.
# SELINUX= can take one of these three values:
# enforcing - SELinux security policy is enforced.
# permissive - SELinux prints warnings instead of enforcing.
# disabled - No SELinux policy is loaded.
SELINUX=disabled
# SELINUXTYPE= can take one of these two values:
# targeted - Targeted processes are protected,
# minimum - Modification of targeted policy. Only selected processes are protected.
# mls - Multi Level Security protection.
SELINUXTYPE=targeted
该文件中有两个指令。 SELINUX 指令指示 SELinux 模式,它可以具有我们之前讨论的三个可能的值。
SELINUXTYPE 指令确定将使用的策略。默认值为目标
。通过有针对性的策略,SELinux 允许您自定义和微调访问控制权限。另一个可能的值是“MLS”(多级安全),一种高级保护模式。同样对于 MLS,您需要安装一个额外的包。
启用和禁用 SELinux
启用 SELinux 相当简单;但与禁用它不同,应该分两步完成。我们假设 SELinux 当前处于禁用状态,并且您已经安装了前面部分中的所有 SELinux 包。
第一步,我们需要编辑 /etc/selinux/config
文件,将 SELINUX 指令更改为许可模式。
vi /etc/sysconfig/selinux
...
SELINUX=permissive
...
首先将状态设置为允许是必要的,因为系统中的每个文件都需要在 SELinux 被强制执行之前标记其上下文。除非所有文件都被正确标记,否则在受限域中运行的进程可能会失败,因为它们无法访问具有正确上下文的文件。这可能会导致引导过程失败或启动时出现错误。我们将在本教程后面介绍上下文 和域。
现在发出系统重启:
reboot
重启过程将看到服务器中标有 SELinux 上下文的所有文件。由于系统在宽容模式下运行,因此会报告 SELinux 错误和拒绝访问,但不会停止任何操作。
以 root 身份再次登录到您的服务器。接下来,从 /var/log/messages 文件的内容中搜索字符串 \SELinux is preventing。
cat /var/log/messages | grep "SELinux is preventing"
如果没有报告错误,我们可以放心地进行下一步。但是,在 /var/log/messages 文件中搜索包含“SELinux”的文本仍然是个好主意。在我们的系统中,我们运行了以下命令:
cat /var/log/messages | grep "SELinux"
这显示了一些与正在运行的 GNOME 桌面相关的错误消息。当 SELInux 被禁用或处于宽容模式时会发生这种情况:
Aug 20 11:31:14 localhost kernel: SELinux: Initializing.
Aug 20 11:31:16 localhost kernel: SELinux: Disabled at runtime.
Aug 20 11:31:21 localhost journal: Unable to lookup SELinux process context: Invalid argument
Aug 20 11:33:20 localhost gnome-session: SELinux Troubleshooter: Applet requires SELinux be enabled to run.
Aug 20 11:37:15 localhost kernel: SELinux: Initializing.
Aug 20 11:37:17 localhost kernel: SELinux: Disabled at runtime.
Aug 20 11:37:23 localhost journal: Unable to lookup SELinux process context: Invalid argument
Aug 20 11:37:44 localhost gnome-session: SELinux Troubleshooter: Applet requires SELinux be enabled to run.
Aug 20 11:39:42 localhost kernel: SELinux: Initializing.
Aug 20 11:39:44 localhost kernel: SELinux: Disabled at runtime.
Aug 20 11:39:50 localhost journal: Unable to lookup SELinux process context: Invalid argument
这些类型的错误很好。
在第二阶段,我们需要编辑配置文件,将 /etc/sysconfig/selinux
文件中的 SELINUX 指令从 permissive 更改为 enforcing:
...
SELINUX=enforcing
...
接下来,再次重新启动服务器。
reboot
服务器重新联机后,我们可以运行 sestatus
命令来检查 SELinux 状态。它现在应该显示有关服务器的更多详细信息:
SELinux status: enabled
SELinuxfs mount: /sys/fs/selinux
SELinux root directory: /etc/selinux
Loaded policy name: targeted
Current mode: permissive
Mode from config file: error (Success)
Policy MLS status: enabled
Policy deny_unknown status: allowed
Max kernel policy version: 28
检查 /var/log/messages 文件:
cat /var/log/messages | grep "SELinux"
应该没有错误。输出应如下所示:
Aug 20 11:42:06 localhost kernel: SELinux: Initializing.
Aug 20 11:42:09 localhost systemd[1]: Successfully loaded SELinux policy in 183.302ms.
Aug 20 11:44:25 localhost kernel: SELinux: Initializing.
Aug 20 11:44:28 localhost systemd[1]: Successfully loaded SELinux policy in 169.039ms.
检查 SELinux 模式和状态(再次)
我们可以运行 getenforce
命令来检查当前的 SELinux 模式。
getenforce
如果我们的系统在强制模式下运行,输出将如下所示:
Enforcing
如果禁用 SELinux,输出将不同:
Disabled
我们也可以运行 sestatus
命令以获得更好的画面。
sestatus
如果 SELinux 未被禁用,输出将显示其当前状态、当前模式、配置文件中定义的模式以及策略类型。
SELinux status: enabled
SELinuxfs mount: /sys/fs/selinux
SELinux root directory: /etc/selinux
Loaded policy name: targeted
Current mode: enforcing
Mode from config file: enforcing
Policy MLS status: enabled
Policy deny_unknown status: allowed
Max kernel policy version: 28
当 SELinux 被禁用时,输出将显示:
SELinux status: disabled
我们还可以使用 setenforce
命令在强制模式和允许模式之间临时切换。 (请注意,当 SELinux 被禁用时,我们无法运行 setenforce
。)
首先在我们的CentOS 7系统中将SELinux模式从enforcing改为permissive:
setenforce permissive
运行 sestatus
命令现在显示当前模式与配置文件中定义的模式不同:
SELinux status: enabled
SELinuxfs mount: /sys/fs/selinux
SELinux root directory: /etc/selinux
Loaded policy name: targeted
Current mode: permissive
Mode from config file: enforcing
Policy MLS status: enabled
Policy deny_unknown status: allowed
Max kernel policy version: 28
切换回执行:
setenforce enforcing
SELinux 政策
SELinux 安全引擎的核心是它的策略。策略顾名思义:一组定义系统中所有内容的安全和访问权限的规则。当我们说一切时,我们指的是用户、角色、进程和文件。该策略定义了这些实体中的每一个如何相互关联。
一些基本术语
要了解政策,我们必须学习一些基本术语。后面会详细介绍,这里先简单介绍一下。 SELinux 策略定义用户对角色的访问、角色对域的访问以及域对类型的访问。
用户
SELinux 有一组预先构建的用户。每个常规 Linux 用户帐户都映射到一个或多个 SELinux 用户。
在 Linux 中,用户运行一个进程。这可以像用户 jo 在 vi 编辑器中打开文档一样简单(它将是运行 vi 进程的 jo 的帐户)或运行 httpd 守护程序的服务帐户。在 SELinux 世界中,进程(守护进程或正在运行的程序)称为 subject。
角色
角色 就像位于用户和进程之间的网关。角色定义哪些用户可以访问该进程。角色不像组,而更像过滤器:只要角色授予,用户可以随时输入或承担角色。 SELinux 策略中角色的定义定义了哪些用户有权访问该角色。它还定义了角色本身可以访问的流程域。角色发挥作用是因为 SELinux 的一部分实现了所谓的基于角色的访问控制 (RBAC)。
主体和客体
主体 是一个过程,可能会影响客体。
SELinux 中的对象 是可以对其进行操作的任何对象。这可以是一个文件、一个目录、一个端口、一个 tcp 套接字、游标,或者可能是一个 X 服务器。主体可以对客体执行的操作是主体的权限。
域用于主题
域 是 SELinux 主题(进程)可以运行的上下文。该上下文就像围绕该主题的包装纸。它告诉进程它能做什么和不能做什么。例如,域将定义主体可以访问哪些文件、目录、链接、设备或端口。
类型用于对象
类型 是规定文件用途的文件上下文的上下文。例如,文件的上下文可能表明它是一个网页,或者文件属于 /etc
目录,或者文件的所有者是特定的 SELinux 用户。文件的上下文在 SELinux 术语中称为其类型。
那么什么是 SELinux 政策呢?
SELinux 策略定义用户对角色的访问、角色对域的访问以及域对类型的访问。首先用户必须被授权进入角色,然后角色必须被授权访问域。该域又被限制为只能访问某些类型的文件。
该策略本身是一堆规则,规定某某用户只能承担某某角色,并且这些角色将被授权仅访问某某域。这些域反过来只能访问某某文件类型。下图显示了这个概念:

术语提示:最后一点,在特定域中运行的进程只能对特定类型的对象执行特定操作,称为类型强制 (TE)。
回到策略主题,默认情况下,SELinux 策略实现通常也是目标。如果您还记得我们之前看到的 SELinux 配置文件,SELINUXTYPE 指令被设置为 targeted
。这意味着,默认情况下,SELinux 将仅限制系统中的某些进程(即仅针对某些进程)。那些没有被定位的将在不受限制的域中运行。
另一种方法是默认拒绝模型,在该模型中,除非策略批准,否则每次访问都会被拒绝。这将是一个非常安全的实现,但这也意味着开发人员必须预测每个进程可能需要的对每个可能对象的每个可能权限。默认行为认为 SELinux 只关注某些进程。
SELinux 策略行为
SELinux 策略并不能取代传统的 DAC 安全性。如果 DAC 规则禁止用户访问文件,则不会评估 SELinux 策略规则,因为第一道防线已经阻止了访问。 SELinux 安全决策在 DAC 安全性被评估后开始发挥作用。
当启用 SELinux 的系统启动时,策略会加载到内存中。 SELinux 策略采用模块化格式,很像在启动时加载的内核模块。就像内核模块一样,它们可以在运行时从内存中动态添加和删除。 SELinux 使用的策略存储 跟踪已加载的模块。 sestatus
命令显示策略存储名称。 semodule -l
命令列出当前加载到内存中的 SELinux 策略模块。
为了感受一下,让我们运行 semodule
命令:
semodule -l | less
输出看起来像这样:
abrt 1.2.0
accountsd 1.0.6
acct 1.5.1
afs 1.8.2
aiccu 1.0.2
aide 1.6.1
ajaxterm 1.0.0
alsa 1.11.4
amanda 1.14.2
amtu 1.2.3
anaconda 1.6.1
antivirus 1.0.0
apache 2.4.0
...
...
semodule
可用于许多其他任务,如安装、删除、重新加载、升级、启用和禁用 SELinux 策略模块。
到目前为止,您可能有兴趣知道模块文件的位置。大多数现代发行版都将模块的二进制版本作为 SELinux 软件包的一部分。策略文件的扩展名为 .pp。对于 CentOS 7,我们可以运行以下命令:
ls -l /etc/selinux/targeted/modules/active/modules/
该清单显示了一些扩展名为 .pp
的文件。如果仔细观察,它们将涉及不同的应用程序:
...
-rw-r--r--. 1 root root 10692 Aug 20 11:41 anaconda.pp
-rw-r--r--. 1 root root 11680 Aug 20 11:41 antivirus.pp
-rw-r--r--. 1 root root 24190 Aug 20 11:41 apache.pp
-rw-r--r--. 1 root root 11043 Aug 20 11:41 apcupsd.pp
...
.pp
文件不是人类可读的。
SELinux 模块化的工作方式是,当系统启动时,策略模块被组合成所谓的活动策略。然后将此策略加载到内存中。此加载策略的组合二进制版本可在 /etc/selinux/targeted/policy
目录下找到。
ls -l /etc/selinux/targeted/policy/
将显示活动政策。
total 3428
-rw-r--r--. 1 root root 3510001 Aug 20 11:41 policy.29
更改 SELinux 布尔值设置
虽然您无法读取策略模块文件,但有一种简单的方法可以调整它们的设置。这是通过 SELinux booleans 完成的。
要查看它是如何工作的,让我们运行 semanage boolean -l
命令。
semanage boolean -l | less
这显示了可以打开或关闭的不同开关、它们的作用以及它们的当前状态:
ftp_home_dir (off , off) Allow ftp to home dir
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
...
...
我们可以看到第一个选项允许 FTP 守护进程访问用户的主目录。该设置目前处于关闭状态。
要更改任何设置,我们可以使用 setsebool
命令。例如,让我们考虑匿名 FTP 写访问:
getsebool ftpd_anon_write
这向我们展示了此时开关已关闭:
ftpd_anon_write --> off
接下来我们更改布尔值以启用它:
setsebool ftpd_anon_write on
再次检查值应该显示更改:
ftpd_anon_write --> on
更改的布尔值不是永久的。重新启动后,它们恢复为旧值。为了使事情永久化,我们可以将 -P 开关与 setsebool
命令一起使用。
结论
在本教程的第一部分,我们尝试了解一些关于 SELinux 的基本概念。我们已经了解了 SELinux 如何保护系统、我们如何启用它以及它可以在哪些模式下运行。我们还谈到了 SELinux 策略这一主题。接下来,我们将学习如何使用 SELinux 来限制对文件和进程的访问。