UP | HOME

Qjail

Table of Contents

Jail 管理工具对比

Qjail 是用于部署 Jail 环境的封装工具,提供了安全性和性能增强功能

本节部署的 Jail 的概念结构如下图所示:

qjail.png

预留 Jail 的 IP 地址:网络接口配置

在 /etc/rc.conf 文件中添加如下配置。克隆接口 lo1 可将 Jail 网络和宿主机网络配置分开,增强隔离性

cloned_interfaces="lo1"  # 克隆出 lo1,应和宿主机网络配置分离 ①
ifconfig_lo1_alias0="inet 192.168.1.1/28" # 创建独立网段,共 14 个 IP 可供分配。需要根据实际网络环境调整地址范围
如果要生成多个接口,应在同一行中以空格分隔描述,而不是另外创建多行,应为 cloned_interfaces="lo1 lo2"

分行书写时,仅第一行生效

重启所有网络接口以应用配置:

$ service netif restart

lo1 将获得 14 个 IP 地址,均可用于分配给各个 Jail

安装 Qjail 工具

  • 使用 pkg 安装 Qjail:

    $ pkg install qjail
    
  • 使用 Ports 安装:

    $ cd /usr/ports/sysutils/qjail/
    $ make install clean
    

设置 qjail 服务开机自启动:

$ sysrc qjail_enable=YES

部署 Qjail 使用的目录结构

使用 Qjail 前,需部署其目录结构,有以下两种方式:

从官方镜像站自动下载

$ qjail install

此时 Qjail 将从 FreeBSD 官网下载 base.txz 文件,示例输出如下:

$ qjail install
resolving server address: ftp.freebsd.org:80
requesting http://ftp.freebsd.org/pub/FreeBSD/releases/amd64/amd64/15.0-RELEASE/base.txz
remote size / mtime: 195363380 / 1652346155
...

方法二:从境内镜像站下载

境内网络访问受限时,可使用镜像站手动下载,以中国科学技术大学开源镜像站为例

使用 freebsd-version 命令可确认宿主机的 FreeBSD 版本,Qjail 要求文件版本与宿主机一致

以下示例为 FreeBSD amd64 15.0:

从镜像服务器下载 FreeBSD 基本系统文件:

$ fetch https://mirrors.ustc.edu.cn/freebsd/releases/amd64/15.0-RELEASE/base.txz

使用 qjail 安装基本系统到指定 Jail:

$ qjail install base.txz

部署 Qjail 的目录结构后,/usr/jails 目录下会自动生成 sharedfstemplatearchiveflavors 四个目录,这四个目录构成了 Qjail 的核心文件系统架构:

Table 1: Qjail 目录结构
目录 说明
sharedfs 包含一份 只读的 操作系统可执行文件库 ,通过 nullfs 在各 Jail 之间共享以节省存储空间。nullfs 是 FreeBSD 提供的特殊文件系统,可在同一主机的不同位置重复挂载同一文件系统
template 包含操作系统的 配置文件模板 ,将被复制到每个 Jail 的基本文件系统中,作为新 Jail 的初始配置
archive 保存 Jail archive 命令产生的 存档 文件,用于 Jail 的备份与恢复
flavors 包含 系统风格 flavors 和用户创建的自定义风格,本质上是预定义的配置文件集合,用于快速定制新 Jail 的配置

文件结构:

/usr/jails/
├── sharedfs/         # 只读操作系统库(各 Jail 共享)
├── template/         # 配置文件模板
├── archive/          # Jail 存档文件
├── flavors/          # 系统风格配置
│   └── default/
│       └── usr/
│           └── local/
│               └── etc/
│                   └── pkg/
│                       └── repos/
│                           └── FreeBSD.conf  # 自定义 pkg 镜像配置
├── jail1/            # jail1 的根目录
└── jail2/            # jail2 的根目录
    └── usr/
        └── local/
            └── etc/
                └── pkg/
                    └── repos/
                        └── FreeBSD.conf  # 自动复制的配置

部署 Jail

创建 Jail jail1,指定网络接口和 IPv4 地址:

$ qjail create -n lo1 -4 192.168.1.1 jail1
  • -n 指定使用 lo1 作为网络接口
  • -4 指定 IPv4 地址
生成 jail1 后,/usr/jails/ 目录下将创建 jail1 目录(/usr/jails/jail1/)用于保存对应文件

可在前述 flavors 目录中创建自定义配置文件,以便部署新 Jail 时自动复制。例如,新建 /usr/jails/flavors/default/usr/local/etc/pkg/repos/FreeBSD.conf 文件,则之后创建的 Jail 将自动复制该文件:

$ qjail create -n lo1 -4 192.168.1.2 jail2

建立 jail2 后,自动生成 /usr/jails/jail2/usr/local/etc/pkg/repos/FreeBSD.conf 文件,即修改了此后所有 Jail 的默认 pkg 镜像

但由于生成 jail1 时尚未在 flavors 目录中写入相应文件,jail1 未生成该文件

Qjail 基本用法

Qjail 管理的 Jail 本质上仍是标准的 FreeBSD Jail,因此 jls、jexec 等系统命令同样可用于查看和操作这些 Jail

以下为 Qjail 专属管理命令:

  • 列出 Qjail 管理的 Jail:

    $ qjail list 
    
  • 启用 Jail:

    $ qjail start # 启动所有 Jail
    $ qjail start jail1 # 启动 jail1
    
  • 停止 Jail:

    $ qjail stop # 停止所有 Jail
    $ qjail stop jail1 # 停止 jail1
    
  • 重启 Jail:

    $ qjail restart # 重启所有 Jail
    $ qjail restart jail1 # 重启 jail1
    
  • 进入 Jail 控制台:

    $ qjail console jail1
    
    进入 Jail 控制台后,将以 Jail 中的 root 账户身份操作(无需输入密码)
    
    由于 Jail 可能开启对外服务,为安全起见,建议设置 root 账户密码
    
  • 备份 Jail:

    $ qjail archive -A  # 备份所有 Jail
    $ qjail archive jail1  # 备份 jail1
    
  • 从备份中恢复 Jail:

    $ qjail restore jail1
    
  • 删除 Jail:

    $ qjail delete jail1  # 删除 jail1
    $ qjail delete -A     # 删除所有 Jail
    

更新 Jail

由于这些文件通过 nullfs 共享一份,Jail 的部分更新并非针对单个 Jail,而是针对所有 Jail

更新 Jail 中的基本系统

更新 sharedfs 中的文件:

$ qjail update -b

更新 ports

选项 -P(大写)使用宿主机的 Ports 更新 Jail 的 Ports 树

$ qjail update -P

更新系统源代码

$ qjail -S # S 大写

更新过程

完整的更新流程如下:

  1. 获取并安装 FreeBSD 系统更新:

    $ freebsd-update fetch
    $ freebsd-update install
    
  2. 停止所有 qjail Jail:

    $ qjail stop
    
  3. 更新 qjail:

    $ qjail update -b
    $ qjail update -S
    $ qjail update -P
    
  4. 启动所有 qjail Jail:

    $ qjail start 
    

Jail 设置

Qjail 提供 qjail config 命令,用于定制每个 Jail 的配置

Jail 运行时核心配置参数无法安全修改,执行该命令前必须先停止目标 Jail

qjail config 命令提供丰富的配置选项,以下列出几个常用参数:

  • -h 为 jail1 快速配置 SSH 服务

    $ qjail config -h jail1
    
    该命令可快速启用 jail1 的 SSH 服务,新建一个 wheel 组用户,用户名和密码均与 jail1 名称相同
    
    首次使用该用户登录时,系统将要求修改密码。也可在登录 jail1 控制台后,自行配置 sshd 服务
    
  • -m、-M 设置 jail1 为手动启动状态:

    $ qjail config -m jail1
    
    • -m 将 jail1 设为手动启动状态(manual 状态)

      qjail_enable="YES" 写入 /etc/rc.conf 文件后,系统启动时将自动启动各个 Jail
      
      设为手动启动后,系统启动时不会自动启动相应 Jail,必须使用 qjail start jailname 手动启动
      
    • 大写的 -M 选项,用于关闭手动启动状态,即清除 manual 状态,可在系统启动时自动启用 Jail

      Qjail 中有大量类似选项,小写字母启用某个功能,大写字母关闭对应功能
      
      下文同时出现小写和大写选项时不再说明
      
  • -r、-R 将 jail1 设为不允许启动(norun 状态):

    $ qjail config -r jail1
    
    该配置相当于禁用 jail1
    
  • -y、-Y 启用 jail1 的 System V IPC(进程间通信)机制:

    $ qjail config -y jail1
    
    在 jail1 中部署 PostgreSQL 等依赖共享内存和信号量的应用时,必须启用该选项
    

网络设定

部分教程提及使用 qjail config -k jailname 启用 raw_sockets 功能以实现外网访问,此系常见误解

raw_sockets 仅为 ping 等工具所需,并非网络访问的必要条件

在 Jail 中启用 raw_sockets 存在安全风险,此为 Jail 环境默认的安全设计

除非确实需要在 Jail 中使用 ping 等工具,否则不宜启用 raw_sockets 功能

该 Jail 绑定在 lo1 网络接口上,lo1 无法直接访问外网,因此此时 Jail 仍无法连接外部网络,需借助 PF 配置网络,其中 em0 为外网接口

使用 ifconfig 命令可查找系统中的外网接口名称

/etc/pf.conf 文件中写入配置。网络地址转换 NAT 可让 Jail 访问外部网络,端口重定向可让外部网络访问指定 Jail 的服务:

rdr pass on em0 inet proto tcp from any to em0 port 22 -> 192.168.1.1 port 22 # 端口重定向:将 em0 上 22 端口的 TCP 连接转发到 192.168.1.1(jail1)的 22 端口
nat pass on em0 inet from lo1:network to any -> (em0)
上述 rdr pass 规则会将所有进入 em0 接口 22 端口的流量重定向到 jail1

如果宿主机也通过 em0 提供 SSH 服务,将导致无法通过 SSH 访问宿主机

建议将重定向的目标端口或外部端口修改为非 22 端口(例如将外部端口改为 2222:rdr pass on em0 inet proto tcp from any to em0 port 2222 -> 192.168.1.1 port 22)

或在规则中添加排除宿主机的条件,以避免宿主机的 SSH 服务被遮蔽

启动防火墙服务:

$ service pf enable
$ service pf start
此时,绑定在 lo1 上的 jail 可访问外部网络,外部网络可通过宿主机的 22 号端口连接 jail1 的 22 号端口

示例:部署 PostgreSQL Jail

已按前述步骤预留 Jail IP 并成功运行 qjail install 命令后,以 PostgreSQL 15 为例进行部署,其他版本也适用

宿主机中操作

创建并配置 PostgreSQL Jail:

  1. 创建 jail postgres,绑定到 lo1 接口,IPv4 地址为 192.168.1.3:

    $ qjail create -n lo1 -4 192.168.1.3 postgres
    
  2. 配置 postgres jail,启用 SysV IPC:

    $ qjail config -y postgres
    
  3. 启动 postgres jail:

    $ qjail start postgres
    
  4. 编辑 /etc/pf.conf 文件:

    nat pass on em0 inet from lo1:network to any -> (em0)
    rdr pass on em0 inet proto tcp from any to em0 port 5432 -> 192.168.1.3 port 5432
    
    直接向外提供 PostgreSQL 连接存在安全风险,应根据实际需要谨慎开启端口转发
    
  5. 启动防火墙服务 PF:

    $ service pf start
    
  6. 进入 jail postgres 的控制台:

    $ qjail console postgres
    

Jail 控制台中的操作

以下命令均在 Jail 控制台内运行,pkg 安装时可根据需要使用镜像

若使用镜像,可在 Jail 控制台中以和宿主机相同的方式设置,详见相关章节

配置 PostgreSQL 数据集

安装 PostgreSQL 的过程略去,详见本书其他章节

设置 PostgreSQL 服务开机自启动:

# service postgresql enable

创建 PostgreSQL 数据目录(注意版本号):

# mkdir -p -m 0700 /var/db/postgres/data15

设置数据目录属主为 postgres 用户:

# chown postgres:postgres /var/db/postgres/data15

切换到 postgres 用户:

# su postgres

初始化 PostgreSQL 数据库:

$ initdb -A scram-sha-256 -E UTF8 -W -D /var/db/postgres/data15
此处使用 initdb 而非安装时提示的 /usr/local/etc/rc.d/postgresql initdb

目的是避免在设置数据库密码时反复修改 pg_hba.conf 文件

对各选项简要说明如下:

选项 说明
-A 为本地用户指定在 pg_hba.conf 中使用的默认认证方法
-E 选择模板数据库的编码
-W 使 initdb 提示为数据库超级用户设置口令
-D 指定数据库集簇应该存放的目录

回到 jail root 用户:

$ exit

立即启动 PostgreSQL 服务:

# service postgresql start
Next: Linux Jail Previous: 厚 Jail Home: Jail 容器管理