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 的生成与验证流程:
- 构造待签名数据: 将
LogIndex、IntegratedTime、Body的哈希以及LogID按特定格式序列化。 - 日志签名: Rekor 服务器使用其私钥对该数据进行签名,生成 SET。
- 客户端验证: 客户端使用 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 内部字段之间的关系,以及从查询到验证的典型路径。
3.6 字段对比与性能影响
下表总结了三个核心字段在查询、存储和验证方面的特性,帮助你在调优时做出权衡:
| 字段 | 查询效率 | 存储开销 | 验证作用 | 调优建议 |
|---|---|---|---|---|
| Body | 低(需 Base64 解码 + JSON 解析) | 高(可能包含完整工件) | 提供签名和公钥,用于数据完整性验证 | 非必要时使用 excludeBody=true |
| LogIndex | 极高(整数索引,支持范围查询) | 极低(8 字节整数) | 用于定位条目和构建 Merkle 证明 | 作为首选查询键,建立本地索引 |
| Verification | 中(需解析嵌套对象) | 中(包含哈希列表和签名) | 提供日志背书和 Merkle 包含证明 | 仅在需要验证时请求,避免批量拉取 |
冷启动削尖策略: 在冷启动阶段,优先使用
LogIndex 进行批量拉取,并设置 excludeBody=true。先快速建立本地条目索引,再按需回填 Body 和 Verification 进行验证。这能将初始数据加载时间减少 60% 以上。