17.3.主机配置
在宿主系统上创建任何 jail 之前,必须做一些配置,并获取宿主系统的一些信息。
这包括配置 jail(8) 工具、创建用于配置和安装 jail 的必要目录、获取宿主系统的网络信息,以及检查宿主是否使用 OpenZFS 或 UFS 作为文件系统。
技巧
jail 中运行的 FreeBSD 版本不得高于宿主系统运行的版本。
17.3.1. jail 工具
jail(8) 工具用于管理 jail。
若要在系统启动时自动启动 jail,执行以下命令:
# sysrc jail_enable="YES"
# sysrc jail_parallel_start="YES"技巧
启用
jail_parallel_start后,所有已配置的 jail 将在后台同时启动。
默认情况下,配置文件中有条目的每个 jail 都会在系统启动时启动。如果只想启动选定的 jail,可在 jail_list 中列出它们的名称:
# sysrc jail_list="www db"jail_list 中的名称以空格分隔,必须与 /etc/jail.conf 或 /etc/jail.conf.d/ 中定义的 jail 名称匹配。只有列表中的 jail 会在启动时启动,并按给定顺序启动,因此未在 jail_list 中的 jail 必须手动启动。当 jail_list 为空时,配置文件中定义的所有 jail 都会启动。
要在关机时按 jail_list 的相反顺序停止 jail,可设置 jail_reverse_stop:
# sysrc jail_reverse_stop="YES"注意
启用
jail_parallel_start后,jail 在后台启动,jail_list的顺序不再得到保证。当某个 jail 必须在另一个 jail 启动之前运行时,请在 /etc/jail.conf 中使用depend参数来表达这种依赖关系,而不是依赖列表顺序。jail 的依赖会在其启动之前自动创建,并在其停止时以相反顺序停止,这与jail_list无关。depend参数将在 jail 配置文件 一节中介绍。
17.3.2. 网络
FreeBSD jail 的网络可通过几种不同的方式配置:
宿主网络模式(IP 共享) 在宿主网络模式中,jail 共享宿主的网络协议栈,而不是获得自己的协议栈。共享协议栈并不意味着共享地址:常见做法是为 jail 分配独立的 ip4.addr(和 ip6.addr),由 jail(8) 作为别名添加到宿主接口上,因此 jail 和宿主在同一协议栈上通过不同地址应答。只有配置为 ip4 = inherit 的 jail 才会完整共享宿主的地址,应答宿主自己的地址,并无限制地访问宿主持有的所有地址。
虚拟网络(VNET) 虚拟网络是 FreeBSD jail 提供的高级网络功能,比基础的宿主网络模式更灵活。VNET 能为每个 jail 创建独立的网络协议栈,为其分配独立的 IP 地址、路由表和网络接口。这提供了更高程度的网络隔离,使 jail 的运行行为更像是独立的虚拟机。
netgraph 系统 netgraph(4) 是通用的内核框架,用于创建自定义网络配置。它可用于定义 jail 与宿主之间、以及多个 jail 之间网络流量的流向方式。
17.3.2.1. jail 的 IP 地址来源
共享协议栈的 jail 通过宿主接口上的地址访问网络。interface 参数指定该接口,对于 ip4.addr 和 ip6.addr 中的每个地址,jail(8) 都会自行管理别名:正如 jail(8) 所述,“在创建 jail 之前,会为每个地址在接口上添加一个别名,并在移除 jail 之后从接口上移除该别名”。宿主上无需预先配置该地址。
也可以按地址指定接口,从而用一行将地址与承载它的接口绑定:
当地址必须独立于 jail 持久存在时——因为宿主上的另一个服务依赖它,或者因为未使用 interface 参数——可在宿主上将其配置为 rc.conf 别名,不交给 jail(8) 管理:
较早的编号形式 ifconfig_em0_alias0="inet 192.168.1.151/32" 仍然可用,但对于新配置,推荐使用 _aliases 形式,因为它避免了编号别名必须形成连续 alias0、alias1、alias2 序列这种脆弱的要求。
17.3.2.2. 共享 IP jail 中的回环地址
共享协议栈的 jail 没有自己的回环接口。FreeBSD 内核对此做了补偿:在非 VNET jail 中,只要 127.0.0.1 或 ::1 本身不是 jail 自己的地址之一,内核就会将回环地址上的 bind() 和 connect() 静默改写为 jail 的第一个 ip4.addr 或 ip6.addr。此行为未在 jail(8) 中记录,但它很重要,因为它带有安全隐患。
警告
不要以为将服务绑定到
localhost就能将其限制在 jail 内部。在共享 IP jail 中,被告知监听127.0.0.1的守护进程实际上绑定的是 jail 的第一个地址,这通常是面向局域网的地址,因此可从网络访问。
标准的缓解方法是给 jail 分配一个私有的回环地址并将其列在首位。在宿主上克隆一个专用的回环接口,并为其分配 127.0.0.0/8 范围内的地址(或私有 RFC 1918 地址):
然后将该地址列在 jail 的 ip4.addr 中的首位,位于任何可路由地址之前,这样回环改写就会落到私有地址而非面向局域网的地址上。
17.3.2.3. 准备宿主服务
每个 jail 别名地址都共享宿主的端口。因此,绑定到通配符地址(在监听器列表中显示为 *:port)的宿主守护进程也会监听每个 jail 别名,并在 jail 自己的服务可以占用该端口之前就将其占用。在启动任何 jail 之前,先审计宿主已监听的内容:
限制每个绑定通配符地址的守护进程,使其仅使用宿主自己的地址,将 jail 地址留空:
syslogd(8):在 /etc/rc.conf 中设置
syslogd_flags="-ss"。单个-s已经使 syslogd 以安全模式运行,不监听远程日志消息;根据 syslogd(8),如果指定两次-s,“将完全不打开网络套接字”,这同时也会阻止 syslogd 向远程主机发送消息。sshd(8):在 /etc/ssh/sshd_config 中将
ListenAddress固定到宿主的地址,而不是保留默认的通配符。ntpd(8) 和 sendmail(8):通过它们各自的配置将它们绑定到宿主地址。
关于哪些地址可由 jail 使用的防火墙级控制,请参见 防火墙 一章。
17.3.3. 设置 jail 目录结构
jail 的文件不需要放在特定路径。
有些管理员使用 /jail,有些使用 /usr/jail,也有些使用 /usr/local/jails。本章将使用 /usr/local/jails。
除了 /usr/local/jails,还将创建以下目录:
media:用于存放下载的用户空间压缩包。
templates:使用瘦 jail 时用于存放模板。
containers:用于存放各个 jail。
如果使用 OpenZFS,执行以下命令为这些目录创建数据集:
技巧
此处使用
zroot作为父数据集,也可使用其他数据集。
为每个 jail 创建单独的子数据集,是实现每个 jail 独立快照、克隆、配额和数据集委托的基础。由于每个 jail 目录都是独立的数据集,OpenZFS 可以使用 quota 和 reservation 属性为其磁盘使用设置上限和保证;参见 jail 资源限制。
如果使用 UFS,执行以下命令创建这些目录:
17.3.4. jail 配置文件
配置 jail 有两种方式。
第一种是在 /etc/jail.conf 文件中为每个 jail 添加条目。另一种方式是在 /etc/jail.conf.d/ 目录中为每个 jail 创建独立的配置文件。
如果宿主系统上只运行少量 jail,可直接将每个 jail 的配置写入 /etc/jail.conf 文件。若宿主系统上运行多个 jail,建议在 /etc/jail.conf.d/ 目录下为每个 jail 分别创建配置文件。
/etc/jail.conf.d/ 中的文件必须使用 .conf 作为扩展名,并且需要在 /etc/jail.conf 中通过以下语句引入:
典型的 jail 配置条目如下:
①
jailnamejail 的名称。②
exec.start在 jail 创建时运行的命令。常见写法为/bin/sh /etc/rc。③
exec.stop在移除 jail 前运行的命令。常见写法为/bin/sh /etc/rc.shutdown。④
exec.consolelog用于记录命令输出(stdout 和 stderr)的日志文件路径。⑤
allow.raw_sockets能在 jail 中创建原始套接字。启用后,可在 jail 中使用如 ping(8) 与 traceroute(8) 等工具。⑥
exec.clean在干净的环境中运行命令。⑧
host.hostnamejail 的主机名。⑨
pathjail 的根目录路径。通过jail或 jexec(8) 执行的命令均在该目录下运行。⑩
ip4.addr分配给 jail 的一个 IPv4 地址,或以逗号分隔的地址列表。设置ip4.addr隐含了ip4 = new;ip4本身不会保留为独立的默认值。ip4参数接受三个值:new将 jail 限制为ip4.addr中列出的地址,inherit让 jail 无限制地访问宿主的所有 IPv4 地址,disable完全关闭 jail 中的 IPv4。未设置ip4或ip4.addr的 jail 行为类似于inherit,此时interface和ip4.addr在inherit下无效。在有多个地址的 jail 中,ip4.saddrsel让内核为未绑定套接字的出站连接选择源地址,而ip4.nosaddrsel强制使用列表中的第一个地址。⑪
ip6.addr分配给 jail 的一个 IPv6 地址,或以逗号分隔的地址列表。ip6参数接受与ip4相同的new、inherit和disable值,ip6.saddrsel和ip6.nosaddrsel控制源地址选择。对于仅 IPv4 的 jail,使用ip6 = disable;对于仅 IPv6 的 jail,使用ip4 = disable。⑫
interface用于添加 jail IP 地址的网络接口,通常为宿主系统的接口名。
注意
jail 没有虚拟控制台:init(8) 和 getty(8) 不会在其中运行,因此没有可交互连接的对象。
exec.consolelog文件仅捕获exec.*命令的标准输出和标准错误,即 /etc/rc 启动脚本和 /etc/rc.shutdown 脚本的输出。它不是交互式控制台;如需交互,可使用 jexec(8)(参见 访问 jail)或在 jail 内运行 sshd(8)。jail 自己的守护进程会将后续输出发送到 jail 的 syslog。
技巧
exec.consolelog文件会无限增长。可通过 newsyslog(8) 添加单个 glob 条目来轮转,例如在 /etc/newsyslog.conf.d/jail 中:
17.3.4.1. 全局设置、通配符和变量
在任何 jail 块之外设置的参数是通配符默认值:jail.conf(5) 会将它们应用于每个 jail,就像写在 * 通配符节中一样。一次性设置共享参数可使每个 jail 块保持简短。
以美元符号开头、可选地用大括号括起的名称,会被替换为该参数或变量的值。内置的 ${name} 会展开为 jail 自己的名称,自定义变量的定义方式与参数相同,但以美元符号开头。
以下 /etc/jail.conf 一次性定义了公共头信息,并仅覆盖每个 jail 不同的部分:
此处 www 继承了头信息中的所有内容,仅设置了自己的地址,而 db 还覆盖了 host.hostname。
17.3.4.2. 命令钩子
jail(8) 通过一系列生命周期钩子来运行 jail,每个钩子是在宿主环境还是在 jail 内部运行都很重要。创建顺序为:
exec.prestart 在创建 jail 之前于宿主环境运行。 exec.created 在 jail 已存在但尚未启动任何进程之前于宿主环境运行。 exec.start 在 jail 内部运行,通常为 /bin/sh /etc/rc 以启动其服务。 exec.poststart 在 jail 启动之后于宿主环境运行。
关闭时运行的是镜像过程:
exec.prestop 在停止 jail 之前于宿主环境运行。 exec.stop 在 jail 内部运行,通常为 /bin/sh /etc/rc.shutdown。 exec.poststop 在 jail 停止之后于宿主环境运行,用于拆除 exec.prestart 设置的内容。
可通过 += 为一个钩子分配多个命令:
exec.timeout 限制了 jail(8) 等待命令完成的时间,exec.consolelog 捕获这些命令的输出。VNET jail 一节使用 exec.prestart 和 exec.poststop 在宿主上构建和拆除每个 jail 的网络管道。
钩子在单个 jail 内部为命令排序,而 depend 参数则为整个 jail 排序。写入 depend = otherjail; 可告知 jail(8) 该 jail 需要 otherjail:依赖项会在此 jail 创建之前首先创建,直到其最后一个 exec.poststart 命令完成,并且这些 jail 会以相反顺序拆除。
17.3.4.3. devfs 规则集
每个设置 mount.devfs 的 jail 都会获得一个 devfs 规则集,用于决定其 /dev 下出现哪些设备节点,该规则集要么是 devfs_ruleset 参数指定的,要么在该参数未设置时使用 mount.devfs 的默认规则集 4。devfs.rules(5) 在 /etc/defaults/devfs.rules 中定义命名规则集。其中两个面向 jail:devfsrules_jail(规则集 4)是标准的 jail 最小设备集,devfsrules_jail_vnet(规则集 5)额外暴露 /dev/pf,使 VNET jail 可以运行自己的防火墙。VNET jail 示例设置 devfs_ruleset = 5,Linux jail 示例设置 devfs_ruleset = 4;传统 jail 和瘦 jail 示例仅设置 mount.devfs,因此使用其默认的规则集 4。
要暴露额外设备,可在 /etc/devfs.rules 中编写自定义规则集,包含一个标准规则集并取消隐藏所需设备。以下规则集从 devfsrules_jail 开始,并额外取消隐藏 bpf(4) 设备:
重新加载规则,然后在 jail 配置中按编号引用新规则集:
/etc/devfs.rules 中的规则集会覆盖 /etc/defaults/devfs.rules 中同号的规则集;否则这两个文件将有效合并。
关于配置变量的更多信息,可参考 jail(8) 与 jail.conf(5)。
最后更新于