17.6.使用 ezjail 管理 Jail ========================== 创建和管理多个 jail 可能很快会变得繁琐且容易出错。Dirk Engling 开发的 ezjail 自动化软件大大的简化了许多 jail 任务。\ *basejail* 被创建为模板。其他 jail 使用 `mount_nullfs(8) `__ 来共享许多 basejail 目录,而无需使用多余的磁盘空间。在安装应用程序之前,每个额外的 jail 仅占用几兆字节的磁盘空间。升级 *basejail* 中用户空间的副本会自动升级所有其他 jail。 其他优点和功能在 ezjail 网站上有详细描介绍:\ https://erdgeist.org/arts/software/ezjail/\ 。 17.6.1.安装 ezjail ------------------ ezjail 的安装包括增加一个环回接口以在 jail 安装 ports 或软件包以及启用服务时使用。 1. 为了保持 jail 环回流量离开主机的环回网络接口 ``lo0``\ ,通过向 **/etc/rc.conf** 添加一个条目来创建第二个环回接口: .. code:: shell-session cloned_interfaces="lo1" 第二个环回接口 ``lo1`` 将在系统启动时创建。也可以手动创建它,而无需重启系统: .. code:: shell-session # service netif cloneup Created clone interfaces: lo1. 可以允许 jail 使用这个二级环回接口的别名而不干扰主机。 在 jail 内,对环回地址 ``127.0.0.1`` 的访问被重定向到分配给 jail 的第一个 IP 地址。为了使 jail 的环回地址与新的 ``lo1`` 接口相对应,在创建新 jail 时,必须首先在接口和 IP 地址列表中指定该接口。 在 ``127.0.0.0/8`` 网块中给每个分配一个 jail 唯一的环回地址。 1. 安装 `sysutils/ezjail `__\ : .. code:: shell-session # cd /usr/ports/sysutils/ezjail # make install clean 1. 通过将这行添加到 **/etc/rc.conf** 来启用 ezjail: .. code:: shell-session ezjail_enable="YES" 1. 该服务将在系统启动时自动启动。它可以立即为当前会话启动: .. code:: shell-session # service ezjail start 17.6.2.初始设置 --------------- 安装 ezjail 后,可以创建和补充 basejail 目录。此步骤仅需要在 jail 主机上执行一次。 在这两个示例中。\ ``-p`` 让用 `portsnap(8) `__ 下载 ports 到 basejail。所有的 jail 都将共享这个 ports 目录的副本。为 jail 使用单独的 ports 目录副本可以将它们与主机隔离。在 ezjailFAQ 中有更详细的解释: http://erdgeist.org/arts/software/ezjail/#FAQ\ 。 1. 用 FreeBSD-RELEASE 来建立 jail 对于基于与主机相匹配的 FreeBSD RELEASE 的 basejail,使用 ``install``\ 。例如,在一台运行 FreeBSD 13-STABLE 的主机上,最新的 FreeBSD-13 RELEASE 版本将被安装在 jail 中: .. code:: shell-session # ezjail-admin install -p 1. 用 ``installworld`` 建立 jail basejail 可以用 ``ezjail-admin update`` 从 ``buildworld`` 在主机上创建的可执行文件安装。 在这个例子中,FreeBSD 10-STABLE 是从源代码构建的。jail 目录被创建。然后执行 ``installworld``\ ,将主机的 **/usr/obj** 安装到 basejail 中: .. code:: shell-session # ezjail-admin update -i -p 默认情况下使用主机的 **/usr/src**\ 。可以用 ``-s`` 和路径指定主机上不同的源目录,或者用 **/usr/local/etc/ezjail.conf** 中的 ``ezjail_sourcetree`` 设置。 .. **技巧** >basejail ports 由其他 jail 共享。但是,下载的 distfile 存储在它们各自的 jail 中。默认情况下,这些文件存储在每个 jail 内的 **/var/ports/distfile** 中。在编译 ports 时,每个 jail 中的 **/var/ports** 也用作工作目录。 **技巧** 默认情况下,使用 FTP 协议下载用于安装 basejail 的软件包。防火墙或代理配置可以阻止或干扰 FTP 传输。HTTP 协议的工作方式不同,可规避这些问题。可以通过在 **/usr/local/etc/ezjail.conf** 中为特定下载镜像站指定完整链接来选择 HTTP: .. code:: shell-session ezjail_ftphost=http://ftp.FreeBSD.org 有关站点列表,请参阅\ `镜像站 `__ 部分。 17.6.3.建立和启动新 Jail ------------------------ 使用 ``ezjail-admin create`` 建立新的 jail。在这些示例中,环回接口 ``lo1`` 按上述方式使用。 示例:建立和启动新 jail 1. 创建 jail,指定名称、要使用的环回和网络接口及其 IP 地址。在此示例中,jail 被命名为 ``dnsjail``\ 。 .. code:: shell-session # ezjail-admin create dnsjail 'lo1|127.0.1.1,em0|192.168.1.50' .. **技巧** 大多数网络服务可以 jail 中正常运行。某些网络服务,最明显的是 `ping(8) `__\ 会使用 *原始网络套接字*\ 。在 jail 中,出于安全考虑,默认情况下禁用原始网络套接字。依赖它们的服务将不起作用。 有时,jail 中确实需要原始套接字。例如,网络监控工具经常使用 `ping(8) `__ 来检查其他计算机的可用性。当 jail 中实际需要原始网络套接字时,可以通过编辑各个 jail 的 ezjail 配置文件 **/usr/local/etc/ezjail/jailname** 来启用它们。修改 ``parameters`` 条目: .. code:: shell-session export jail_jailname_parameters="allow.raw_sockets=1" 请勿启用原始网络套接字,除非 jail 中的服务确实需要它们。 1. 启动 jail: .. code:: shell-session # ezjail-admin start dnsjail 1. 在 jail 中使用控制台: .. code:: shell-session # ezjail-admin console dnsjail jail 正在运行,可以完成其他配置。此时可进行的一般设置包括: 1. 设置 ``root`` 密码 连接到 jail 并设置 ``root`` 用户的密码: .. code:: shell-session # ezjail-admin console dnsjail # passwd Changing local password for root New Password: Retype New Password: 1. 时区配置 可以用 `tzsetup(8) `__ 来设置 jail 的时区。为避免虚假的错误消息,可以注释或删除 **/etc/crontab** 中的 `adjkerntz(8) `__ 条目。此任务使用时区更改来更新计算机的硬件时钟,但不允许 jail 访问该硬件。 1. 域名服务器 在 **/etc/resolv.conf** 中输入域名服务器一行,以便让 DNS 在 jail 中工作。 1. 编辑 **/etc/hosts** 更改地址并将 jail 名称添加到 **/etc/hosts** 中的 ``localhost`` 条目中。 1. 配置 **/etc/rc.conf** 在 **/etc/rc.conf** 中输入配置设置。这很像配置一台完整的计算机。此处未设置主机名和 IP 地址。这些值已由 jail 配置提供。 在配置 jail 后,可以安装为其创建 jail 的应用程序。 **技巧** 某些 port 必须使用特殊选项编译才能在 jail 中使用。例如,网络监控插件软件 `net-mgmt/nagios-plugins `__ 和 `net-mgmt/monitoring `__ 插件都有一个 ``JAIL`` 选项,必须启用该选项才能在 jail 中正常工作。 17.6.4.更新 Jail ---------------- 17.6.4.1.更新操作系统 ~~~~~~~~~~~~~~~~~~~~~ 由于 basejail 的用户空间副本由其他 jail 共享,因此更新 basejail 会自动更新所有其他 jail。可以使用软件源更新或二进制更新。 要从主机上的源代码编译 world,然后将其安装在 basejail 中,请使用: .. raw:: latex \diilbookstyleinputcell .. code:: shell-session # ezjail-admin update -b 如果 world 已经在主机上编译,请使用以下命令将其安装在 basejail 中: .. raw:: latex \diilbookstyleinputcell .. code:: shell-session # ezjail-admin update -i 二进制更新使用 `freebsd-update(8) `__\ 。这些更新与直接运行 `freebsd-update(8) `__ 具有相同的限制。最重要的一点是,只有 -RELEASE 版本的 FreeBSD 可以使用此方法。 用 basejail 将主机的 FreeBSD 版本更新到最新补丁版本。例如,从 RELEASE-p1 更新到 RELEASE-p2。 .. raw:: latex \diilbookstyleinputcell .. code:: shell-session # ezjail-admin update -u 要将 basejail 升级到新版本,请首先按照\ `“执行主要和次要版本升级” `__\ 中所述升级主机系统。升级并重新引导主机后,即可升级 basejail。\ `freebsd-update(8) `__ 无法确定 basejail 中当前安装了哪个版本。因此必须指定原始版本。使用 `file(1) `__ 确定 basejail 中的原始版本: .. raw:: latex \diilbookstyleinputcell .. code:: shell-session # file /usr/jail/basejail/bin/sh /usr/jail/basejail/bin/sh: ELF 64-bit LSB executable, x86-64, version 1 (FreeBSD), dynamically linked, interpreter /libexec/ld-elf.so.1, for FreeBSD 13.0, FreeBSD-style, stripped 现在,使用此命令执行从当前的主机系统版本到 ``13.0-RELEASE`` 的升级: .. raw:: latex \diilbookstyleinputcell .. code:: shell-session # ezjail-admin update -U -s 13.0-RELEASE 更新 basejail 后。必须运行 `mergemaster(8) `__ 来更新每个 jail 的配置文件。 如何使用 `mergemaster(8) `__ 取决于 jail 的目的和可信度。如果 jail 的服务或用户不可信,则 `mergemaster(8) `__ 只能在该 jail 内部运行: **例 32.在不可信的 Jail 上运行** `mergemaster(8) `__ 删除从 jail 的 **/usr/src** 到 basejail 的链接,并在 jail 中创建一个新的 **/usr/src** 作为挂载点。将主机的 **/usr/src** 只读挂载到 jail 的新 **/usr/src** 挂载点上: .. code:: shell-session # rm /usr/jail/jailname/usr/src # mkdir /usr/jail/jailname/usr/src # mount -t nullfs -o ro /usr/src /usr/jail/jailname/usr/src 在 jail 中获取控制台: .. code:: shell-session # ezjail-admin console jailname 在 jail 里运行 ``mergemaster``\ 。然后退出 jail 控制台: .. code:: shell-session # cd /usr/src # mergemaster -U # exit 最后,卸载 jail 的 **/usr/src**\ : .. code:: shell-session # umount /usr/jail/jailname/usr/src .. **例 33.可信 Jail 与** `mergemaster(8) `__ 如果 jail 中的用户和服务是可信的。\ `mergemaster(8) `__ 可以在主机运行: .. code:: shell-session # mergemaster -U -D /usr/jail/jailname **技巧** 在主要版本更新后,建议使用 `sysutils/ezjail `__\ ,以确保你的版本正确。因此,请输入: .. code:: shell-session # pkg-static upgrade -f pkg` 以升级或降级到相应的版本。 17.6.4.2.更新 ports ------------------- 基本系统 jail 中的 port 由其他 Jail 共享。更新 port 的该副本也会为其他 jail 提供更新的版本。 basejail ports 可使用 `portsnap(8) `__ 进行更新: .. raw:: latex \diilbookstyleinputcell .. code:: shell-session # ezjail-admin update -P 17.6.5.控制 Jail ---------------- 17.6.5.1.停止和启动 Jail ~~~~~~~~~~~~~~~~~~~~~~~~ ezjail 在计算机启动时会自动启动 jail。可以使用 ``stop`` 和 ``start`` 手动停止和重新启动 jail: .. raw:: latex \diilbookstyleinputcell .. code:: shell-session # ezjail-admin stop sambajail Stopping jail: sambajail. 默认情况下,jail 在主机启动时自动启动。可以通过 ``config`` 禁用自动启动: .. raw:: latex \diilbookstyleinputcell .. code:: shell-session # ezjail-admin config -r norun seldomjail 这将在下次启动主机时生效。已经运行的 jail 不会停止。 启用自动启动非常相似: .. raw:: latex \diilbookstyleinputcell .. code:: shell-session # ezjail-admin config -r run oftenjail 17.6.5.2.归档和恢复 Jail ~~~~~~~~~~~~~~~~~~~~~~~~ 使用 ``archive`` 来创建一个 **.tar.gz** 的 jail 归档。文件名由 jail 的名称和当前日期组成。归档文件被写入归档目录——**/usr/jail/ezjail_archives**\ 。可以通过在配置文件中设置 ``ezjail_archivedir`` 来选择其他的归档目录。 可以将归档文件作为备份复制到其他位置,也可以使用 ``restore`` 从中恢复现有 jail。可以从存档中创建新的 jail,从而为克隆现有 jail 提供便捷的方法。 关闭 jail 并归档到名为 ``wwwserver`` : .. raw:: latex \diilbookstyleinputcell .. code:: shell-session # ezjail-admin stop wwwserver Stopping jail: wwwserver. # ezjail-admin archive wwwserver # ls /usr/jail/ezjail-archives/ wwwserver-201407271153.13.tar.gz 根据在上一步中创建的归档创建一个名为 ``wwwserver-clone`` 的新 jail。使用 ``em1`` 接口并分配新的 IP 地址以避免与原始 IP 地址冲突: .. raw:: latex \diilbookstyleinputcell .. code:: shell-session # ezjail-admin create -a /usr/jail/ezjail_archives/wwwserver-201407271153.13.tar.gz wwwserver-clone 'lo1|127.0.3.1,em1|192.168.1.51' 17.6.6.完整示例:Jail 中的 BIND ------------------------------- 将 BINDDNS 服务器放入 jail 可以通过隔离来提高安全性。此示例创建一个简单的仅缓存域名服务器。 - jail 将被称为 ``dns1``\ 。 - jail 将使用主机接口 ``re0`` 上的 IP 地址 ``192.168.1.240``\ 。 - 上游 ISP 的 DNS 服务器位于 ``10.0.0.62`` 和 ``10.0.0.61``\ 。 - 如\ `初始设置 `__\ 中所示,已经创建 basejail,并且安装了 ports。 .. 例 34.在 jail 中运行 BIND 通过向 **/etc/rc.conf** 添加一行来创建克隆的环回接口: .. code:: shell-session cloned_interfaces="lo1" 立即创建新的环回接口: .. code:: shell-session # service netif cloneup Created clone interfaces: lo1. 创建 jail: .. code:: shell-session # ezjail-admin create dns1 'lo1|127.0.2.1,re0|192.168.1.240' 启动 jail,连接到在其上运行的控制台,然后执行一些基本配置: .. code:: shell-session # ezjail-admin start dns1 # ezjail-admin console dns1 # passwd Changing local password for root New Password: Retype New Password: # tzsetup # sed -i .bak -e '/adjkerntz/ s/^/#/' /etc/crontab # sed -i .bak -e 's/127.0.0.1/127.0.2.1/g; s/localhost.my.domain/dns1.my.domain dns1/' /etc/hosts 在 **/etc/resolv.conf** 中临时设置上游 DNS 服务器,以便可以下载 ports: .. code:: shell-session nameserver 10.0.0.62 nameserver 10.0.0.61 仍使用 jail 控制台,安装 `dns/bind99 `__\ 。 .. code:: shell-session # make -C /usr/ports/dns/bind99 install clean 通过编辑 **/usr/local/etc/namedb/named.conf** 来配置域名服务器。 创建允许向此域名服务器发送 DNS 查询的地址和网络的访问控制列表(ACL)。此部分将添加到文件中已有的 ``options`` 部分之前: .. code:: shell-session ... // or cause huge amounts of useless Internet traffic. ... // or cause huge amounts of useless Internet traffic. acl "trusted" { 192.168.1.0/24; localhost; localnets; }; options { ... 在 ``listen-on`` 设置中使用 jail 的 IP 地址来接受来自网络上其他计算机的 DNS 查询: .. code:: shell-session listen-on { 192.168.1.240; }; 通过更改 ``forwarders`` 该部分来创建一个简单的仅缓存 DNS 域名服务器。原始文件包含: .. code:: shell-session /* forwarders { 127.0.0.1; }; */ 通过删除 ``/*`` 和 ``*/`` 行来取消注释该部分。输入上游 DNS 服务器的 IP 地址。紧跟在 ``forwarders`` 部分之后,添加对前面定义的 ``trusted`` ACL 的引用: .. code:: shell-session forwarders { 10.0.0.62; 10.0.0.61; }; allow-query { any; }; allow-recursion{ trusted; }; allow-query-cache { trusted; }; 在 **/etc/rc.conf** 中启用该服务: .. code:: shell-session named_enable="YES" 启动并测试域名服务器: .. code:: shell-session # service named start wrote key file "/usr/local/etc/namedb/rndc.key" Starting named. # /usr/local/bin/dig @192.168.1.240 freebsd.org 响应包括 .. code:: shell-session ;; Got answer; 表明新的 DNS 服务器正在工作。长时间延迟后出现响应,例如 .. code:: shell-session ;; connection timed out; no servers could be reached 表明发生错误。请检查配置设置,并确保任何本地防火墙允许对上游 DNS 服务器进行新的 DNS 访问。 新的 DNS 服务器可以像其他本地计算机一样,将自身用于本地域名解析。在客户端计算机的 **/etc/resolv.conf** 中设置 DNS 服务器的地址: .. code:: shell-session nameserver 192.168.1.240 可以将本地 DHCP 服务器配置为为本地 DNS 服务器提供此地址,从而在 DHCP 客户端上提供自动配置。