CentOS7上的SELinux简介-第1部分:基本概念

来自菜鸟教程
跳转至:导航、​搜索

介绍

安全增强型 Linux 或 SELinux 是一种内置于大多数现代 Linux 发行版中的高级访问控制机制。 它最初由美国国家安全局开发,用于保护计算机系统免受恶意入侵和篡改。 随着时间的推移,SELinux 在公共领域发布,并且各种发行版已将其纳入其代码中。

许多系统管理员发现 SELinux 是一个有点未知的领域。 这个话题似乎令人生畏,有时甚至令人困惑。 但是,正确配置的 SELinux 系统可以大大降低安全风险,了解它可以帮助您排除与访问相关的错误消息。 在本教程中,我们将了解 SELinux 背后的概念——它的包、命令和配置文件——以及它在访问被拒绝时记录的错误消息。 我们还将看到一些将 SELinux 付诸实践的实际实例。

注意 本教程中显示的命令、包和文件是在 CentOS 7 上测试的。 其他发行版的概念保持不变。

在本教程中,除非另有说明,否则我们将以 root 用户身份运行命令。 如果您无权访问 root 帐户并使用具有 sudo 权限的其他帐户,则需要在命令前加上 sudo 关键字。

为什么选择 SELinux

在开始之前,让我们了解一些概念。

SELinux 实现了所谓的 MAC(强制访问控制)。 这是在每个 Linux 发行版中已经存在的 DAC(自由访问控制)之上实现的。

要了解 DAC,我们首先要考虑传统的 Linux 文件安全性是如何工作的。

在传统的安全模型中,我们有三个实体:用户、组和其他 (u,g,o),它们可以对文件或目录拥有读、写和执行 (r,w,x) 权限的组合。 如果用户 jo 在他们的主目录中创建了一个文件,那么该用户将拥有对该文件的读/写访问权限,jo 组也是如此。 “其他”实体可能无法访问它。 在下面的代码块中,我们可以考虑 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 脚本。 当您有开发人员在生产系统上工作时,可能会发生这种情况。 您希望他们查看日志文件,但不希望他们使用 susudo 命令,也不希望他们从其主目录运行任何脚本。 你是怎样做的?

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(提供解密审计日志消息的工具)
  • settools(提供审计日志监控、查询策略、文件上下文管理工具)
  • settools-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 指令确定将使用的策略。 默认值为 targeted。 通过有针对性的策略,SELinux 允许您自定义和微调访问控制权限。 另一个可能的值是“MLS”(多级安全性),一种高级保护模式。 同样使用 MLS,您需要安装一个附加包。

启用和禁用 SELinux

启用 SELinux 相当简单; 但与禁用它不同,应该分两步完成。 我们假设 SELinux 当前已禁用,并且您已经安装了前面部分中的所有 SELinux 软件包。

作为第一步,我们需要编辑 /etc/selinux/config 文件以将 SELINUX 指令更改为许可模式。

vi /etc/sysconfig/selinux
...
SELINUX=permissive
...

首先将状态设置为 permissive 是必要的,因为系统中的每个文件都需要在执行 SELinux 之前标记其上下文。 除非所有文件都正确标记,否则在受限域中运行的进程可能会失败,因为它们无法访问具有正确上下文的文件。 这可能会导致引导过程失败或以错误开始。 我们将在教程后面介绍 contextsdomains

现在发出系统重启:

reboot

重新启动过程将看到服务器中标有 SELinux 上下文的所有文件。 由于系统在许可模式下运行,SELinux 错误和拒绝访问会被报告,但不会停止任何事情。

root 身份再次登录到您的服务器。 接下来,从 /var/log/messages 文件的内容中搜索字符串“SELinux is prevent”。

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 模式从强制更改为许可:

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 安全引擎的核心是其 策略 。 策略顾名思义:一组定义系统中所有内容的安全性和访问权限的规则。 当我们说 everything 时,我们指的是用户、角色、进程和文件。 该策略定义了这些实体中的每一个如何相互关联。

一些基本术语

要了解政策,我们必须学习一些基本术语。 我们稍后会详细介绍,但这里是一个简单的介绍。 SELinux 策略定义了用户对角色的访问、对域的角色访问以及对类型的域访问。

用户

SELinux 有一组预建的用户。 每个常规 Linux 用户帐户都映射到一个或多个 SELinux 用户。

在 Linux 中,用户运行一个进程。 这可以像用户 jo 在 vi 编辑器中打开文档(它将是运行 vi 进程的 jo 帐户)或运行 httpd 守护程序的服务帐户一样简单。 在 SELinux 世界中,进程(守护进程或正在运行的程序)称为 subject

角色

role 就像一个网关,位于用户和进程之间。 角色定义了哪些用户可以访问该进程。 角色不像组,而更像过滤器:用户可以在任何时候进入或担任角色,只要角色授予它。 SELinux 策略中的角色定义定义了哪些用户有权访问该角色。 它还定义了角色本身可以访问的进程域。 角色开始发挥作用是因为 SELinux 的一部分实现了所谓的 基于角色的访问控制 (RBAC)。

主体和客体

subject 是一个进程,可能会影响 object

SELinux 中的 object 是任何可以被操作的东西。 这可以是一个文件、一个目录、一个端口、一个 tcp 套接字、游标,或者可能是一个 X 服务器。 主体可以对对象执行的操作是主体的 权限

域用于主题

domain 是 SELinux 主题(进程)可以运行的上下文。 该上下文就像围绕主题的包装器。 它告诉进程它可以做什么和不能做什么。 例如,域将定义主体可以访问哪些文件、目录、链接、设备或端口。

类型用于对象

type 是规定文件用途的文件上下文的上下文。 例如,文件的上下文可能表明它是一个网页,或者文件属于 /etc 目录,或者文件的所有者是特定的 SELinux 用户。 一个文件的上下文在 SELinux 术语中称为它的 type

那么什么是 SELinux 政策?

SELinux 策略定义了用户对角色的访问、对域的角色访问以及对类型的域访问。 首先必须授权用户进入角色,然后必须授权角色访问域。 该域又被限制为只能访问某些类型的文件。

策略本身就是一堆规则,规定某某用户只能承担某某角色,并且这些角色将被授权访问某某域。 域反过来只能访问某某文件类型。 下图显示了这个概念:

术语提示:最后一点,在特定域中运行的进程只能对某些类型的对象执行某些操作,称为 类型强制 (TE)。

回到策略的话题,SELinux 策略的实现通常也是默认的targeted。 如果你还记得我们之前看到的 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

更改的布尔值不是永久的。 它们在重新启动后恢复为旧值。 为了使事情永久化,我们可以在 setsebool 命令中使用 -P 开关。

结论

在本教程的第一部分,我们尝试了解一些有关 SELinux 的基本概念。 我们已经了解了 SELinux 如何保护系统、我们如何启用它以及它可以在哪些模式下运行。 我们还谈到了 SELinux 政策的话题。 接下来,我们将学习如何使用SELinux来限制对文件和进程的访问