安全

对称加密

师成师成· 更新于 2026-09-28· 阅读 10 分钟· 0 次阅读

登录后可跨设备保存划线和私人笔记登录

在安全模式下,Ozone 会签发令牌来授权并验证每一次块和容器的访问。传统上,每个令牌由 Ozone Manager(OM)或 Storage Container Manager(SCM)使用 RSA 私钥签名,并由 Datanode 使用公钥和证书进行验证。然而,当 RSA 私钥长度为 2048 位时,签名操作的计算开销很大,可能占 Ozone Manager 读写操作延迟的 80% 以上。

由于 Ozone Manager 在设计上不支持水平扩展,最小化运行开销对于实现亚毫秒级延迟至关重要。非对称密钥签名无法满足这一要求。解决方案是使用对称密钥算法(例如配合 SHA256 的 HMAC)来签名令牌——这与 HDFS 的工作方式类似。该方法将签名生成的开销从毫秒级降低到微秒级。

相对于非对称加密的性能优势

方面非对称(RSA-2048)对称(HMAC-SHA256)
签名速度毫秒微秒
CPU 开销高低
延迟影响>80% 的 OM 读写延迟可忽略
可扩展性受签名开销限制高度可扩展

共享密钥模型

对称密钥算法要求签名方(OM)和验证方(Datanode)共享同一个 SecretKey。这就需要在各个 Ozone 组件之间管理 SecretKey 的分发和生命周期。

架构概览

各组件职责:

组件职责
SCM数据权威来源。负责生成、轮换、存储和分发 SecretKey。
OM从 SCM 获取当前 SecretKey,进行缓存,并使用 HMAC 签名块令牌。
Datanode通过心跳/注册接收 SecretKey,使用缓存的密钥验证令牌。

SecretKey 流转:

SecretKey 生命周期

密钥结构

每个 SecretKey 封装了以下内容:

  • ID:SecretKey 的唯一标识符
  • creationTime:密钥创建时间戳
  • expiryTime:creationTime + X 天(可配置的过期时长)
  • secretKey:实际的对称密钥材料

密钥生成与存储

  • SCM 生成 SecretKey,并将其持久化存储在 SCM 文件系统中
  • 每个 SCM 独立生成自己的 SecretKey
  • SCM 同时维护当前活跃的 SecretKey 以及所有未过期的密钥
  • 密钥存储在 <hdds.metadata.dir>/scm/<hdds.key.dir.name> 路径下的 KeyStore 文件中
  • 文件权限仅限 SCM 进程属主进行只读访问

密钥轮换

SCM 主动生成并分发下一个 SecretKey,以确保当前活动密钥在启用之前就已经存在于各数据节点上:

// When SCM first starts
currentKey = generateSecretKey();
nextKey = generateSecretKey();
allKeys.add(currentKey);
allKeys.add(nextKey);

// Key rotation (periodic)
currentKey = nextKey;
nextKey = generateSecretKey();
allKeys.add(nextKey);
filterExpiredSecretKeys(allKeys);

在每个轮换周期中:

  1. 先前生成的 nextKey 成为 currentKey
  2. 为下一个周期生成新的 nextKey
  3. 过期的 SecretKey 从活动集合中移除

密钥分发

发送给 Ozone Manager

  • OM 通过 RPC 从 SCM(leader)获取当前的 SecretKey
  • 为提升性能,OM 会以可配置的 TTL 在内存中缓存该 SecretKey
  • 签名的令牌包含 SecretKey ID,使 Datanode 能够识别应使用哪个密钥进行验证

发送给 Datanode

Datanode 通过两种机制接收 SecretKey:

  1. 注册:当 Datanode 加入或重新加入集群时,它会向所有 SCM 实例注册,并获取当前所有未过期的 SecretKey
  2. 心跳:在处理心跳的过程中,SCM 会检查是否需要分发新的 SecretKey,并将其包含在心跳响应中

Datanode 使用 HashMap 将 SecretKey 存储在内存中,以便通过 ID 快速查找。它们还会定期移除过期的密钥。

特殊事件处理

OM 重启

重启后,OM 会调用 SCM 获取并缓存当前的 SecretKey。

SCM 重启

重启后,SCM 会:

  1. 读取存储的文件,加载未过期的 SecretKey
  2. 移除任何已过期的密钥
  3. 根据已加载密钥的时间戳确定 currentKey
  4. 如有必要,生成新的 nextKey

如果所有存储的密钥都已过期,SCM 将如同全新启动一样运行。

下表展示了在密钥过期周期为 7 天的情况下,SCM 的密钥恢复行为。在此示例中,kN 代表第 N 天生成的密钥。假设 SCM 一直运行到第 6 天,存储了密钥 k1-k7(其中 k6 为 currentKey,k7 为 nextKey),随后宕机。表格展示了 SCM 在不同日期重启时会发生什么:

存储的密钥重启日期密钥恢复结果
k1-k7第 6 天currentKey = k6,nextKey = k7,allKeys = [k1, k2, k3, k4, k5, k6, k7]
k1-k7第 7 天currentKey = k7,nextKey = generateNewKey(),allKeys = [k1, k2, k3, k4, k5, k6, k7, nextKey]
k1-k7第 8 天currentKey = k7,nextKey = generateNewKey(),allKeys = [k2, k3, k4, k5, k6, k7, nextKey]
k1-k7第 13 天currentKey = k7,nextKey = generateNewKey(),allKeys = [k7, nextKey]
k1-k7第 14 天currentKey = generateNewKey(),nextKey = generateNewKey(),allKeys = [currentKey, nextKey]

说明:

  • 第 6 天:与关机同一天,密钥按原样恢复
  • 第 7 天:k7 被提升为 current,生成新的 nextKey
  • 第 8 天:k1 过期(第 1 天生成 + 7 天 = 第 8 天),从 allKeys 中移除
  • 第 13 天:仅 k7 仍然有效,k1-k6 全部过期
  • 第 14 天:所有存储的密钥都已过期(k7:第 7 天 + 7 天 = 第 14 天),生成全新的密钥

SCM 故障切换

当 SCM 领导权转移到新实例时:

  • 新 SCM 的 SecretKey 应当已经存在于各数据节点上(因为数据节点会向所有 SCM 实例注册)
  • OM 可以继续使用其缓存的 SecretKey,直到缓存过期
  • 数据节点缺少所需 SecretKey 的边缘情况,通过最终一致性机制加以处理

数据节点缺失 SecretKey

如果数据节点找不到所需的 SecretKey:

  1. 它会立即触发一次心跳,从所有 SCM 更新 SecretKey
  2. 向客户端返回 SecretKeyNotFound 错误
  3. 客户端改用管线中的其他节点进行重试
  4. 如果所有节点都失败,客户端会向 OM 请求最新的块信息,并带上一个用于刷新 SecretKey 缓存的标志
  5. 系统会发出一个指标,以便在监控中暴露该情况

合规性与安全标准

算法选择

遵循 NIST SP 800-133 关于消息认证码的建议,Ozone 选用 HMAC,原因是:

  • 性能极高
  • 受 Java 安全核心(Java Security Core)支持
  • 符合安全标准

默认配置使用 基于 SHA256 的 HMAC,根据 NIST SP 800-57,它可提供 128 位的安全强度。

密钥生成

SecretKey 使用 Java 的 SecureRandom 生成,符合 FIPS 140-2 对经认可的随机数生成器的要求。

密钥存储

  • SecretKey 持久化存储在 KeyStore 文件中
  • 文件权限仅限所有者读取
  • 位置:<hdds.metadata.dir>/scm/<hdds.key.dir.name>

密钥传输

SecretKey 通过受 TLS 保护的 RPC 连接在 SCM、OM 与数据节点之间传输,确保传输过程中的机密性。

评论

登录后参与评论

正在加载评论…