FreeBSD VNET Jail

FreeBSD VNET Jail是一种 虚拟化 环境,对其中运行的进程的网络资源进行隔离和控制:

  • 通过对VNET Jail创建单独的网络堆栈,确保Jail内网络流量与主机系统和其他Jail隔离

  • 确保高级别网络隔离和安全性

  • 可以为VNET Jail创建成 FreeBSD Thick(厚) JailFreeBSD Thin(薄) Jail

VNET Jail是一种专门针对网络的Jail,可以补充 thick jailthin jail 的不足

创建bridge

创建VNET Jail的第一步是创建一个网桥(bridge):

创建 bridge
ifconfig bridge create

通常输出显示(如果系统中还没有创建过brideg):

创建 bridge 输出显示生成了 bridge0
bridge0

备注

我的 MacBook Pro 15" Late 2013 使用 FreeBSD无线网络BCM43602(通过wifibox) wifibox 实际上就是一个 bridge ,所以这步创建bridge我跳过,后续的Jail网卡是 addmwifibox0 这个网桥上的。

创建网桥 bridge 之后,需要使用以下命令将其附加到物理网卡上,假设物理主机的有线网卡是 em0 则执行:

将策划构建的 bridge 附加到物理网卡
ifconfig bridge0 addm em0

为了能够在操作系统重启之后自动启动网桥,需要在 /etc/rc.conf 配置:

/etc/rc.conf 中配置网桥
defaultrouter="192.168.1.1"
cloned_interfaces="bridge0"
ifconfig_bridge0="inet 192.168.1.150/24 addm em0 up"

备注

由于 FreeBSD无线网络BCM43602(通过wifibox) 已经包含了上述步骤,所以我的 MacBook Pro 15" Late 2013 不需要上述步骤。

后续实践步骤将在 wifibox0 这个网桥上进行,是我的实践案例,其中网段是 10.0.0.x

配置Jail

VNET Jail 只是在网络堆栈有特殊配置,其他部分和 FreeBSD Thick(厚) Jail / FreeBSD Thin(薄) Jail 是一样的,所以这里需要配置一个 Jail 可以是Thick也可以是Thin,甚至可以结合 FreeBSD Linux Jail

我的实践步骤在 FreeBSD Linux Jail d2l 上进行,也就是我已经完成了 d2l 这个Linux Jail配置和运行,现在来构建VNET部分:

FreeBSD Linux Jail 添加 VNET 配置
d2l {
  # 这里 devfs_ruleset 和Linux Jail的4不同
  devfs_ruleset=5;
  # 去除了 ip4.addr 配置

  # VNET/VIMAGE
  vnet;
  vnet.interface = "${epair}b";

  # NETWORKS/INTERFACES
  $id = "9";
  $ip = "10.0.0.${id}/24";
  $gateway = "10.0.0.1";
  $bridge = "wifibox0"; 
  $epair = "epair${id}";

  # ADD TO bridge INTERFACE
  exec.prestart += "ifconfig ${epair} create up";
  exec.prestart += "ifconfig ${epair}a up descr jail:${name}";
  exec.prestart += "ifconfig ${bridge} addm ${epair}a up";
  exec.start    += "ifconfig ${epair}b ${ip} up";
  exec.start    += "route add default ${gateway}";
  exec.poststop = "ifconfig ${bridge} deletem ${epair}a";
  exec.poststop += "ifconfig ${epair}a destroy";
  
  # MOUNT
  mount += "devfs     $path/compat/debian/dev     devfs     rw  0 0";
  mount += "tmpfs     $path/compat/debian/dev/shm tmpfs     rw,size=1g,mode=1777  0 0";
  mount += "fdescfs   $path/compat/debian/dev/fd  fdescfs   rw,linrdlnk 0 0";
  mount += "linprocfs $path/compat/debian/proc    linprocfs rw  0 0";
  mount += "linsysfs  $path/compat/debian/sys     linsysfs  rw  0 0";
  mount += "/tmp      $path/compat/debian/tmp     nullfs    rw  0 0";
  mount += "/home     $path/compat/debian/home    nullfs    rw  0 0";
} 

启动Jail

  • 现在启动 d2l Jail:

启动 d2l Linux Jail
service jail start d2l

启动以后在物理主机上 ifconfig 就能够看出和之前 FreeBSD Thin(薄) Jail / FreeBSD Linux Jail 的网络差异部分了:

启动 VNET Jail 之后检查 ifconfig 输出
lo0: flags=1008049<UP,LOOPBACK,RUNNING,MULTICAST,LOWER_UP> metric 0 mtu 16384
	options=680003<RXCSUM,TXCSUM,LINKSTATE,RXCSUM_IPV6,TXCSUM_IPV6>
	inet 127.0.0.1 netmask 0xff000000
	inet6 ::1 prefixlen 128
	inet6 fe80::1%lo0 prefixlen 64 scopeid 0x1
	groups: lo
	nd6 options=21<PERFORMNUD,AUTO_LINKLOCAL>
wifibox0: flags=1008843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST,LOWER_UP> metric 0 mtu 1500
	options=0
	ether 58:9c:fc:10:60:55
	inet 10.0.0.2 netmask 0xffffff00 broadcast 10.0.0.255
	id 00:00:00:00:00:00 priority 32768 hellotime 2 fwddelay 15
	maxage 20 holdcnt 6 proto rstp maxaddr 2000 timeout 1200
	root id 00:00:00:00:00:00 priority 32768 ifcost 0 port 0
	member: epair10a flags=143<LEARNING,DISCOVER,AUTOEDGE,AUTOPTP>
	        ifmaxaddr 0 port 5 priority 128 path cost 2000
	member: tap0 flags=143<LEARNING,DISCOVER,AUTOEDGE,AUTOPTP>
	        ifmaxaddr 0 port 3 priority 128 path cost 2000000
	groups: bridge
	nd6 options=9<PERFORMNUD,IFDISABLED>
tap0: flags=1008943<UP,BROADCAST,RUNNING,PROMISC,SIMPLEX,MULTICAST,LOWER_UP> metric 0 mtu 1500
	options=80000<LINKSTATE>
	ether 58:9c:fc:10:ff:b4
	groups: tap
	media: Ethernet 1000baseT <full-duplex>
	status: active
	nd6 options=29<PERFORMNUD,IFDISABLED,AUTO_LINKLOCAL>
	Opened by PID 375
epair10a: flags=1008943<UP,BROADCAST,RUNNING,PROMISC,SIMPLEX,MULTICAST,LOWER_UP> metric 0 mtu 1500
	description: jail:d2l
	options=8<VLAN_MTU>
	ether 02:39:45:0a:f6:0a
	groups: epair
	media: Ethernet 10Gbase-T (10Gbase-T <full-duplex>)
	status: active
	nd6 options=29<PERFORMNUD,IFDISABLED,AUTO_LINKLOCAL>

请注意:

  • 之前 FreeBSD Thin(薄) Jail / FreeBSD Linux Jail 是直接在 wifibox0 上绑定自己的IP地址的,也就是在 inet 10.0.0.2 (第11行) 之后有 inet 10.0.0.9 ,但是现在这行 inet 10.0.0.9 配置消失了

  • 新出现了一个 epair10a 设备,也就是 VNET Jail d2l.conf 配置中 $epair ,此时在物理主机上看不到这个设备的IP地址

检查Jail

现在我们进入 d2l Jail 检查: jexec d2l

  • d2l Jail 中使用 ifconfig 就可以看到 $epair 的另外一头 b :

d2l Jail 中使用 ifconfig
lo0: flags=1008049<UP,LOOPBACK,RUNNING,MULTICAST,LOWER_UP> metric 0 mtu 16384
	options=680003<RXCSUM,TXCSUM,LINKSTATE,RXCSUM_IPV6,TXCSUM_IPV6>
	inet 127.0.0.1 netmask 0xff000000
	inet6 ::1 prefixlen 128
	inet6 fe80::1%lo0 prefixlen 64 scopeid 0x7
	groups: lo
	nd6 options=21<PERFORMNUD,AUTO_LINKLOCAL>
epair10b: flags=1008843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST,LOWER_UP> metric 0 mtu 1500
	options=8<VLAN_MTU>
	ether 02:39:45:0a:f6:0b
	inet 10.0.0.10 netmask 0xffffff00 broadcast 10.0.0.255
	groups: epair
	media: Ethernet 10Gbase-T (10Gbase-T <full-duplex>)
	status: active
	nd6 options=29<PERFORMNUD,IFDISABLED,AUTO_LINKLOCAL>
  • 此时 chroot 进入 Linux Jail 部分:

jexec 结合 chroot 将访问 Debian 系统Linux二进制兼容
jexec d2l chroot /compat/debian /bin/bash

神奇的部分来了,此时在Linux环境执行 ifconfig 也能够看到完整的网卡:

d2l chroot 的 Linux Jail 中使用 ifconfig
root@d2l:/ # chroot /compat/debian/ /bin/bash

root@d2l:/# uname -s -r -m
Linux 5.15.0 x86_64

root@d2l:/# ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 10.0.0.10  netmask 255.255.255.0  broadcast 10.0.0.255
        ether 02:39:45:0a:f6:0b  (Ethernet)
        RX packets 29  bytes 2540 (2.4 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 18  bytes 1379 (1.3 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=4169<UP,LOOPBACK,RUNNING,MULTICAST>  mtu 16384
        inet 127.0.0.1  netmask 255.0.0.0
        unspec 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00  (UNSPEC)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

也就是说在 Linux Jail 中也能比较完整地使用网络堆栈了

现在验证 深度学习环境 ,终于能够正常运行 Jupyter - 数据科学开发平台 程序了(在 Linux Jail 中支持了socket)

备注

不过 VNET Linux 的网络依然不支持 UDP 协议,也不支持普通用户的ICMP

警告

我突然发现我可能搞错了,并不是Jail网络不支持UDP协议或者ICMP,有可能是Jail默认的安全限制。

man jail 8 中有众多的 allow.* 配置,其中就有限制 allow.raw_sockets raw sockets 用于很多网络子系统配置和交互,会导致一些特殊问题。总之,太多配置选项需要挖掘。

参考