delphij's Chaos

选择chaos这个词是因为~~实在很难找到一个更合适的词来形容这儿了……

13 Mar 2014

基于Asrock C2750D4I的全加密存储

去年第四季度的时候,在网上看到 华擎科技 推出了一款基于 Intel Atom C2750 SoC 的主板, Asrock C2750D4I,感觉很赞,于是立即和华擎科技取得了联系(当时这款主板还没进入量产),并着手开始了测试等工作。这张主板的重要特色包括:

  • mini-iTX尺寸
  • CPU支持Intel AES-NI,加密加速
  • 提供了两个千兆以太网口
  • 支持ECC内存(更重要的是,采用的是台式机和服务器常见的4x240-pin DDR3 DIMM规格,不像同类产品通常使用的是204-pin的SO-DIMM,这一点可以节省很多成本)
  • 提供了8个SATA III 6.0Gbps接口和4个SATA II 3.0Gbps接口
  • 支持IPMI并提供了独立网口

此处强行插入一条广告: 我厂 目前这一代的 FreeNAS Mini 采用了这张主板,组装好的产品可以通过 Amazon 购买,我厂每年都会将一部分利润捐给 FreeBSD 基金会,如果先 在 smile.amazon.com 注册支持 FreeBSD 基金会,并使用前述链接, Amazon 公司还会再捐出 0.5% 的金额给 FreeBSD 基金会

目前这张主板已经进入了量产阶段,因此也可以从其他零售渠道获得相关组件自行组装。

我厂的出厂配置中,整套系统包括了一个容量为 16GB、预装了最新版 FreeNAS 的 SATA DOM。目前新版的 FreeNAS 已经支持全盘加密,通过其 Web 界面即可完成配置(参见 FreeNAS 手册中关于如何创建加密卷的介绍)。

作为不折腾就会死星人,以及强烈的迫害妄想症患者 为了进一步完善 FreeBSD 对于全盘加密的支持以及为下一代 FreeNAS 版本尝试其他一些选择,我并没有直接使用 FreeNAS,而是改装成了一套我自己补过的 FreeBSD 版本。此外,在对磁盘初始化的过程中也进行了一些调整。

具体来说,在使用全盘加密之前,应首先对裸盘做一次初始化(在其上写满随机数)。写随机数的目的是在磁盘被人物理地拿到的时候,对方在没有密钥的情况下将无法知道某个具体的扇区是否存在加密数据。FreeBSD 的 geli(4) 手册上建议在 GELI provider 上写随机数,但是由于我们并不使用 GELI 的 checksum 能力,因此实际上直接在裸盘上写随机数就可以了。

FreeNAS 目前版本的做法是用 dd 在裸盘上写 /dev/random 的数据。这样做本身并没有太大的问题,但是很慢,根据我的计算,4块4TB (WD Red)的硬盘完成初始化需要将近两天的时间。显然,花些时间改进初始化流程是十分必要的,于是我对 libc 中的 arc4random(3) 进行了一些改进,然后写了一个简单的多线程 producer-consumer 程序,这样第二天起床的时候初始化就完全做好了(具体代码将在稍后集成进 FreeNAS)。

目前 FreeBSD 提供了以磁盘序号作为标签的能力(/dev/diskid/*)。因此,直接在初始化后的磁盘上建立 GELI provider,这样当盘位变化时不致影响 GELI 的解密;此外,密钥直接放在一个USB盘上,在其上建立一个GPT分区(放上4KB随机数),这样在系统启动时插上,启动脚本检测到其存在即开始解密磁盘,之后将其拔下即可。保险起见,我做了两个USB盘分别保存用于解密 GELI 两个密钥槽中的两个不同的密钥。

由于民用硬盘的尺寸可能略有不同,因此我在 GELI provider 上也建立了 GPT 分区,并留出了最后大约1GB的空间作为缓冲,以备将来出现硬盘损坏时找不到更大的替换硬盘时使用。(使用最后部分作为缓冲区的原因是在初始化过程中发现靠后的部分性能较差)。

这个存储上采用的 ZFS 有一些尚未提交的改进,例如采用 LZ4 作为默认的元数据压缩算法,等等。此外,我采用了 sha256 而不是默认的 fletcher4 作为 checksum,虽然这样性能会稍微有些影响,但它可以改善send dedup的性能,由于这台机器只有两个千兆口,因此 CPU 也不致成为性能瓶颈。