介绍
Security Enhanced 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 脚本的场景。当您让开发人员在生产系统上工作时,就会发生这种情况。您希望他们查看日志文件,但不希望他们使用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 目标[targeted]策略)
- 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 都可以处于三种可能的模式中的任何一种:
- 强制执行 Enforcing
- 许可模式 Permissive
- 已禁用 Disabled
在强制模式下,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。通过targeted
有针对性的策略,SELinux 允许您自定义和微调访问控制权限。另一个可能的值是“MLS”(多级安全),一种高级保护模式。对于 MLS,您还需要安装一个额外的包。
启用和禁用 SELinux
启用 SELinux 相当简单;但与禁用它不同,应该分两步完成。我们假设 SELinux 当前已禁用,并且您已经安装了前面部分中的所有 SELinux 包。
作为第一步,我们需要编辑/etc/selinux/config文件以将 SELINUX 指令更改为许可模式。
vi /etc/sysconfig/selinux
...
SELINUX=permissive
...
首先将状态设置为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
这些类型的错误没有问题(fine)。
在第二阶段,我们需要编辑配置文件,在/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
切换回enforcing:
setenforce enforcing
SELinux 策略
SELinux 安全引擎的核心是它的策略。策略顾名思义:定义系统中一切内容的安全性和访问权限的一组规则。当我们说一切时,我们指的是用户、角色、进程和文件。该策略定义了这些实体中的每一个如何相互关联。
一些基本术语
要理解策略,我们必须学习一些基本术语。我们稍后会详细介绍,但这里是一个简单的介绍。SELinux 策略定义了用户对角色的访问、角色对域的访问以及域对类型的访问。
用户
SELinux 有一组预建的用户。每个常规 Linux 用户帐户都映射到一个或多个 SELinux 用户。
在 Linux 中,用户运行一个进程。这可以像用户jo在 vi 编辑器中打开文档(它将是运行 vi 进程的 jo 帐户)或运行 httpd 守护程序的服务帐户一样简单。在 SELinux 世界中,一个进程(一个守护进程或一个正在运行的程序)被称为一个subject。
角色
一个角色就像是位于一个用户和进程之间的一个网关。角色定义哪些用户可以访问该进程。角色不像组,而更像是过滤器:用户可以随时进入或承担角色,只要将角色授予它。SELinux 策略中的角色定义限定了哪些用户可以访问该角色。它还定义了角色本身可以访问的进程域。角色发挥作用是因为 SELinux 的一部分实现了所谓的基于角色的访问控制(RBAC)。
主体和对象
主体是一个进程,可能会影响一个对象。
SELinux 中的对象是任何可以操作的对象。这可以是一个文件、一个目录、一个端口、一个 tcp 套接字、游标,或者一个 X 服务器。主体可以对对象执行的操作是主体的权限。
域用于主体
域是的SELinux的主体(进程)可以在其中运行的上下文。该上下文就像围绕主体的包装器。它告诉进程它可以做什么,不能做什么。例如,域将定义主体可以访问哪些文件、目录、链接、设备或端口。
类型用于对象
类型是的文件的上下文(此处原文为A type is the context for a file’s context),它规定了文件的用途。例如,文件的上下文可能表明它是一个网页,或者该文件属于/etc
目录,或者该文件的所有者是特定的 SELinux 用户。文件的上下文在 SELinux 术语中称为其类型。
那么什么是 SELinux 策略?
SELinux 策略定义了用户对角色的访问、角色对域的访问以及域对类型的访问。首先必须授权用户进入角色,然后必须授权角色访问域。接下来,域被限制为只能访问某些类型的文件。
策略本身是一堆规则,规定某某用户只能承担某某角色,而这些角色将被授权只能访问某某域。接下来域只能访问某某文件类型。下图显示了这个概念: 
术语提示:最后一点,在特定域中运行的进程只能对某些类型的对象执行某些操作,这称为类型强制(TE)。
回到策略主题,SELinux 策略实现通常默认为目标(targeted)。如果你还记得我们之前看到的 SELinux 配置文件,SELINUXTYPE 指令被设置为targeted
。这意味着,默认情况下,SELinux 将仅限制系统中的某些进程(即,仅针对某些进程)。未被针对(targeted)的进程将在不受限制的域中运行。
替代方案是默认拒绝模型,其中除非获得策略批准,否则每次访问都会被拒绝。这将是一个非常安全的实现,但这也意味着开发人员必须预测每个进程在每个可能的对象上可能需要的每个可能的权限。默认行为确认(原文为sees) SELinux 只关注某些进程。
SELinux 策略行为
SELinux 策略并不能取代传统的 DAC 安全性。如果 DAC 规则禁止用户访问文件,则不会评估 SELinux 策略规则,因为第一道防线已阻止访问。在评估 DAC 安全性之后, SELinux 安全决策开始发挥作用。
当启用 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 来限制对文件和进程的访问。
留言