注意
本文档适用于 Ceph 的开发版本。
镜像加密
从 Pacific 版本开始,RBD 客户端可以在内部处理镜像级别的加密。这意味着您可以设置一个密钥,用于加密特定的 RBD 镜像。本页描述了 RBD 加密功能的范围。
注意
krbd 内核模块目前不支持加密。
注意
也可以使用外部工具(例如 dm-crypt、QEMU)来加密 RBD 镜像,其功能集和限制集可能与此处所述有所不同。
加密格式
默认情况下,RBD 镜像不加密。要加密 RBD 镜像,需要将其格式化为受支持的加密格式之一。格式化操作会将加密元数据持久化到镜像中。加密元数据通常包括诸如加密格式和版本、密码算法和模式规范,以及用于保护加密密钥的信息。加密密钥本身受用户保管的密钥(通常是密码)保护,该密钥永远不会持久化。基本的加密格式化操作将需要指定加密格式和密钥。
一些加密元数据可能作为镜像数据的一部分存储,通常会在原始镜像数据的开头写入一个加密头。这意味着加密镜像的有效镜像大小可能低于原始镜像大小。有关更多详细信息,请参阅支持的格式部分。
注意
除非明确(重新)格式化,否则加密镜像的克隆将固有地使用相同的格式和密钥进行加密。
注意
加密镜像的克隆始终是加密的。不支持重新格式化为明文。
注意
在格式化之前写入镜像的任何数据都可能变得不可读,尽管它可能仍占用存储资源。
注意
启用了日志功能的镜像无法被 RBD 客户端格式化和加密。
加密加载
格式化镜像是启用加密的必要先决条件。但是,所有 RBD API 仍会将格式化的镜像视为原始未加密镜像。特别是,加密的 RBD 镜像可以使用与任何其他镜像相同的 API 打开,并且可以读取/写入原始未加密数据。此类原始 IO 可能会危及加密格式的完整性,例如通过覆盖位于镜像开头的加密元数据。
为了安全地在格式化的镜像上执行加密 IO,在打开镜像后应应用额外的加密加载操作。加密加载操作需要提供加密格式和密钥,以解锁镜像本身及其每个显式格式化祖先镜像的加密密钥。成功执行加密加载操作后,打开镜像的所有 IO 都将进行加密/解密。对于克隆镜像,这也包括对祖先镜像的 IO。加密密钥将由 RBD 客户端存储在内存中,直到镜像关闭。
注意
一旦加载了加密,就不能再对打开的镜像上下文应用其他加密加载/格式化操作。
注意
一旦加载了加密,使用打开的镜像上下文检索镜像大小和父重叠的 API 调用将分别返回有效镜像大小和有效父重叠。
注意
一旦加载了加密,调整镜像大小的 API 调用将把指定的目标大小解释为有效镜像大小。
注意
如果显式格式化了加密镜像的克隆,则扁平化克隆镜像的操作将不再透明,因为父数据必须根据克隆镜像格式进行重新加密,因为它从父快照复制。如果在发出扁平化操作之前未加载加密,则克隆镜像中以前可访问的任何父数据都可能变得不可读。
注意
如果显式格式化了加密镜像的克隆,则缩小克隆镜像的操作将不再透明,因为在某些情况下(例如,如果克隆镜像具有快照,或者如果克隆镜像被缩小到与对象大小不一致的大小),它涉及从父快照复制一些数据,类似于扁平化。如果在发出缩小操作之前未加载加密,则克隆镜像中以前可访问的任何父数据都可能变得不可读。
注意
通过 rbd-nbd 将 RBD 镜像挂载为块设备时,可以自动应用加密加载。
支持的格式
LUKS
支持 LUKS1 和 LUKS2。数据布局完全符合 LUKS 规范。因此,RBD 格式化的镜像可以使用外部支持 LUKS 的工具(例如 dm-crypt 或 QEMU)加载。此外,可以在 RBD 外部创建的现有 LUKS 数据可以导入(通过将原始 LUKS 数据复制到镜像中)并通过 RBD 加密加载。
注意
LUKS 格式仅在基于 Linux 的系统上受支持。
注意
目前,仅支持 AES-128 和 AES-256 加密算法。此外,xts-plain64 是目前唯一受支持的加密模式。
要使用 LUKS 格式,首先格式化镜像
rbd encryption format [--cipher-alg {aes-128|aes-256}] {image-spec} {luks1|luks2} {passphrase-file}
加密格式化操作会生成 LUKS 头部并将其写入镜像开头。头部附加了一个包含随机生成的加密密钥的密钥槽,并受从 passphrase-file 读取的密码保护。
注意
在旧版本中,如果 passphrase-file 的内容以换行符结尾,则会将其剥离。
默认情况下,将使用 xts-plain64 模式下的 AES-256(这是当前推荐的模式,也是其他工具的通常默认设置)。格式化操作也允许选择 AES-128。RBD 目前不支持添加/删除密码,但可以使用兼容工具(例如 cryptsetup)将其应用于原始 RBD 数据。
LUKS 头部大小可以变化(LUKS2 中最大可达 136MiB),但通常最大为 16MiB,具体取决于安装的 libcryptsetup 版本。为了获得最佳性能,加密格式将把数据偏移量设置为与镜像条带周期大小对齐。例如,如果使用配置了 8MiB 对象大小的镜像,则预期最小开销为 8MiB;如果使用配置了 4MiB 对象大小和 条带计数为 3 的镜像,则预期最小开销为 12MiB。
在 LUKS1 中,扇区(最小加密单元)固定为 512 字节。LUKS2 支持更大的扇区,为了更好的性能,我们将默认扇区大小设置为最大 4KiB。小于扇区或未对齐到扇区开头的写入将触发客户端上的受保护读-修改-写链,并带来相当大的延迟惩罚。批量此类未对齐写入可能导致 IO 竞争,从而进一步降低性能。因此,建议在无法保证传入写入与扇区对齐的情况下避免使用 RBD 加密。
要映射 LUKS 格式化的镜像,请运行
rbd device map -t nbd -o encryption-passphrase-file={passphrase-file} {image-spec}
请注意,出于安全原因,加密格式化和加密加载操作都是 CPU 密集型的,可能需要几秒钟才能完成。对于实际镜像 IO 的加密操作,假设启用了 AES-NI,则应增加相对较小的微秒延迟,以及 CPU 利用率的小幅增加。
示例
创建一个有效大小为 50GiB 的 LUKS2 格式化镜像
rbd create --size 50G mypool/myimage
rbd encryption format mypool/myimage luks2 passphrase.bin
rbd resize --size 50G --encryption-passphrase-file passphrase.bin mypool/myimage
末尾的 rbd resize 命令会增加镜像大小以补偿与 LUKS2 头部相关的开销。
给定一个 LUKS2 格式化的镜像,创建一个具有相同有效大小的 LUKS2 格式化克隆
rbd snap create mypool/myimage@snap
rbd snap protect mypool/myimage@snap
rbd clone mypool/myimage@snap mypool/myclone
rbd encryption format mypool/myclone luks2 clone-passphrase.bin
给定一个有效大小为 50GiB 的 LUKS2 格式化镜像,创建一个具有相同有效大小的 LUKS1 格式化克隆
rbd snap create mypool/myimage@snap
rbd snap protect mypool/myimage@snap
rbd clone mypool/myimage@snap mypool/myclone
rbd encryption format mypool/myclone luks1 clone-passphrase.bin
rbd resize --size 50G --allow-shrink --encryption-passphrase-file clone-passphrase.bin --encryption-passphrase-file passphrase.bin mypool/myclone
由于 LUKS1 头部通常小于 LUKS2 头部,因此末尾的 rbd resize 命令会缩小克隆镜像,以摆脱不需要的空间余量。
给定一个有效大小为 50GiB 的 LUKS1 格式化镜像,创建一个具有相同有效大小的 LUKS2 格式化克隆
rbd resize --size 51G mypool/myimage
rbd snap create mypool/myimage@snap
rbd snap protect mypool/myimage@snap
rbd clone mypool/myimage@snap mypool/myclone
rbd encryption format mypool/myclone luks2 clone-passphrase.bin
rbd resize --size 50G --allow-shrink --encryption-passphrase-file passphrase.bin mypool/myimage
rbd resize --size 50G --allow-shrink --encryption-passphrase-file clone-passphrase.bin --encryption-passphrase-file passphrase.bin mypool/myclone
由于 LUKS2 头部通常大于 LUKS1 头部,因此开头的 rbd resize 命令会临时增加父镜像大小,以便在父快照中保留一些额外的空间,从而也保留在克隆镜像中。这对于使所有父数据在克隆镜像中都可访问是必需的。末尾的 rbd resize 命令会将父镜像缩小回其原始大小(这不会影响父快照),也会将克隆镜像缩小以摆脱未使用的保留空间。
这同样适用于创建未格式化(明文)镜像的格式化克隆,因为未格式化镜像根本没有头部。
要映射格式化的克隆,请提供克隆本身及其所有显式格式化的父镜像的加密格式和密码。提供 encryption-format 和 encryption-passphrase-file 选项的顺序基于镜像层次结构:从克隆镜像开始,然后是其父镜像,依此类推。
这是一个映射格式化克隆的命令示例
rbd device map -t nbd -o encryption-passphrase-file=clone-passphrase.bin,encryption-passphrase-file=passphrase.bin mypool/myclone