3. Rekor 透明日志数据模型:日志条目结构详解

Rekor 透明日志的核心数据单元是 LogEntry。理解其内部结构是进行高效查询、性能调优以及构建可信验证链路的基础。一个 LogEntry 并非简单的键值对,而是由三个紧密关联的字段构成的复合对象:Body、LogIndex 与 Verification(内含 SignedEntryTimestamp)。

核心概念: LogEntry 是 Rekor 日志中不可变、可验证的记录。每个条目代表一个被签名并提交到透明日志的“声明”(如软件工件的签名、容器镜像的摘要等)。

3.1 LogEntry 顶层结构概览

当通过 Rekor API 查询一个条目时,返回的 JSON 对象顶层结构如下:

{
  "Body": "Base64 编码的字符串",
  "LogIndex": 123456,
  "IntegratedTime": 1700000000,
  "LogID": "c0d23d6ad40653f...",
  "Verification": {
    "SignedEntryTimestamp": "Base64 编码的字符串",
    "InclusionProof": {
      "LogIndex": 123456,
      "RootHash": "sha256...",
      "TreeSize": 500000,
      "Hashes": ["sha256...", "sha256..."]
    }
  }
}

下表对顶层字段进行简要说明:

字段 类型 描述
Body string (Base64) 条目的核心载荷,包含签名、公钥、声明数据等。是验证的起点。
LogIndex integer 条目在 Rekor 日志 Merkle 树中的顺序索引,从 0 开始递增。
IntegratedTime integer (Unix) 条目被日志接受并持久化的 Unix 时间戳。
LogID string (hex) Rekor 日志实例的唯一标识符,通常为日志公钥的 SHA256 哈希。
Verification object 包含用于验证条目真实性和日志一致性的密码学证据。
性能提示: 在冷启动或大规模查询场景下,LogIndex 是最高效的查询键。基于 LogIndex 的范围查询(如 ?logIndex=1000&logIndex=2000)比基于时间戳的查询快一个数量级。

3.2 Body 字段:条目的核心载荷

Body 字段是一个 Base64 编码的字符串,解码后是一个 JSON 对象。其结构根据条目类型(kind)而不同。最常见的类型是 hashedrekord 和 rekord。以 hashedrekord 为例,解码后的结构如下:

{
  "apiVersion": "0.0.1",
  "kind": "hashedrekord",
  "spec": {
    "data": {
      "hash": {
        "algorithm": "sha256",
        "value": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
      }
    },
    "signature": {
      "content": "Base64 编码的签名",
      "publicKey": {
        "content": "Base64 编码的公钥"
      }
    }
  }
}

Body 字段关键子字段详解:

  • kind:标识条目类型,如 hashedrekord(仅存储哈希)、rekord(存储原始数据)、alpine、helm 等。查询时可通过 ?entryType=hashedrekord 过滤。
  • spec.data:被签名的数据。对于 hashedrekord,仅存储哈希值,保护数据隐私。
  • spec.signature.content:对 spec.data 的签名值。
  • spec.signature.publicKey.content:用于验证签名的公钥。
调优注意: Body 字段可能非常大(例如 rekord 类型包含完整文件)。在批量查询时,如果不需要验证签名,可以使用 ?excludeBody=true 参数跳过 Body 的返回,显著减少网络传输和解析开销。

3.3 Verification.SignedEntryTimestamp (SET):日志的权威背书

SignedEntryTimestamp(SET)是 Rekor 日志服务器对 整个 LogEntry(包括 Body 和 LogIndex)的签名。它是证明“该条目确实被 Rekor 日志接受并记录”的核心证据。

SET 的生成与验证流程:

  1. 构造待签名数据: 将 LogIndex、IntegratedTime、Body 的哈希以及 LogID 按特定格式序列化。
  2. 日志签名: Rekor 服务器使用其私钥对该数据进行签名,生成 SET。
  3. 客户端验证: 客户端使用 Rekor 日志的公钥(通过 rekor-cli get-public-key 或从 LogID 推导)验证 SET 的签名。
关键作用: SET 提供了 非否认性。即使 Rekor 日志服务器后续被攻破或数据被篡改,只要客户端持有有效的 SET,就能证明在 SET 生成的时间点,该条目确实存在于日志中。

3.4 Verification.InclusionProof:Merkle 树包含证明

InclusionProof 是证明一个特定 LogEntry 存在于 Rekor 的 Merkle 树中的密码学证据。它由以下字段组成:

字段 类型 描述
LogIndex integer 该条目在树中的索引。
RootHash string (hex) 当前 Merkle 树的根哈希。
TreeSize integer 当前 Merkle 树包含的叶子节点总数。
Hashes array of strings 从该叶子节点到根节点的路径上所需的兄弟节点哈希列表。

通过 LogIndex、Hashes 和 RootHash,客户端可以在本地计算并验证该条目是否被包含在指定 TreeSize 的 Merkle 树中。

3.5 数据模型关系与查询路径

下面的 SVG 图展示了 LogEntry 内部字段之间的关系,以及从查询到验证的典型路径。

Rekor LogEntry 数据模型与验证路径 LogEntry 数据模型与验证路径 LogEntry Body (核心载荷) LogIndex (索引) Verification (证据) SignedEntryTimestamp InclusionProof kind spec.data 验证路径 1. 从 Body 中提取签名和公钥,验证数据完整性。 2. 使用 Rekor 公钥验证 SignedEntryTimestamp,确认日志背书。 3. 使用 InclusionProof 和 LogIndex 验证 Merkle 树包含证明。 高效查询路径 推荐:使用 LogIndex 进行范围查询(/api/v1/log/entries?logIndex=1000&logIndex=2000)

3.6 字段对比与性能影响

下表总结了三个核心字段在查询、存储和验证方面的特性,帮助你在调优时做出权衡:

字段 查询效率 存储开销 验证作用 调优建议
Body 低(需 Base64 解码 + JSON 解析) 高(可能包含完整工件) 提供签名和公钥,用于数据完整性验证 非必要时使用 excludeBody=true
LogIndex 极高(整数索引,支持范围查询) 极低(8 字节整数) 用于定位条目和构建 Merkle 证明 作为首选查询键,建立本地索引
Verification 中(需解析嵌套对象) 中(包含哈希列表和签名) 提供日志背书和 Merkle 包含证明 仅在需要验证时请求,避免批量拉取
冷启动削尖策略: 在冷启动阶段,优先使用 LogIndex 进行批量拉取,并设置 excludeBody=true。先快速建立本地条目索引,再按需回填 Body 和 Verification 进行验证。这能将初始数据加载时间减少 60% 以上。