ZFS on Linux 0.8.0 原生加密与迁移

友情提示:开启 ZFS 原生加密会导致硬盘 I/O 性能严重下降,请谨慎考虑,不建议在生产环境中使用。

自从 ZFS 支持 Native Encryption 后就迫不及待想尝试,但由于之前用的是 dm-crypt ,所以需要先去掉 LUKS 层,虽然不是必要的。如果原本没有开启 dm-crypt 加密的话,那么直接用 zpool upgrade 命令升级池就可以了,非常方便。

1.加密

通过创建池或数据集时设置 encryption,keyformat,keylocation 这三个属性,可以开启加密:

池加密(使用 dd 生成的 raw 密钥):

「请务必备份好您的密钥!」

dd if=/dev/urandom of=/etc/zfskey bs=32 count=1

zpool create -O encryption=aes-256-gcm -O keyformat=raw -O keylocation=file:///etc/zfskey -R /mnt tank /dev/sdXy

数据集加密:

zfs create -o encryption=aes-128-gcm -o keyformat=passphrase tank/dataset1

数据集加密后,如果是手动导入池,则需要手动加载密钥解密,然后挂载

zfs load-key -L file:///etc/zfskey -a

zfs mount -a

2.传输

需要注意的是,如果父数据集或池开启了加密,那么子数据集也必须要是加密的才行。比如用 zfs send 命令发送快照到一个加密的池或数据集,需要在传输的过程中加密:

zfs send -Rv tank/dataset1 | zfs recv -o encryption=on -o keyformat=raw -o keylocation=file:///etc/zfskey somepool/dateset2

这条命令中,由于是通过管道直接收发,标准输入被 ZFS 占用(当然,从快照备份还原也会被占用),所以无法使用交互式界面输入密码,只能指定预先设置好的密钥文件。

如果是发送已加密的数据到未加密的数据集,直接使用 zfs send/recv 命令收发,接受到的数据集是未加密的,如果想让数据集在发送过程中保持加密,需要使用 zfs send -w 命令发送。如果是把已加密的数据发送到已加密的数据集,则必须使用 -w 参数。

3.性能

文章的开头说过,开启 ZFS 原生加密会导致硬盘 I/O 严重下降,由于我现在已经不再使用 ZFS 原生加密,这里就大概描述一下:

  • 西数(日立)6T 金盘:
  • 未加密或使用 LUKS 时读写约为: 220MB/s
  • 使用 ZFS 原生加密后读写约为:20MB/s

这是我 NAS 服务器上的硬盘,在开启 ZFS 原生加密后对数据传输的影响比较大,所以我把加密去掉了,希望后面会有所改善。

4.引导 ZFS 根文件系统(Root on ZFS with Native Encryption)

这一小节只是为需要加密根分区的人介绍。使用原生加密比使用 LUKS 层的设置要简单得多,建议使用最新版的 dracut 作为 initramfs 生成工具。

使用 dracut 制作 initramfs ,主要注意两点,一个是将 ZFS 密钥通过 –install(-optional) 参数加入到 initramfs 中,(你也可以放到其他设备上,或者使用例如智能卡之类的设备),还有就是设置好内核参数。下面这条内核参数,包含了:Rescue Shell,ZFS 根数据集,文件系统类型和挂载参数这四个参数。必要时也可以加上 zfs_force=1相当于 zpool import -f):

rd.shell=1 root=zfs:WS-Sys/Gentoo/Root rootfstype=zfs rootflags=rw,relatime,seclabel,xattr,noacl

跟 LUKS 相比,省去了 /etc/fstab 以及 /etc/crypttab 以及其他设置,方便了不少。

以上是对 ZFS 原生加密的一点使用体验,如果错误之处,欢迎指出。