第十七章 Jails和容器

第十七章 Jails和容器17.1. 简介17.2. Jail 类型17.2.1. 厚 Jails17.2.2. 瘦 Jails17.2.3. 服务 Jails17.2.4. VNET Jails17.2.5. Linux Jails17.3. 主机配置17.3.1. Jail 实用程序17.3.2. 网络17.3.3. 设置Jail目录树17.3.4. Jail 配置文件17.4. 经典 Jail(厚 Jail)17.4.1. 创建一个经典Jail17.5. 瘦 Jails17.5.1. 使用OpenZFS快照创建瘦Jail17.5.2. 使用NullFS创建瘦Jail17.5.3. 创建VNET Jail17.5.4. 创建一个Linux Jail17.5.5. 配置服务Jails17.6. Jail 管理17.6.1. 列出运行中的jails17.6.2. 开始、重启和停止Jail17.6.3. 销毁Jail17.6.4. 在Jail中处理包17.6.5. 访问Jail17.6.6. 在Jail中执行命令17.7. Jail升级17.7.1. 使用OpenZFS快照升级经典Jail或瘦Jail17.7.2. 使用NullFS升级瘦Jail17.8. Jail资源限制17.9. Jail管理器和容器

17.1. 简介

由于系统管理是一项艰巨的任务,因此开发了许多工具,使管理员的生活更轻松。这些工具通常会增强系统的安装、配置和维护方式。jails 是可用于增强FreeBSD系统安全性的工具之一。Jails从FreeBSD 4.X开始就可以使用,并且在实用性、性能、可靠性和安全性方面都在不断增强。

Jails基于 chroot(2) 概念构建,该概念用于更改一组进程的根目录。这创造了一个安全的环境,与系统的其他部分分开。在chrooted环境中创建的进程无法访问其外部的文件或资源。因此,破坏在chroote环境中运行的服务不应允许攻击者破坏整个系统。

然而,chroot有几个局限性。它适用于不需要太多灵活性或复杂高级功能的简单任务。随着时间的推移,人们发现了许多逃离chrooted环境的方法,使其成为保护服务的不太理想的解决方案。

Jails在几个方面改进了传统chroot环境的概念。

在传统的chroot环境中,进程仅限于它们可以访问的文件系统部分。其余的系统资源、系统用户、正在运行的进程和网络子系统由chrooted进程和主机系统的进程共享。jails通过虚拟化对文件系统、用户集和网络子系统的访问来扩展这种模式。更细粒度的控制可用于调整jails环境的访问。jails可以被视为一种操作系统级的虚拟化。

本章涵盖:

•什么是jail,它在FreeBSD安装中有什么作用。 •不同类型的jail。 •为jail配置网络的不同方法。 •jail配置文件。 •如何创建不同类型的jail。 •如何启动、停止和重新启动jail。 •jail内外的jail管理基础知识。 •如何升级不同类型的jail。 •不同FreeBSD jail管理者的不完整列表。

17.2. Jail 类型

一些管理员将jail分为不同类型,尽管底层技术是相同的。每个管理员都必须根据他们必须解决的问题,评估在每种情况下创建哪种类型的jail。

下面列出了不同类型、它们的特点和使用注意事项。

17.2.1. 厚 Jails

Tick Jails —— 厚jail,是FreeBSDjail的一种传统形式。在一个厚jail里,基础系统的完整副本被复制到jail的环境中。这意味着jail有自己独立的FreeBSD基础系统实例,包括库、可执行文件和配置文件。jail可以被认为是一个几乎完整的独立FreeBSD安装,但在主机系统的范围内运行。这种隔离确保了jail内的进程与主机和其他jail的进程分开。

厚jail的优点:

厚jail的缺点:

17.2.2. 瘦 Jails

瘦jail使用OpenZFS快照或模板中的NullFS挂载共享基础系统。每个瘦jail只复制基本系统的一小部分,与厚jail相比,资源消耗更少。然而,这也意味着与厚jail相比,瘦jail的隔离性和独立性较低。共享组件的更改可能会同时影响多个瘦jail。

总之,FreeBSD瘦jail是一种FreeBSDjail,它在隔离环境中复制了基础系统的大部分,但不是全部。

瘦 Jails的优点:

瘦 Jails的缺点:

17.2.3. 服务 Jails

serivice jails —— 服务jails,直接与主机共享完整的文件系统树(jail根路径为/),因此可以访问和修改主机上的任何文件,并与主机共享相同的用户帐户。默认情况下,它无法访问网络或jail中限制的其他资源,但可以将其配置为重新使用主机的网络并删除一些jail限制。服务jail的用例是以最小的配置将服务/守护进程自动限制在jail内,并且不知道此类服务/守护程序所需的文件。服务jail自FreeBSD 15以来就存在。

服务 Jails的优点:

服务jail的缺点:

服务jail不需要下文讨论的大多数jail配置。要了解jail是如何工作的,建议了解这些配置的可能性。有关配置服务jail所需内容的详细信息,请参阅【17.5.5. 配置服务jail】。

17.2.4. VNET Jails

FreeBSD VNET jail是一个虚拟化环境,允许隔离和控制其中运行的进程的网络资源。它通过为jail内的进程创建单独的网络堆栈来提供高级别的网络分段和安全性,确保jail中的网络流量与主机系统和其他jail隔离。

本质上,FreeBSD VNETjail增加了一种网络配置机制。这意味着VNETjail可以创建为厚jail或瘦jail。

17.2.5. Linux Jails

FreeBSD Linux Jail是FreeBSD操作系统中的一项功能,它允许在FreeBSD Jail中使用Linux二进制文件和应用程序。此功能是通过包含一个兼容层来实现的,该兼容层允许在FreeBSD内核上翻译和执行某些Linux系统调用和库。Linux Jail的目的是方便在FreeBSD系统上执行Linux软件,而不需要单独的Linux虚拟机或环境。

17.3. 主机配置

在主机系统上创建任何jail之前,有必要执行某些配置并从主机系统获取一些信息。

需要配置 jail(8) 实用程序,创建配置和安装jail所需的目录,从主机的网络获取信息,并检查主机是使用OpenZFS还是UFS作为其文件系统。

17.3.1. Jail 实用程序

jail(8) 实用程序管理jails。

要在系统启动时启动jail,请运行以下命令:

17.3.2. 网络

FreeBSD jail的网络可以通过几种不同的方式配置:

17.3.3. 设置Jail目录树

没有具体的地方可以存放jails的文件。

一些管理员使用 /jail ,另一些使用 /usr/jail ,还有一些使用 /usr/local/jail 。本章将使用 /usr/local/jail

除了 /usr/local/jail 之外,还将创建其他目录:

使用OpenZFS时,执行以下命令为这些目录创建数据集:

使用UFS时,执行以下命令以创建目录:

17.3.4. Jail 配置文件

有两种方法可以配置jails。

第一种方法是在 /etc/jail.conf 文件中为每个jail添加一个条目。另一种方法是为 /etc/jail.conf.d/ 目录中的每个jail创建一个文件。

如果主机系统的jail很少,可以在 /etc/jail.conf 文件中为每个jail添加一个条目。如果主机系统有很多jail,最好在 /etc/jail.conf.d/ 目录中为每个jail设置一个配置文件。

/etc/jail.conf.d/ 中的文件必须以 .conf 作为扩展名,并且必须包含在 /etc/jail.conf 中:

一个典型的jail条目看起来像这样:

jailname —— jail的名称。 exec.start —— 创建jail时在jail环境中运行的命令。一个典型的运行命令是 /bin/sh/etc/rc exec.stop —— 在jail被移除之前在jail环境中运行的命令。一个典型的运行命令是 /bin/sh/etc/rc.shutdown exec.consolelog —— 用于将命令输出(stdout和stderr)定向到的文件。 allow.raw_sockets —— 允许在jail内创建原始套接字。设置此参数允许 ping(8)traceroute(8) 等实用程序在jail内运行。 exec.clean —— 在干净的环境中运行命令。 mount.devfs —— 在chrooted /dev 目录上挂载一个 devfs(5) 文件系统,并应用 devfs_ruleset 参数中的规则集来限制jail内可见的设备。 host.hostname —— jail的主机名。 path —— 作为jail根目录的目录。在jail中运行的任何命令,无论是由jail还是从 jexec(8) 运行,都是从这个目录运行的。 ip4.addr —— IPv4地址。IPv4有两种配置可能性。第一种方法是建立一个IP或IP列表,如示例中所示。另一种方法是使用 ip4 ,并设置 inherit 值以继承主机的IP地址。 ip6.addr —— IPv6地址。IPv6有两种配置可能性。第一种方法是建立一个IP或IP列表,如示例中所示。另一种方法是使用 ip6 ,并设置 inherit 值以继承主机的IP地址。 interface —— 用于添加jail的IP地址的网络接口。通常是主机接口。

关于配置变量的更多信息可以在 jail(8)jail.conf(5) 中找到。

17.4. 经典 Jail(厚 Jail)

这些jail类似于真正的FreeBSD系统。它们可以或多或少地像普通主机系统一样进行管理,并独立更新。

17.4.1. 创建一个经典Jail

原则上,jail只需要一个主机名、根目录、IP地址和用户空间(userland)。

jail的用户空间可以从官方FreeBSD下载服务器获得。

执行以下命令下载用户空间:

下载完成后,需要将内容提取到jail目录中。

执行以下命令将用户区提取到jail的目录中:

在jail目录中提取用户空间后,有必要复制时区和DNS服务器文件:

复制文件后,下一步要做的是通过执行以下命令更新到最新补丁级别:

最后一步是配置jail。有必要在配置文件 /etc/jail.confjail.conf.d 中添加一个包含jail参数的条目。

示例如下:

运行以下命令启动此jail:

有关如何管理jails的更多信息,请参阅【17.6. Jail管理】一节。

17.5. 瘦 Jails

虽然瘦Jails使用与厚Jails相同的技术,但创建过程不同。瘦Jail可以使用OpenZFS快照或使用模板和NullFS创建。使用NullFS的OpenZFS快照和模板比经典jail具有某些优势,例如能够从快照中更快地创建它们,或者能够使用NullFS更新多个jail。

17.5.1. 使用OpenZFS快照创建瘦Jail

由于FreeBSD和OpenZFS之间的良好集成,使用OpenZFS快照创建新的瘦Jails非常容易。

要使用OpenZFS快照创建瘦Jail,第一步是按照【17.3.3. 设置Jail目录树】中的说明创建Jail目录树。

接下来,创建一个模板。模板仅用于创建新jails。出于这个原因,它们是以“只读”模式创建的,因此jail是以不可变的基础创建的。

要为模板创建数据集,请执行以下命令:

然后执行以下命令下载用户空间:

下载完成后,需要通过执行以下命令提取模板目录中的内容:

在模板目录中提取用户空间后,有必要通过执行以下命令将时区和DNS服务器文件复制到模板目录中:

接下来要做的是通过执行以下命令更新到最新补丁级别:

更新完成后,模板就准备好了。

要从模板创建OpenZFS快照,请执行以下命令:

一旦创建了OpenZFS快照,就可以使用OpenZFS 克隆函数创建无限jails。

要创建名为 thinjail 的瘦 Jail,请执行以下命令:

最后一步是配置jail。有必要在配置文件 /etc/jail.confjail.conf.d 中添加一个包含jail参数的条目。

示例如下:

执行以下命令启动jail:

有关如何管理jails的更多信息,请参阅【17.6. Jail管理】一节。

17.5.2. 使用NullFS创建瘦Jail

通过使用瘦Jail技术和使用NullFS选择性地将特定目录从主机系统共享到jail中,可以创建jail,减少系统文件的重复。

第一步是创建数据集以保存模板,如果使用OpenZFS,请执行以下命令:

或者,如果使用UFS:

然后执行以下命令下载用户空间:

下载完成后,需要通过执行以下命令提取模板目录中的内容:

一旦在模板目录中提取了用户空间,就需要通过执行以下命令将时区和DNS服务器文件复制到模板目录中:

将文件移动到模板后,下一步要做的就是通过执行以下命令更新到最新的补丁级别:

除了基础模板外,还需要创建一个 skeleton (骨架)所在的目录。一些目录将从模板复制到 skeleton

如果使用OpenZFS,请执行以下命令为 skeleton 创建数据集:

或者在使用UFS的情况下:

然后创建 skeleton 目录。 skeleton 目录将保存监狱的本地目录。

执行以下命令以创建目录:

下一步是通过执行以下命令创建指向 skeleton 的符号链接:

skeleton 准备就绪后,有必要将数据复制到jail目录。

在使用OpenZFS的情况下,OpenZFS快照可用于通过执行以下命令轻松创建所需数量的jails:

如果使用UFS,可以通过执行以下命令来使用 cp(1) 程序:

然后创建安装基础模板和骨架的目录:

/etc/jail.conf 中添加jail条目或在 jail.conf.d 中添加文件,如下所示:

然后创建 /usr/local/jails/thinjail-nullfs-base.fstab 文件,如下所示:

执行以下命令启动jail:

17.5.3. 创建VNET Jail

FreeBSD VNET Jails有自己独特的网络堆栈,包括接口、IP地址、路由表和防火墙规则。

创建VNET jail的第一步是通过执行以下命令创建 bridge(4)

创建网桥后,有必要将其连接到 em0 接口,并通过执行以下命令将两者都打开:

要使此设置在重新启动后仍然有效,请在 /etc/rc.conf 中添加以下行:

有关桥接的更多信息,请参阅【34.8. 网络桥接】。

下一步是创建如上所述的jail。

可以使用【17.4. 经典Jail(厚Jail)】程序和【17.5. 瘦Jails】程序。唯一会改变的是 /etc/jail.conf 文件中的配置。

路径 /usr/local/jails/containers/vnet 将用作创建的jail的示例。

以下是VNET jail 的示例配置:

① 代表jail的IP,它必须是唯一的。 ② 指之前创建的网桥。

17.5.4. 创建一个Linux Jail

FreeBSD可以使用【12. Linux二进制兼容性】和 deboottrap(8) 在jail中运行Linux。Jails没有内核。它们在主机的内核上运行。因此,有必要在主机系统中启用Linux二进制兼容性。

要在启动时启用Linux ABI,请执行以下命令:

启用后,可以通过执行以下命令在不重新启动的情况下启动它:

下一步将是创建如上所述的jail,例如在【17.5.1. 使用OpenZFS快照创建瘦Jail】中,但不执行配置。FreeBSD Linux Jail需要一个特定的配置,下面将详细介绍。

如上所述创建jail后,执行以下命令以执行jail所需的配置并启动它:

要访问jail,需要安装 sysutils/debootstrap

执行以下命令以访问FreeBSD Linux jail:

在jail中,执行以下命令安装sysutils/deboottrap并准备Ubuntu环境:

当进程完成并且控制台上显示消息“Base system installed successful”时,有必要通过执行以下命令从主机系统停止jail:

然后在 /etc/jail.conf 中为Linux jail添加一个条目:

然后,可以使用以下命令像往常一样启动jail:

可以使用以下命令访问Ubuntu环境:

更多信息可以在【12. Linux二进制兼容性】一章中找到。

17.5.5. 配置服务Jails

服务jail完全通过 /etc/rc.confsysrc(8) 配置。基础系统服务已准备就绪。它们包含一个配置行,可以启用网络或解除jail的其他限制。在jail中运行没有意义的基本系统服务被配置为不作为服务jail启动,即使在 /etc/rc.conf 中启用。此类服务的一些示例是希望在start-of-stop方法中挂载或卸载某些内容的服务,或者只配置路由、防火墙等。

第三方服务可能会也可能不会为jail服务。要检查服务是否已准备就绪,可以使用以下命令:

如果没有输出,则服务未准备好服务jail,或者不需要任何额外的权限,例如网络访问。

如果服务没有准备好服务jail,需要网络访问,可以通过在 /etc/rc.conf 中添加必要的配置来准备好:

有关所有可能的 _svcj_options ,请参阅 rc.conf(5) 手册页。

要为给定的服务启用服务jail,需要停止该服务,并将 servicename_svcj 变量设置为 YES 。要将 syslogd(8) 放入服务jail,请使用以下命令序列:

如果 servicename_svcj 变量被更改,则需要在更改之前停止服务。如果不停止,rc框架将无法检测到服务的正确状态,也无法执行所请求的操作。

服务jail仅通过 rc.conf(5)/sysrc(8)service(8) 命令进行管理。jail实用程序,如【17.6. Jail管理】中描述的 jls(8) ,可用于调查该行动,但 jail(8) 命令不应用于管理它们。

17.6. Jail 管理

一旦创建了jail,就可以执行许多操作,如启动、重新启动或删除jail、在其中安装软件等。本节将介绍主机对jail可以采取的不同行动。

17.6.1. 列出运行中的jails

要列出主机系统上运行的jails,可以使用命令 jls(8)

jls(8) 支持 --libxo 参数,该参数通过 libxo(3) 库允许显示其他类型的格式,如JSON、HTML等。

例如,执行以下命令以获取JSON输出:

17.6.2. 开始、重启和停止Jail

service(8) 用于启动、重新启动或停止主机上的jail。

例如,要启动jail,请运行以下命令:

更改 start 参数以重新启动或停止对jail执行其他操作。

17.6.3. 销毁Jail

销毁jail并不像使用 service(8) 停止jail并删除监狱目录和 /etc/jail.conf 条目那么简单。

FreeBSD非常重视系统安全。因此,有些文件即使是root用户也无法删除。此功能称为文件标志。

第一步是停止所需的jail执行以下命令:

第二步是通过执行以下命令,使用 chflags(1) 删除这些标志,其中 classic 是要删除的jail的名称:

第三步是删除jail所在的目录:

最后,需要删除 /etc/jail.confjail.conf.d 中的jail条目。

17.6.4. 在Jail中处理包

pkg(8) 工具支持 -j 参数,以便处理安装在jail中的包。

例如,要在jail中安装 www/nginx-lite ,可以从主机执行下一个命令:

有关在FreeBSD中使用软件包的更多信息,请参阅【4. 安装应用程序:软件包和Ports】。

17.6.5. 访问Jail

虽然上面已经说过最好从主机系统管理jail,但可以使用 jexec(8) 进入jail。

通过从主机运行 jexec(8) 可以进入监狱:

当进入jail时,将显示 motd(5) 中配置的消息。

17.6.6. 在Jail中执行命令

要从jail中的主机系统执行命令,可以使用 jexec(8)

例如,要停止jail内运行的服务,将执行以下命令:

17.7. Jail升级

升级FreeBSD Jails可确保隔离环境保持安全、最新,并符合FreeBSD生态系统中可用的最新功能和改进。

17.7.1. 使用OpenZFS快照升级经典Jail或瘦Jail

Jails必须从主机操作系统更新。FreeBSD的默认行为是禁止在jail中使用 chflags(1) 。这将阻止某些文件的更新,因此从jail内部进行更新将失败。

要将jail更新到它正在运行的FreeBSD版本的最新补丁版本,请在主机上执行以下命令:

要将jail升级到新的主要或次要版本,请首先按照【26.2.3. 执行主要和次要版本升级】中的说明升级主机系统。一旦主机升级并重新启动,jail就可以升级。

例如,要从13.1-RELEASE升级到13.2-RELEASE,请在主机上执行以下命令:

然后,如果是主要版本升级,请重新安装所有已安装的软件包,然后重新启动jail。这是必需的,因为在FreeBSD的主要版本之间升级时,ABI版本会发生变化。

来自主机:

17.7.2. 使用NullFS升级瘦Jail

由于使用NullFS的瘦Jail共享大部分系统目录,因此它们很容易更新。更新模板就足够了。这允许同时更新多个jail。

要将模板更新到它正在运行的FreeBSD版本的最新补丁版本,请在主机上执行以下命令:

要将模板升级到新的主要或次要版本,请首先按照【26.2.3. 执行主要和次要版本升级】中的说明升级主机系统。一旦主机升级并重新启动,就可以升级模板。

例如,要从13.1-RELEASE升级到13.2-RELEASE,请在主机上执行以下命令:

17.8. Jail资源限制

控制jail从主机系统使用的资源是系统管理员需要考虑的任务。

使用 rctl(8) 管理jail可以从主机系统使用的资源。

限制jail资源的语法如下:

例如,要限制jail可以访问的最大RAM,请运行以下命令:

为了使限制在主机系统重新启动时持续存在,有必要将规则添加到 /etc/rctl.conf 文件中,如下所示:

有关资源限制的更多信息,请参阅【16.14. 资源限制】部分的安全章节。

17.9. Jail管理器和容器

如前所述,每种类型的FreeBSD Jail都可以手动创建和配置,但FreeBSD也有第三方实用程序,使配置和管理更容易。

以下是不同FreeBSD Jail管理器的不完整列表:

表31. Jail管理器

名称许可证文档
BastilleBSDBSD-3sysutils/bastille文档
potBSD-3sysutils/pot文档
cbsdBSD-3sysutils/cbsd文档
AppJailBSD-3sysutils/appjail,
开发版: sysutils/appjaildevel
文档
iocageBSD-2sysutils/iocage文档
ezjailBeer Waresysutils/ezjail文档