Mofos 是一款用于创建、运行和管理虚拟机的工具。它基于 Libvirt/QEMU/KVM 和 Python,因此兼容任何 Linux 发行版。Mofos 深受 Qubes OS (https://www.qubes-os.org/) 的启发,旨在复现其许多功能。
该工具已在 Debian 及基于 Debian 的虚拟机上进行了广泛测试。虽然其他 Linux 发行版预计也能正常运行,但可能需要进行一些额外配置。更多细节有待补充。
Mofos 提供了一系列专注于安全地管理虚拟机的功能,包括:
一台 mofos 机器由两个通过 overlayfs 组合在一起的磁盘组成。第一个磁盘称为下层,是一个只读的模板磁盘;第二个磁盘则存储虚拟机所做的所有更改。这个模板磁盘在多台虚拟机之间共享。因此,创建新虚拟机只需克隆一个已经分好区、用于保存修改数据的空磁盘。这种方法确保可以快速创建新虚拟机,同时允许模板独立更新。模板的任何更新都将在依赖它的虚拟机下次重启时生效。
根据 Linux 发行版的不同,可以利用 Makefile 来生成 deb 包或直接安装这些文件。```
make deb
apt install ./mofos-VERSION.deb
在 `apt` 安装过程中,会提示各种设置。通常可以接受默认选项。唯一需要注意的设置是 mofos libvirt 网络使用的子网地址(默认:`192.168.90.0/24`)。
或者
安装以下依赖:
- guestfs-tools
- libnotify-bin
- libvirt
- libvirt-clients
- libvirt-daemon
- make
- python3-click
- python3-click-completion
- python3-colorama
- python3-cryptography
- python3-dbus
- python3-jinja2
- python3-lxml
- python3-prettytable
- python3-pyroute2
- python3-tqdm
- qemu-system-common
- qemu-system-modules-spice
- socat
- spice-client-gtk
- sudo
- virtinst
- virt-install
- virtiofsd
- virt-manager
- virt-viewer```
make install_files
Depending on the distribution, the Python files copied to /usr/lib/python3/dist-packages may not be detected by the Python interpreter and should be placed elsewhere. For example, on Fedora, the Python files must be copied to /usr/lib/python3.11/site-packages.
[!WARNING] 注意,自 Debian trixie 起,
xpra不再打包发布,您必须从其自定义软件仓库手动安装。有关详细说明,请参阅 https://github.com/Xpra-org/xpra/wiki/Download#-for-debian-based-distributions。
Mofos 使用 QEMU/KVM 系统会话,因此要允许 virsh 命令访问虚拟机及相关资源,请将环境变量 LIBVIRT_DEFAULT_URI 设置为 qemu:///system:```console
export LIBVIRT_DEFAULT_URI=qemu:///system
### 安全考量
使用 QEMU/KVM 系统会话可提高宿主机与客户机虚拟机之间的隔离性,其做法是在专用用户(`libvirt-qemu`)下运行 qemu 实例,并为每个实例应用特定的安全配置文件。
然而,默认情况下,普通用户无法与 `libvirtd` 系统套接字交互,也就无法管理机器、网络及其他资源。要获得访问权限,用户要么必须是 libvirt Unix 组的成员,要么使用 sudo。从历史上看,本地权限提升漏洞正是利用 libvirt 组成员身份来获取 root 权限的。
为降低这些风险,本仓库在基于 AppArmor 的系统上为 `libvirtd` 进程提供了强化的 AppArmor 配置文件。该配置文件显著限制了 `libvirtd` 可写入文件的位置以及可执行的程序。
此外,还包含了 `polkit` 规则,以进一步控制允许 `libvirt` 组成员执行的操作。
请注意,AppArmor 配置文件随 `deb` 包一起发布,但不会由 Makefile 的 `install_files` 目标安装,因此必须单独安装。
## Mofos 配置
Mofos 需要一个位于 `$HOME/.config/mofos/config.toml` 的配置文件,并包含最少量的设置才能正常运行。最小示例配置可在 `/usr/share/mofos/config.minimal.toml` 中找到,而更全面的配置则记录在 `/usr/share/mofos/config.sample.toml` 中。
以下错误表示未找到配置文件:```
[-] Copy the sample configuration file from /usr/share/mofos/config.minimal.toml to ~/.config/mofos/config.toml
以下错误表明当前用户不是 libvirt 组的成员:``` [-] libvirtError("authentication unavailable: no polkit agent available to authenticate action 'org.libvirt.unix.manage'")
需要在配置文件中自定义的关键配置设置如下:
- key (路径):用于访问虚拟机的 SSH 私钥文件。建议为此目的创建专用密钥。
- user (字符串):用于 SSH 访问虚拟机的用户名。
- root_password (哈希值):安装新模板期间要设置的 root 密码哈希值。
- root_ssh_pubkey (字符串):模板安装期间要安装到 root 用户目录中的 SSH 公钥。
此外,还必须为模板安装配置以下参数:
- ntp
- dns (如果提供了代理,则可选)
- proxy
## 安装模板
### 配置防火墙
由于安装过程依赖于 PXE 网络启动,因此需要有效的互联网连接。应配置以下防火墙规则:```
sysctl net.ipv4.ip_forward=1
iptables -t nat -I POSTROUTING -s 192.168.90.0/24 -j MASQUERADE
iptables -t nat -I POSTROUTING -s 192.168.91.0/24 -j MASQUERADE
或者使用 nftables:``` sysctl net.ipv4.ip_forward=1 nft insert inet nat postrouting iifname "install-*" masquerade nft insert inet nat postrouting iifname "mof0" masquerade
当 `ip_forward` 参数设置为 1 时,应配置 FORWARD 链,以防止网络上的其他设备将主机用作路由器。
总的来说,建议采用以下规则:```
iptables -I INPUT -i mof0 -p udp --sport 68 --dport 67 -j ACCEPT -m comment --comment "mofos dhcp"
iptables -I INPUT -i mof0 -p udp --dport 69 -j ACCEPT -m comment --comment "mofos tftp"
iptables -I OUTPUT -o mof0 -j ACCEPT -m comment --comment "host -> mofos"
iptables -I FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
iptables -I FORWARD -i mof0 -j ACCEPT -m comment --comment "mofos ->"
iptables -t nat -I POSTROUTING -s 192.168.90.0/24 -j MASQUERADE
iptables -t nat -I POSTROUTING -s 192.168.91.0/24 -j MASQUERADE
或者使用 nftables:```
table inet filter {
chain input {
type filter hook input priority 0; policy drop
iifname "install-*" ip daddr 255.255.255.255 udp sport 68 udp dport 67 accept comment "mofos dhcp"
iifname "mof0" ip daddr 255.255.255.255 udp sport 68 udp dport 67 accept comment "mofos dhcp"
iifname "install-*" udp dport 69 accept comment "mofos tftp"
}
chain forward {
type filter hook forward priority 0; policy drop
ct state established,related accept;
ct state invalid drop;
iifname "mof0" counter accept
iifname "install-*" counter accept
}
chain output {
type filter hook output priority 0; policy drop
oifname "mof0" counter accept
}
} table inet nat { chain postrouting { type nat hook postrouting priority 100 iifname "mof0" masquerade iifname "install-*" masquerade } }
It is recommended to restrict masquerade and forwarding rules based on your specific needs, to prevent mofos virtual machines from accessing the entire host network.
建议根据您的具体需求限制 masquerade 和转发规则,以防止 mofos 虚拟机访问整个主机网络。
Isolation between virtual machines is automatically enforced by a libvirt hook, which requires nft to function properly.
虚拟机之间的隔离由 libvirt hook 自动强制执行,这需要 nft 才能正常运行。
### Install
### 安装
The first step is to build the initial layer: the template. By default, Mofos can install a Debian 12–based template.
第一步是构建初始层:模板。默认情况下,Mofos 可以安装基于 Debian 12 的模板。```
mofos template create debian-template
注意:对于每个命令,都可以使用 --debug 选项来获取详细的技术信息,以防出现意外行为。具体到本命令,--debug 标志还会强制显示一个图形窗口以展示安装进度。或者,也可以使用 virt-manager 来监控安装过程。
目前,仅支持 Debian 12 模板进行安装。下面的 Python 字典指定了要使用的安装映像:```python NETBOOT = { "debian-stable-amd64": { "variant": "debian11", "url": "https://deb.debian.org/debian/dists/stable/main/installer-amd64/current/images/netboot/netboot.tar.gz", } }
变体设置为 `debian11`,因为在 Debian 12 中,其 `osinfo` 变体尚无法通过 libvirt 安装。
要安装其他发行版,请修改位于 `/usr/lib/python3/dist-packages/mofos/settings.py` 中的字典。
运行上述命令时,Mofos 会下载 netboot 文件并将 `tar.gz` 压缩包缓存到 `$HOME/.cache/template-installer`。目前,如果 netboot 压缩包已存在,Mofos 不会再次下载。如果缓存的压缩包已过时,这可能会导致错误。如果安装过程中出现此类错误,删除缓存的压缩包将强制 Mofos 下载更新版本,从而解决该问题。
接下来,压缩包被解压到 `/tmp`,并配置 libvirt 通过 TFTP 提供其内容。
然后创建模板虚拟机,并将其设置为通过 PXE 引导,使用提供的 preseed 文件(默认为 `/usr/share/mofos/templates/debian/preseed.cfg.j2`)安装指定发行版。该文件是一个 `jinja2` 模板;在将其复制到 TFTP 根目录之前,会注入配置文件(`ntp`、`proxy`、`dns`、`root_password`)中的变量。
安装结束时,`postinstall` 脚本会被放置到 TFTP 目录中并在模板上执行。默认使用位于 `/usr/share/mofos/templates/postinstall.sh.j2` 的脚本。此 `jinja2` 模板会注入要在模板上配置的 SSH 公钥。
除了配置 root 的 SSH 公钥外,还会执行以下操作:
- 禁用标准 SSH 服务,并启用基于虚拟套接字(vsock)的 SSHD。
- 清空 `/etc/resolv.conf` 文件。
- 将 GRUB 超时设置为 0 秒。
- 安装一个 initramfs 钩子,当检测到标记为 `overlay` 的分区时挂载 overlayfs。