第二十三章:FreeBSD的边缘

如果你在FreeBSD社区呆上一段时间,你会听到有人提到,如果你知道怎么做,可以做各种各样的事情。人们构建嵌入式FreeBSD设备并将其运送给世界各地的客户,他们甚至不知道他们在运行空调或无线电中继站的小盒子里有一个类似Unix的服务器。人们在没有硬盘的机器上运行FreeBSD,从一台服务器支持数百或数千个无盘工作站。您会发现包含完整FreeBSD系统的可引导CD和USB设备,包括您可能想要的所有已安装软件。一旦你知道诀窍,这些事情就不难做了。

在本章中,我们将进入FreeBSD的边缘——由FreeBSD用户完成的非常酷的事情,但不一定得到主流FreeBSD项目的支持。虽然您可以通过常规渠道获得支持和帮助,但您必须准备好调试和排除本章中的所有问题,甚至比平时更多。

终端

终端 —— terminal 是人们可以登录的设备。键盘、视频和鼠标组成了一个终端,也称为控制台 —— console 。当您通过SSH连接到主机时,它会提供一个虚拟终端 —— virtual terminal 。终端配置是完全自动的,但您可能需要对其进行调整。

/etc/ttys 文件控制用户登录FreeBSD系统的方式和位置。控制台登录有效吗?虚拟终端怎么样?通过串行线路登录怎么样?FreeBSD系统提供四种标准终端:控制台、虚拟终端、拨号终端和伪终端(pseudoterminals)。

控制台是单用户模式下唯一可用的设备。在大多数FreeBSD系统上,这要么是一个包含显示器和键盘的视频控制台,要么是一种从另一个系统访问的串行控制台。一旦系统进入多用户模式,控制台通常会连接到虚拟终端。控制台设备是 /dev/console

虚拟终端 ——virtual terminal ,连接到物理监视器和键盘。您可以在一个物理终端上拥有多个终端。使用ALT和功能键在它们之间切换。下次你在键盘前,按ALT-F2。您将看到一个新的登录屏幕,主机名后有 ttyv1 。这是第二个虚拟终端。点击ALT-F1将返回主虚拟终端。默认情况下,FreeBSD有八个虚拟终端,并为X Windows保留了第九个。即使在X中,您也可以使用八个虚拟文本终端,一些X桌面提供多个X虚拟终端。虚拟终端是 /dev/ttyv 设备。

拨号终端 —— dial-up terminal ,通过串行线连接。您可以将调制解调器直接连接到串行端口,让用户拨入您的服务器。现在这种情况并不常见,但同样的功能支持通过串行控制台登录。拨号终端是 /dev/ttyu 设备。

最后,伪终端 —— pseudoterminal ,完全用软件实现。当您通过SSH连接到服务器时,您不需要任何实际的硬件,但软件仍然需要一个用于会话的设备节点。伪终端是 /dev/pts/ 中的设备节点。您不配置伪终端;当你登录时,它们会自动协商。

/etc/ttys 中配置对控制台、虚拟终端和拨号终端的访问。您可以启用串行访问、要求或禁用密码等。

/etc/ttys 格式

/etc/ttys 中的一个典型条目如下:

第一个字段是终端的设备节点。此例中,ttyv0是系统上的第一个虚拟终端。

第二个字段是为处理此终端上的登录请求而生成的程序。FreeBSD使用 getty(8) ,但如果你有一个首选的终端管理程序,你可以使用它。你会在packages里找到几个。此字段接受一个参数,即终端配置。/etc/gettytab 文件包含所有终端配置。

第三个条目是终端类型。/etc/termcap 文件描述了FreeBSD支持的无数终端类型。对于非常小的系统,FreeBSD只提供最重要的条目 /etc/termcap.small 。几乎所有现代设备都可以使用 xtermvt100

第四个条目确定终端是否可用于登录。这可以设置为 on 用于接受登录,也可以设置为 off 用于不允许登录。如果内核将串行端口配置为控制台,则 onifconsole 设置允许在串行端口上登录。

最后,我们有选项。这个例子有一个选项 secure set ,它告诉 `getty(8) root可以登录到这个控制台。

提供终端是由 init(8) 直接处理的低级系统任务。对 /etc/ttys 的更改只有在您告诉 init(8) 重新读取其配置文件后才会生效。Init始终为PID 1。

控制台不安全

当你在单用户模式下启动FreeBSD时,你会得到一个root命令提示符。这对你的笔记本电脑来说很好,对公司数据中心的服务器也很好,但对于不受信任的设施中的机器呢?例如,如果你在托管中心有一台服务器,你可能不希望任何人都能获得对机器的根级访问权限。你可以告诉FreeBSD物理控制台是不安全的,并让它需要root密码才能进入单用户模式。然后,系统将从开机模式启动到多用户模式,不需要密码,但当您在单用户模式下明确启动时,它将需要密码。

在单用户模式下要求密码并不能完全保护您的数据,但它确实大大提高了标准。一个独自工作到很晚的技术人员,在没有人注意的情况下,可以在大约15分钟内将你的系统引导到单用户模式并为自己添加一个帐户。拆卸你的机器、移除硬盘、将它们安装到另一台机器、进行更改并使你的服务器重新上线需要更多的时间,更具侵入性,并且更有可能被主机代管管理人员注意到。

/etc/ttys 中找到控制台条目:

你会发现控制台终端并不像其他终端那样功能齐全;它不运行 getty(8) ,而是使用通用的 unknown 终端类型。然而,控制台仅适用于单用户模式,并且连接到物理终端时使用,所以这很好。

要使控制台在启动到单用户模式时需要root登录,请将secure 更改为insecure

控制台密码保护可防止随意恶作剧。它甚至不会减慢一个有物理访问权限的入侵者的速度。

管理云FreeBSD

由数百或数千台服务器组成的集群正变得越来越普遍。像Ansible和Puppet这样的自动化系统让我们能够以某种方式维护这些系统。然而,Unix的设计初衷并非如此。Primorial UNIX是由一位技术娴熟的操作员编写的,他能够轻松处理无数不同命令输出格式甚至更多配置文件样式的变幻莫测。

FreeBSD正在用libXo和通用配置语言(universal configuration language —— UCL)解决云规模管理的问题。

LibXo

虽然自动化监控是必要的,可以提醒您注意问题,但在深入故障排除方面,没有什么能取代登录主机、运行命令和解释结果。我记不清我写了多少脚本来解析 ps(1) 标志的一些模糊组合的输出,以便我可以向监控软件提供一个数字。我也记不清我花了多少时间调试这些脚本,或者解释为什么我写的处理一个 netstat(1) 标志的脚本与我们现在感兴趣的标志无关。将其乘以数百或数千台服务器,从软件中快速获取信息就成了一个严重的问题。

FreeBSD通过libXo减少了这个问题空间。

LibXo是一个库,它帮助命令不仅以文本形式,而且以XML、JSON甚至HTML形式提供输出。您可以让解析器从标记格式中提取数据,而不是使用 grep(1)awk(1) 以及您为查找所需信息而准备的任何令人震惊的shell、Perl或Python组合。您可以将命令输出直接转储到网页。

并非所有程序都支持libXo,但支持不断添加到更多程序中。手册页声明了程序是否支持libXo,但如果你懒得阅读,可以尝试使用带有 --libXo 标志的命令。所有支持libXo的命令都使用该命令行选项。您还必须指定输出格式,可以是文本、XML、JSON或HTML。在这里,我运行arp-an并将JSON标识为输出格式。

你怎么用这个?我们中的许多人不会。但是,如果您正在运行数十或数百台服务器,您可能拥有内部专业知识,可以轻松解析此内容。数百种工具可以选择标记的数据,您的应用程序开发人员可能已经在您的主机上安装了他们喜欢的软件。虽然 arp(8) 的输出相当一致,但libXo还可以处理 netstat(1)vmstat(8) 等标志的任意组合。一旦学会从输出中抓取标记数据,你就永远不会编写那些可怕的脚本了。

通用配置语言

Unix系统具有相当标准的配置文件格式。哈希标记(#)是注释。有变量。也许配置文件中变量的存在足以激活一个功能,或者你必须将变量设置为一个值。不过,它们都有点不同。一些程序可以从主文件和目录中的文件中提取配置片段,就像 cron(8)/etc/crontab/etc/cron.d/ 所做的那样。其他的不能。一些人使用大括号来留出配置块,而另一些人则使用......30年前程序员认为什么是好主意。结果是,没有人查看 syslog.conf 并认为它看起来像 pkg.conf ,即使它们共享共同的底层概念。

通用配置语言(universal configuration language —— UCL)旨在改变这一点。如果所有这些程序都有类似的语法,为什么不为每个程序使用一个解析库呢?如果你有一个解析库,为什么不让它解析多种格式呢?UCL允许您以经典的Unix风格、JSON或YAML提供配置文件,是自动化管理的理想选择。它可以提取shell代码、UCL、JSON或YAML中的配置设置。

在我写这篇文章的时候,FreeBSD将UCL用于 pkg(8) 。对其他公用事业的支持,如 bhyve(8) ,正在慢慢实现。如果您正在管理大量服务器,请检查您的版本中UCL的状态。

无盘 FreeBSD

虽然FreeBSD并不难管理,但数十或数百个几乎相同的系统可能会成为一个负担。减少维护开销的一种方法是使用无盘( diskless )系统。无盘系统不禁止有硬盘;相反,它们从网络上其他地方的NFS服务器加载内核和操作系统。

为什么要为服务器场(server farm)使用无盘系统?多个系统可以从单个NFS服务器启动,集中所有补丁和包管理。这对于终端集合、计算集群和其他具有大量相同系统的环境来说是极好的。推出操作系统更新只需替换NFS服务器上的文件即可。同样,当您发现更新有问题时,还原它就像还原NFS服务器上的文件一样简单。在任何一种情况下,您在客户端唯一要做的就是重新启动。由于客户端对服务器具有只读访问权限,因此不受信任的用户无法对操作系统进行任何更改。如果你只有几个系统在运行,那么无盘可能对你来说工作量太大了,但除此之外,无盘显然是赢家。

在运行无盘系统之前,您必须拥有NFS服务器、DHCP服务器、TFTP服务器和支持无盘启动的硬件。让我们逐一介绍,看看如何设置它。

测试,测试,测试! 您的第一个无盘设置将与您的第一次防火墙设置非常相似:容易出错、麻烦和令人恼火。我强烈建议你测试准备的每一步,这样你就可以更容易地发现和解决问题。为每项所需服务提供测试说明。

无盘客户端

运行无盘的机器必须具有足够的智能,以便通过网络找到其引导加载程序和操作系统。有两种标准方法可以做到这一点:BOOTP和PXE。BOOTP,即互联网Bootstrap协议,是一个很久以前就不受欢迎的旧标准。PXE,英特尔的预引导执行环境,多年来几乎在每台新机器上都得到了支持,所以我们将专注于此。

启动无盘客户端计算机并进入BIOS设置。在BIOS的某个地方,你会发现一个设置引导设备顺序的选项。如果计算机支持PXE,其中一个选项将是网络。启用该选项并让计算机先尝试。

您的无盘客户端已准备就绪。现在让我们准备好服务器。

DHCP 服务器设置

虽然大多数人认为DHCP是向客户端分配IP地址的一种方式,但它可以提供更多。您可以配置DHCP服务器以提供TFTP服务器、NFS服务器和其他网络资源的位置。无盘系统广泛使用DHCP,您会发现我们使用了您以前从未尝试过的DHCP选项。

OpenBSD的DHCP服务器不支持FreeBSD无盘客户端;您必须使用ISC的DHCP服务器或其他功能更全面的版本。一旦您获得了无盘工作站的MAC地址,配置ISC DHCP服务器以处理无盘系统就非常简单。

MAC 地址

要为DHCP客户端分配配置信息,您需要该客户端网卡的MAC地址。一些BIOS实现提供了集成网卡的MAC地址,一些服务器级硬件上印有MAC地址的标签。然而,这些选择太容易了,所以我们会努力尝试。

当一台机器试图从网络上启动时,它会向DHCP请求其配置信息。虽然您还没有无盘配置,但任何DHCP服务器都会记录客户端的MAC地址。您可以从租约文件 /var/db/dhcpd.releases 中获取客户端信息。

此客户端的MAC地址为08:00:27:d8:c1:1c➋,并已提供IP地址198.51.100.10➊. 根据此信息,我们可以创建一个DHCP配置,为该主机分配一个静态IP地址并提供其引导信息。

DHCP配置:特定无盘主机

我们在第20章中配置了基本的DHCP服务。这是一个无盘客户端的 dhcpd(8) 配置示例。这并不包含在子网语句中,但它本身就是一个顶级语句,即使它位于与非共享DHCP客户端共享的子网上。

我们定义了一个名为 diskless ➊的组。这个定义将允许我们为组分配某些参数,然后只需将主机添加到组中。组中的每个主机都获得相同的参数。

next-server 设置➋告诉DHCP客户端TFTP服务器的IP地址,而 filename 选项➌告诉DHCP客户端要从TFTP服务器请求的引导加载程序文件的名称。记住第4章中的引导加载程序是查找和加载内核的软件。最后,option root-path ➍告诉引导加载程序在哪里可以找到这台机器的根目录。所有这些选项和设置都提供给无盘组中的所有客户端。

然后,我们使用 host 语句和该系统的主机名将无盘客户端分配给无盘组➎。我们的第一个客户端称为 compute1 。该客户端由其MAC地址➏标识,并分配了一个静态IP➐。它还接收该组的标准配置。

为网络上的每个无盘主机创建类似这样的其他主机条目。

重新启动 dhcpd(8) 以使此配置生效。现在重新启动您的无盘客户端。DHCP日志应显示您已向此客户端提供了其静态地址。但是,如果没有引导加载程序,DHCP客户端将无法进一步引导,这意味着您需要TFTP服务器。

DHCP配置:无盘服务器场

也许您有大量相同的无盘主机,例如终端机房中的瘦客户端。不想为每个瘦客户端创建静态DHCP条目是非常明智的。让这些主机从DHCP服务器获取启动信息,但不指定主机地址。他们只会从DHCP池中取出一个地址。许多集群解决方案都包括客户端服务,这些服务可以向他们使用的任何“集群管理器”注册新主机,因此硬编码地址并不那么重要。

您还可以明确标识从PXE请求DHCP信息的主机,并将这些主机分配给特定的地址组。使用PXE启动的主机向DHCP服务器标识自己为PXEcient类型的客户端。您可以编写特定的规则来匹配该类型的客户端,并对其进行适当的配置。有关如何匹配供应商类标识符(vendor-class-identifier)和DHCP客户端标识符(dhcp-client-identifier)的信息,请参阅DHCP手册。

tftpd 和启动加载器

我们在第20章中介绍了配置TFTP服务器。TFTP服务器必须为您的无盘客户端提供 pxeboot 文件。FreeBSD在 /boot 目录中提供 pxeboot

尝试通过TFTP从工作站下载 pxeboot。如果成功,请重新启动您的无盘客户端,并观察它尝试启动。控制台应显示如下消息:

你以前见过这条消息,当一个普通的FreeBSD从硬盘上启动时。您的无盘客户端将识别PXE版本,打印内存,并声明它正在运行引导加载程序。到那时,它将无休止地尝试加载内核。它无法加载内核,因为我们还没有设置NFS服务器。

无盘安全

无盘系统在NFS上运行,并存在NFS的所有安全问题。即使部署Kerberos来加密NFS流量,根文件系统的初始网络引导和挂载也始终是未加密的。不要在开放的互联网上运行无盘节点。

通过为NFS根帐户分配不同的用户,可以在一定程度上保护NFS服务器。运行 find /diskless/1 -user 0 -exec chown nfsroot{}\; 将root拥有的所有文件的所有者更改为用户nfsroot拥有。然后,您可以编辑 export 文件,将root映射到nfsroot用户。但是,您需要恢复该状态才能运行 freebsd-update(8) ,然后在应用补丁后恢复它。但当你第一次学习时,不要幻想。首先让一个基本的用户区工作。

NFS服务器和无盘客户端用户区

许多关于无盘操作的教程建议对无盘客户端使用服务器的用户区和根分区。这可能很容易做到,但它甚至不是模糊的安全。您的无盘服务器上可能有您不希望客户端访问的程序,而且它肯定有您不想分发给一大堆工作站的敏感安全信息。提供一个单独的用户区是一个更明智的选择。

虽然你可以通过多种方式提供一个单独的用户区,但我发现最简单的方法是稍微修改第22章中的 jail(8) 构建过程。首先,为我们的无盘客户端创建一个数据集、UFS文件系统或目录作为其根目录,然后在该目录中安装用户区和内核。提取该目录中FreeBSD版本的 base.txzkernel.txz 分发文件。

如果你已经构建了一个你想运行的FreeBSD,那也是可行的。在这里,我们在 /diskless/1 中安装一个本地构建的用户区:

现在告诉您的NFS服务器这个目录。我打算在这个网络上安装几个无盘系统,所以我通过NFS将这个目录提供给我的整个子网。客户端不需要对NFS根目录的写访问权限,因此我以只读方式导出它。以下 /etc/exports 行执行此操作:

重新启动 mountd(8) 以使此共享可用,并尝试从工作站装载它。确认目录包含一个从客户端可见的基本用户区,并且客户端无法写入文件系统。

您的无盘主机需要root密码。使用 chroot(8)passwd(1) 设置它。

您需要告诉主机其根文件系统是只读的。创建 /diskless/1/etc/rc.conf 并将 root_rw_mount 设置为 NO 。当您在该目录中时,也为您的客户端创建一个 resolv.conf

现在重新启动无盘客户端,看看会发生什么。它应该找到内核并引导到未配置的多用户模式。根据服务器、客户端和网络速度,这可能需要一段时间才能完成。

此时,您可以配置您的用户空间,以专门匹配您的单个无盘客户端。您可以在 /etc 中进行更改,例如创建反映您需求的 /etc/fstab,并将密码文件复制到位。对于一个无盘客户端来说,这就足够了,但FreeBSD的基础设施是专门为支持同一文件系统中的数十或数百台主机而设计的。让我们来看看这是如何做到的。

无盘场配置

无盘系统的好处之一是多台机器可以共享同一个文件系统。然而,即使在基本相同的机器上,您也可能会发现必须使某些配置文件略有不同。FreeBSD包括一种机制,通过在 tmpfs(5) 临时文件系统上 remounting 目录并将自定义文件复制到这些分区,在统一的用户空间上提供个性化的配置文件。

FreeBSD的默认无盘设置允许您跨多个网络和子网配置无盘工作站,这在大型网络上是一个非常宝贵的功能。然而,如果你只有几个无盘系统,起初你可能会觉得有点麻烦。然而,随着时间的推移,你会发现你越来越多地使用它。无盘系统是解决许多问题的方便方法。

引导FreeBSD系统使用 vfs.nfs.diskless_valid 来查看它是否运行无盘。如果sysctl等于 0 ,则它正在硬盘上运行;否则,它将无盘运行。在无盘系统上,FreeBSD运行 /etc/rc.initdiskless 脚本来解析和部署分层无盘配置。

配置层次结构

在无盘主机的 /conf 中配置您的无盘服务器场。/conf 目录中可以有一大堆目录。两个关键的目录是 /conf/base/conf/default ,但您也可能有单独的子网和/或单个IP地址目录。无盘系统使用这些目录的内容在挂载的根分区上构建tmpfs文件系统,这样单个主机就可以拥有唯一的设置和读写文件系统。您可以将任何目录设置为tmpfs文件系统并从该层次结构填充它,但每个主机都需要一个读写 /etc 目录,因此我们将使用它作为示例。

/conf/base 目录包含需要在无盘客户端上以读写方式挂载的基本系统文件。创建 /conf/base/etc 并用一组 /etc 文件填充它,无盘主机可以将它们用作其tmpfs /etc 的基础。(它还可以回收无盘根目录等,我们稍后会看到。)

/conf/default 目录包含您环境的默认值。也许您环境中的每个主机都需要一个 /etc/fstab 来引导它挂载共享数据存储。您可以创建 /conf/defaults/etc/fstab,无盘系统会将其从 /conf/base/etc 复制到基础系统之上的每个主机。我还将在默认目录中分发您环境的通用 rc.conf

您还可以拥有每个子网的目录。以子网的广播地址(网络中的顶部地址)命名该目录。我的无盘服务器场在子网198.51.100.0/24上运行,广播地址为198.51.100.255。如果我创建了 /conf/198.1.100.255/etc/rc.conf ,则该子网中的每个主机都将获得该 rc.conf 。如果我在该子网上为无盘主机提供了一个特殊的 /etc/fstab ,我可以将其放在 /conf/198.51.100.255/etc/fstab 中,它将覆盖默认值。我还将在 /etc/rc.conf.d/ 中为仅在该子网上运行的特殊服务添加文件。

最后,我可以有每个主机的目录。如果我创建了 /conf/198.51.100.101/etc/rc.conf.d/apache ,那么主机198.51.100.101——并且只有该主机——将获得该文件。如果该特定主机需要一个真正唯一的 /etc/fstab ,我可以将其放在 /conf/198.51.100.101/etc/fstab 中,它将覆盖默认值和子网 /etc/fstab

这种分层配置是通过一个称为无盘重新挂载(diskless remounting)的过程部署的。

无盘重新挂载 /etc

无盘系统检查 /conf/base/etc/diskless_remount 文件,以获取它应该作为内存文件系统挂载的目录列表。没有这个文件,就不会创建内存文件系统,您的无盘主机与所有其他无盘主机共享一个只读用户区。diskless_remount 文件包含要重新装载的文件系统列表。

这篇文章告诉FreeBSD构建一个MFS /etc ,并将无盘根的现有 /etc 复制到它上面,为我们提供了一个工作的基础。

您不一定希望无盘根目录 /etc 中的所有文件都在无盘主机 /etc 上。这是一个内存文件系统,那么为什么要浪费内存来存放不需要的东西呢?您也不想向初级系统管理员暗示主机支持他们不支持的功能。无盘系统不应该在本地保存日志,所以它们不需要 newsyslog/etc/newsyslog.conf 。你不备份无盘客户端,所以 /etc/dumpdates 也是不必要的。浏览 /etc 将显示许多与无盘主机无关的文件。然而,如果你删除了太多,你的系统将无法启动,必要文件的列表也不直观。例如,如果删除 /etc/mtree ,机器将挂在单用户模式下,因为它无法重新填充MFS /var 分区。

将不需要的文件和目录的完整路径放在 /conf/base/etc.remove 文件中。例如,以下条目删除了 /etc/gss/etc/bluetooth 目录以及前面讨论的syslog和备份文件。您不需要复制 /etc/resolv.conf 。FreeBSD的 /etc/rc.d/resolv 启动脚本会从启动主机的原始DHCP响应中创建一个。

没那么难吧?

现在让我们把一些东西放回我们的配置中。

完成设置

现在您已经安装了系统,让我们进行一些微调。无盘客户端需要第三方软件包和各种配置文件。完成客户端设置的最简单、最安全的方法是使用 chroot(8) 程序,该程序将您锁定到文件系统的子目录中。通过在NFS服务器上使用 chroot(8) ,您可以几乎完全像无盘客户端上一样对文件系统进行读写访问。

是的,/etc 仍然具有层次覆盖,但系统的其他部分与无盘客户端看到的完全相同。在chrooted期间所做的任何更改都将与客户端保持一致。

安装软件包

使用 pkg(8) 在无盘客户端上安装软件。使用 -c 标志指定无盘根目录,并将 pkg(8) chroot放入其中。

现在,您的无盘客户端上已经有了包工具、数据库和存储库信息。

以这种方式安装您需要的任何软件。

SSH 密钥

也许无盘客户端最烦人的事情是主机的SSH密钥。在正常操作中,每个主机都需要唯一的SSH密钥。如果您在专用网络上运行,您可能会决定让所有无盘客户端共享相同的SSH密钥。您可能会决定让每个主机在启动时自动生成新的SSH密钥。由于tmpfs上存在 /etc ,这些密钥将在关闭时消失,但用户会很快习惯“主机密钥已更改”的消息。不过,这并不是你希望用户习惯的。

然而,为每个无盘客户端建立持久、唯一的主机密钥并不难。为每个主机创建一个 /conf 目录。

在此目录中,为您的SSH版本使用的每种算法创建SSH密钥。虽然 ssh-keygen(1) 包含 -A 标志来自动生成丢失的密钥,但它将这些密钥放在 /etc/ssh 中。这不适用于您的无盘用户区,甚至在chroot中也不起作用。你需要用老式的方法创建这些密钥。

您需要用小写两次替换加密算法的名称。例如,以下是如何创建DSA SSH密钥:

如今,OpenSSH为RSA、ECDSA和ED25519创建密钥。创造每一个。密钥创建很容易编写脚本。示例请参见 /etc/rc.d/shd

无盘客户端使您可以轻松运行数千台几乎相同的机器。现在让我们来看看只保护一个。

存储加密

FreeBSD支持两种不同的磁盘加密方法,GBDE和GELI。这两种工具的工作方式非常不同,支持不同的加密算法,并且针对不同的威胁模型而设计。人们一直在谈论加密磁盘,但你很少听到关于磁盘加密应该保护磁盘免受什么影响的讨论。

GBDE,即基于Geom的磁盘加密(Geom-Based Disk Encryption),具有针对高安全环境的特定功能,在这些环境中,保护用户与隐藏数据同样重要。除了用户提供的加密密钥外,GBDE还使用存储在硬盘驱动器特定扇区中的密钥。如果任一密钥不可用,则无法解密分区。为什么这很重要?如果一个安全的数据中心(比如大使馆)受到攻击,运营商可能有一两分钟的时间销毁硬盘上的密钥,使数据无法恢复。如果坏人拿枪指着我的头,告诉我“输入密码或其他”,我希望磁盘系统说,密码是正确的,但密钥已被销毁( The passphrase is correct, but the keys have been destroyed. )。我不希望出现一个通用错误,即无法解密磁盘(Cannot decrypt disk)。在第一种情况下,我作为哭泣的人质仍然有价值;在后者中,要么我死了,要么攻击者变得令人不快

GELI更灵活,但它不会像GBDE那样保护我免受身体伤害。如果有人可能会窃取我的笔记本电脑上的机密文件,或者如果一个不受信任的系统用户可能会窥探我的交换空间来窃取机密,GELI就足够了。GELI不试图保护我的人身安全,只保护我的数据。由于我不会接受任何暴露于枪支风险高于平均水平的工作(记住我住在底特律),这对我来说完全没问题。GELI还使用FreeBSD的加密设备驱动程序,这意味着如果你的服务器有硬件加密加速器,GELI会透明地利用它。

我应该提到的是,人们因加密配置错误或丢失密钥而丢失的数据比笔记本电脑被盗丢失的数据更多。当我听到有人说,“我已经加密了我的整个硬盘!”我对未来有一种近乎通灵的愿景,同一个人说,“在我的硬盘上,我失去了对所有东西的访问!”通常情况下,我是对的。仔细考虑你是否真的需要磁盘加密。如果你确实需要它,也要备份你的文件。那些政府间谍不会破解你笔记本电脑的加密。他们会等你自己解密,然后他们就会闯入。

如果你想加密你的笔记本电脑,请使用FreeBSD安装程序。你仍然应该阅读本节,以便了解磁盘加密的工作原理,但如果安装程序想为你做这项工作,那就顺其自然吧。我们将使用GELI加密 /dev/da0 上的磁盘分区,将加密密钥存储在 /media 上安装的USB存储设备上。您可能会发现,在文件中使用文件系统(见第13章)作为加密分区更为合理。很少有人真正需要加密他们的整个硬盘,在某些情况下,这样做可能会引起怀疑。我很难向机场安保人员解释为什么我的电脑“看起来很奇怪”(“looks so weird.”)。在他们看来,一个提示“插入加密密钥并输入加密密码”的启动提示离这个人只有一步之遥。这个人是一个危险的疯子,需要进行非常彻底的体腔搜查。如果你真的需要加密某些文档,它们的总容量可能只有几兆字节。对于文件或闪存驱动器中的文件系统来说,这是一个完美的应用程序。

Insert cryptographic key and enter cryptographic passphrase is only one step away from This man is a dangerous lunatic who requires a very thorough body cavity search.

请注意,在使用GELI之前,您必须加载 geom_eli.ko 内核模块。

生成和使用加密密钥

GELI允许您使用密钥文件和/或密码作为加密设备的加密密钥。我们两者都用。要生成加密密钥文件,请使用 dd(1)/dev/random 获取适量数据并将其写入文件。记住,/media 是我们USB设备的安装位置。如果你真的想保护你的数据,直接在USB设备上创建你的密钥,不要把它放在文件系统上,因为假设的入侵者可能会恢复它。(即使删除文件,也会留下一些残留物,熟练的攻击者也可以提取。)

64字节的数据构成512位密钥。如果愿意,您可以增加密钥的大小,但在访问加密文件系统时需要额外的处理器开销。别忘了,你的密码也会增加密钥的复杂性。

要为密钥分配密码,请使用 geli init-s 标志告诉 geli(8) 加密文件系统上所需的扇区大小;4096字节,即4KB,对于这个应用程序来说通常是一个不错的扇区大小。-K 表示密钥文件。您还必须指定要加密的设备。

密码短语与密码非常相似,除了它可以包含空格和任何长度。如果你真的想保护你的数据,我建议使用几个单词长、包含非字母数字字符且不是母语短语的密码。

现在您有了密钥,请将其附加到要加密的设备上。

GELI现在知道 /dev/da0p1 是一个加密磁盘,/media/da0p1.key 文件包含密钥文件。输入密码后,您可以在新设备节点 /dev/da0p1.eli 访问加密磁盘的解密内容。当然,您需要一个文件系统来将任何数据放在该磁盘上。

加密设备上的文件系统

在加密设备上构建文件系统之前,请清除磁盘上的任何残留数据。像 newfs(8)zpool(8) 这样的程序实际上不会覆盖新分区中的大部分位;它们只是添加指示inode位置的超级块。如果您以前使用过此磁盘,入侵者将能够看到磁盘上的旧文件块。更糟糕的是,他会看到吉利放置在那里的加密数据块。在将文件系统放在磁盘上之前,最好用随机性的欺骗性薄膜覆盖磁盘,使入侵者更难识别哪些块包含数据,哪些块不包含数据。再次使用dd(1)

FreeBSD有无限的混乱——或者,用技术术语来说,/dev/random 是非阻塞的(nonblocking)。用高质量随机性覆盖整个磁盘所需的时间取决于您的存储系统。这可能需要一天的时间。

现在你的磁盘已经充满了垃圾,在上面放一个文件系统并将其连接到你的系统。我经常在这种加密设备上使用UFS。

您的加密磁盘设备现在可以在 /mnt 上使用。将您的机密文件存储在那里。

加密磁盘有更多的可能性。要么阅读 geli(8) ,要么看看我的书 FreeBSD Mastery:Storage Essentials(倾斜风车出版社,2014)。

这将带您穿越FreeBSD的一些阴暗角落。现在让我们看看当事情真的出错时该怎么办。