多疑的企鹅 - 在用户模式 Linux 下运行网络服务,第二部分
在本“多疑的企鹅”专栏中,我们正在构建一个使用用户模式 Linux 的虚拟网络服务器。上个月,我解释了为什么这是一个好主意,它是如何工作的,如何为优化的用户模式 Linux 操作准备您的主机,以及如何为您的访客(虚拟)系统构建内核。
本月,我们将注意力转向访客系统:如何获取预构建的根文件系统镜像,如何在您的主机和访客系统上配置网络,以及如何开始为您的自身目的自定义根文件系统镜像。
首先,快速回顾一下我们尝试做的事情,以防您错过了上个月的专栏。我们的目标是使用用户模式 Linux 创建一个或多个虚拟访客机器,每个机器运行不同的网络服务。这样,如果一个访客机器上的一个应用程序(例如,BIND)以某种方式受到损害,Sendmail、Apache 以及您在其他访客系统(或底层主机系统本身)上运行的任何其他程序都不会受到影响。
(按照用户模式 Linux 的惯例,我们使用“主机”一词来表示运行虚拟机的系统,使用“访客”一词来表示虚拟系统实例。)
由于可以轻松创建精简的 Debian 安装,Debian 是我们在这里为主机和访客系统所做的有些随意的选择,尽管用户模式 Linux 本身绝对是与发行版无关的。我们将创建一个运行 BIND 软件以提供 DNS 服务的单个访客系统。
根据上个月的步骤,希望您已经拥有一个启用 skas 的主机内核和一个为 um 架构编译的访客内核。现在,是时候获取或构建根文件系统镜像了。
当您的 Linux 主机启动时,它通过 root 命令行开关了解 / 的位置;在 lilo.conf 或 menu.lst 中的某个位置,有一行内核调用行,其中包含类似root=/dev/hda1的内容。 这也适用于用户模式 Linux,只不过我们通常使用单个平面文件形式的虚拟磁盘,而不是 /dev/hda 等物理硬盘,该文件称为根文件系统镜像。
根文件系统镜像包含完整的 Linux 发行版。如果您曾经将 CD-ROM 复制到 ISO 文件(或反之亦然),您就已经创建了类似的镜像文件。使用以单个文件形式存在的文件系统对于用户模式 Linux 有两个重要的影响:首先,它有助于保持您的访客系统相对紧凑和便携;其次,它使变更控制像跟踪单个文件的更改一样简单,通过 COW 文件方法。
假设我使用以下命令启动用户模式 Linux 访客
umluser@host:~> ./guestkernel ubd0=mycow,my_root_fs root=/dev/ubda
请注意 umluser@host 提示符。 我正在从一个 shell 会话中执行此命令,我以普通用户 而非 root 身份登录。 guestkernel 是我的可执行用户模式 Linux 访客内核;ubd0 是我声明为由镜像文件 my_root_fs 加上一个名为 mycow 的写入时复制 (COW) 文件组成的虚拟磁盘设备。 root 开关将我们的根分区定义为虚拟磁盘 ubda(由其完整路径 /dev/ubda 标识)。
有些令人困惑的是,按照惯例,虚拟磁盘声明使用编号的设备名称(ubd0、ubd1 等),但根文件系统定义使用相应的字母(ubda、ubdb 等),它们是同义词。命令./guestkernel ubda=mycow,my_root_fs root=/dev/ubda实际上在我的 SUSE 系统上与上述命令一样有效,但您选择的发行版可能表现不同。
严格来说,COW 文件是可选的。如果您指定一个,您在用户模式 Linux 会话期间对镜像文件所做的更改将被写入 COW 文件,而不是磁盘镜像本身。如果您省略 COW 文件名,镜像文件将由访客内核直接写入——也就是说,您对访客系统所做的任何更改都将是“永久性的”。
就我而言,当在安全场景中使用 UML 时,COW 文件是强制性的。使用用户模式 Linux 托管网络服务的关键假设是此服务可能会以某种方式受到损害,如果受到损害,您希望能够尽快恢复。如果您使用 COW 文件,您需要做的就是删除旧的 COW 文件并创建一个新的(空的)文件,即可将访客系统恢复到其基线状态。
使用 COW 文件的另一个主要优点是,它们允许您同时在多个访客系统上使用相同的根文件系统镜像。您需要做的就是每次启动访客内核时指定不同的 COW 文件。实际上,您可以为多个访客使用相同的镜像文件和相同的内核。您可以猜到,我们将在我们的示例场景中使用 COW 文件。
构建您自己的根文件系统镜像的过程可以归结为以下几点
创建一个空的文件系统镜像文件并将其挂载到某个目录。
将 Linux 安装到该目录中。
听起来很简单,对吧?在 Debian 和 SUSE 上是这样——有点。在其他发行版上,情况就没那么简单了。无论如何,我将在我的下一篇专栏中更详细地讨论该过程,其中我将介绍我认为是高级用户模式 Linux 主题和技术的内容。为了让您以令人满意的快速方式启动并运行用户模式 Linux,现在我建议您下载一个预构建的镜像。
我最喜欢的来源是 Nagafix Ltd. 的“UML 资源”页面(请参阅在线资源),您可以从中下载不仅适用于 Debian 访客,而且也适用于 Gentoo、Slackware、Fedora、Ubuntu 等的根文件系统镜像。 Nagafix 尽力使这些镜像与安全补丁保持同步,这是一个不错的举措。
此外,Nagafix 还提供了它提供的每个镜像文件的 MD5 和 SHA 哈希值。如果您直接单击上面引用的页面上的 x86 和 AMD64 链接,您可能会错过它们;相反,请使用操作系统名称链接,每个链接都指向一个页面,其中不仅包含镜像的链接,还包含构建日志和哈希值,以及有关如何自行更新镜像的实用技巧。
我通过导航到 uml.nagafix.co.uk,单击 Debian 3.1,然后单击 root_fs 和 MD5 链接来下载文件 Debian-3.1-x86-root_fs.bz2 和 Debian-3.1-x86-root_fs.bz2.md5,从而获得了我的 Debian 3.1 镜像。在我的下载完成后(文件系统镜像本身为 169MB!),我使用命令在终端窗口中验证了 MD5 签名
md5sum -c ./Debian-3.1-x86-root_fs.bz2.md5
当有疑问时,自己构建镜像
即使您使用来自可信来源的根文件系统镜像并通过 MD5、SHA 或 GPG 哈希/签名验证其完整性,但事实是,如果您真的担心安全问题(我们是担心的,不是吗?),您最好自己构建文件系统镜像,而不是使用别人的。
在本文中使用预构建的镜像,我只是稍微偷懒和寻求即时满足感,我认为这在鼓励 UML 实验和采用的更大目标中是合理的。只需确保检查您镜像的哈希/签名,并且在您第一次在 UML 中挂载它时,运行apt-get dist-upgrade(或 YaST Online Update、yum 或您的访客发行版支持的任何更新机制)。
下次,我将更深入地讨论文件系统镜像构建过程,以及如何在您的主机和访客操作系统上使用 iptables 以向您的虚拟机添加另一层保护。
现在,我们准备好首次启动我们的虚拟访客。我们有一个名为 uml-guestkernel-2.6.17.3 的访客内核(来自我之前的专栏示例)和一个名为 Debian-3.1-x86-root_fs.bz2 的根文件系统镜像。您应该已经以非 root 用户身份登录到终端会话。使用命令解压缩文件系统镜像
bunzip2 ./Debian-3.1-x86-root_fs.bz2
接下来,就像健全性检查一样,尝试启动您的访客系统
umluser@host:~> ./uml-guestkernel-2.6.17.3 ↪ubd0=testcow,Debian-3.1-x86-root_fs root=/dev/ubda
如果一切顺利,您应该会看到一些用户模式 Linux 消息,然后是一长串 Linux 内核启动消息,最后是登录提示符。以 root 身份登录——您不会被提示输入密码。随意浏览一下;您不会损坏任何以后可以通过从新的 COW 文件开始来修复的东西。
要查看已安装软件包的列表,请输入命令dpkg -l |less。您可能会惊讶于 Debian 软件包的数量如此之少。不用担心;您将能够像在“真实” Debian 系统上一样使用 apt-get 安装其他软件包。当您完成初始探索后,发出命令halt以干净地关闭您的访客系统。在您的访客系统可以执行任何严肃工作之前,我们还有一些事情要做——首要任务是配置网络。
有多种方法可以对 UML 访客进行联网,所有这些方法都在 Rusty Russell 的用户模式 Linux HOWTO(请参阅资源)中进行了描述。将 UML 访客用作网络服务器的最佳选择是桥接,其中您的主机系统充当自身、在其上运行的 UML 访客和外部世界之间的以太网桥。
简而言之,过程如下
将您的主机的 TCP/IP 堆栈配置为虚拟桥,然后将您的“真实”网络接口定义为该桥上的第一个“端口”。
对于您打算运行的每个访客系统,创建一个本地隧道接口并将其定义为桥上的另一个端口。
当您启动访客系统时,将其虚拟以太网接口 (eth0) 定义为您在上一步中创建的隧道接口。
列表 1 显示了这转化为的确切命令序列,改编自 David Cannings 的有用文章“使用桥接连接 UML 网络”。所有这些命令都必须以 root 身份执行。
列表 1. 设置桥接网络
root@host# bash -c 'echo 1 > /proc/sys/net/ipv4/ip_forward' root@host# apt-get install bridge-utils uml-utilities root@host# ifconfig eth0 0.0.0.0 promisc up root@host# brctl addbr uml-bridge root@host# brctl setfd uml-bridge 0 root@host# brctl sethello uml-bridge 0 root@host# brctl stp uml-bridge off root@host# ifconfig uml-bridge 192.168.250.250 netmask 255.255.255.0 up root@host# brctl addif uml-bridge eth0 root@host# tunctl -u umluser -t uml-conn0 root@host# chgrp uml-net /dev/net/tun root@host# chmod 660 /dev/net/tun root@host# ifconfig uml-conn0 0.0.0.0 promisc up root@host# brctl addif uml-bridge uml-conn0
第一个命令启用您主机上的 IP 转发。虽然从技术上讲,桥接发生在比 IP 转发更低的级别,但从内核的角度来看,它们的效果是相同的。因此,如果您的主机上有本地 iptables 策略,您需要在 FORWARD 表中添加规则,以允许进出您连接到主机桥的隧道接口的流量。
第二个命令 (apt-get install...) 显然安装了 Debian 软件包 bridge-utils 和 uml-utilities。 bridge-utilities 提供了 brctl 命令,而 uml-utilities 提供了 tunctl 命令。为了使这些命令起作用,您的主机内核需要已编译 802.1d 以太网桥接、IP 隧道、桥接 IP/ARP 数据包过滤和通用 TUN/TAP 设备驱动程序支持。
列表 1 中的第三个命令 (ifconfig eth0...) 可能看起来有点吓人。它将您主机的以太网接口重置为(临时的)无 IP 状态。在执行此命令后,请为本地网络功能中断做好准备。
但是,随后的六个命令将通过定义新的虚拟桥设备(称为 uml-bridge)、配置它、将您主机的 IP 地址分配给它(在本例中为 192.168.250.250)并将 eth0 作为虚拟桥端口连接到它来恢复它。如果您的主机上 eth0 的 IP 地址在您将其重置为 0.0.0.0 之前是 10.1.1.10,那么在发出前四个 brctl 命令后,您将使用ifconfig uml-bridge 10.1.1.10 netmask 255.255.255.0 up。此时,您的主机应该能够以与之前完全相同的方式与外部世界交互(当然,除非您的本地 iptables 策略还没有适当的 FORWARD 规则)。
好的,我们的主机系统现在是一个桥。剩下的就是向其附加一个隧道端口。对于您打算运行的每个访客系统,您都应该重复列表 1 中的剩余步骤(从 tunctl -u... 开始)。
在 tunctl -u... 命令中,umluser 是您在执行访客内核时打算使用的非特权帐户的名称,而 uml-conn0 是您正在创建的新隧道接口的名称。
在随后的 chgrp 和 chmod 命令中,我们正在更改虚拟隧道设备(始终是 /dev/net/tun)的权限,使其可由我们的非特权帐户读取和写入。因此,在本例中,帐户 umluser 属于组 uml-net。(在我的真实测试系统上,我改为使用了 wheel 组,我的非特权帐户 mick 属于该组。)
在将新隧道接口的 IP 地址设置为 0.0.0.0(就像我们对 eth0 所做的那样)之后,我们使用最后一个 brctl 命令将其定义为本地桥上的另一个端口。
就这样!现在,当我们启动访客系统时,我们添加选项eth0=tuntap,uml-conn0到我们的内核命令行,这告诉内核使用隧道接口 uml-conn0 作为其虚拟 eth0。我们的完整示例命令行(与列表 1 不同,它应该由非特权用户而不是 root 运行)如下所示
umluser@host$ ./debkern ubd0=debcow,debroot root=/dev/ubda ↪eth0=tuntap,uml-conn0
在虚拟机启动后,您可以通过以下方式为(虚拟)eth0 分配 IP 地址ifconfig,通过以下方式定义默认路由route add...(使用与您的主机系统相同的网关 IP),在 /etc/resolv.conf 中设置 DNS 查找信息,简而言之,以与配置真实 Debian 系统完全相同的方式配置它。
一旦您的虚拟机成功地与您的本地 LAN 和更远的地方通信,您应该立即配置 apt-get 并使用它在您的虚拟访客上安装最新的 Debian 补丁。无论如何,您都需要 apt-get 才能工作,以安装您刚刚费尽心思构建此虚拟机以运行的网络软件。在我们的示例虚拟 DNS 服务器的情况下,这些软件包可能是 Debian 软件包 bind9,也可能是 bind9-doc。请记住,所有这些更改都将对您的 COW 文件进行,因此请确保在后续启动时指定相同的 COW 文件(或通过 uml_moo 命令将其合并到您的镜像中)。
下次,我们将通过讨论您可以在访客系统上使用的其他安全控制、一两个巧妙的 COW 文件技巧,当然还有如何创建自定义根文件系统镜像来结束本系列。在那之前,请注意安全!
本文的资源: /article/9385。
Mick Bauer (darth.elmo@wiremonkeys.org) 是美国最大的银行之一的网络安全架构师。他是 O'Reilly 图书 Linux 服务器安全 第二版(以前称为 使用 Linux 构建安全服务器)的作者,偶尔在信息安全会议上发表演讲,并且是“网络工程波尔卡舞曲”的作曲家。