强曰为道
与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

Rekor 透明日志完整教程 / 03 - 基本操作

第 3 章:基本操作

本章将带你通过 rekor-cli 和 cosign 进行 Rekor 的日常操作,包括创建日志条目、查询、搜索、验证包含证明等核心功能。


3.1 操作概览

Rekor 的基本操作可以分为以下几类:

操作类别 说明 主要命令
日志信息 查看 Rekor 日志状态 rekor-cli loginfo
创建条目 将签名记录上传到透明日志 rekor-cli upload
查询条目 根据索引或 UUID 查询日志条目 rekor-cli get
搜索条目 根据条件搜索日志条目 rekor-cli search
验证条目 验证条目的包含证明 rekor-cli verify
验证日志 验证日志的完整性和一致性 rekor-cli logproof

3.2 查看日志信息

3.2.1 获取日志状态

# 查看公共 Rekor 实例的日志信息
rekor-cli loginfo

# 预期输出示例:
# [rekor root hash]: 4b8e2b5a45e3...
# [tree size]: 534,218,392
# [tree ID]: 3747744012

这个命令返回三个关键信息:

字段 说明
Root Hash Merkle Tree 的根哈希,代表整个日志的当前状态
Tree Size 日志中的总条目数
Tree ID 日志树的唯一标识符

3.2.2 指定自定义 Rekor 服务器

# 使用自定义 Rekor 实例
rekor-cli loginfo --rekor_server=https://rekor.mycompany.com

# 使用环境变量
export REKOR_SERVER=https://rekor.mycompany.com
rekor-cli loginfo

3.3 创建日志条目

3.3.1 上传哈希记录

最基础的操作是将一个文件的哈希值上传到 Rekor:

# 计算文件的 SHA256 哈希
sha256sum myartifact.tar.gz

# 创建一个哈希记录并上传
rekor-cli upload \
  --artifact myartifact.tar.gz \
  --signature myartifact.sig \
  --public-key mykey.pub \
  --rekor_server=https://rekor.sigstore.dev

# 预期输出:
# Created entry at index 12345678, available at:
# https://rekor.sigstore.dev/api/v1/log/entries/<UUID>

3.3.2 使用 cosign 创建条目(推荐)

cosign 自动与 Rekor 集成,签名时会自动上传记录:

# 签名一个文件并自动上传到 Rekor
cosign sign-blob \
  --key cosign.key \
  --yes \
  myartifact.tar.gz

# 预期输出:
# Using payload from: myartifact.tar.gz
# Enter password for private key:
# tlog entry created with index: 12345678
# ZXlKaGJHY2lPaUp...

3.3.3 签名容器镜像

# 对容器镜像进行签名
cosign sign \
  --key cosign.key \
  --yes \
  ghcr.io/myorg/myimage:v1.0.0

# 签名后自动创建 Rekor 条目
# 预期输出:
# Pushing signature to: ghcr.io/myorg/myimage:sha256-abc123.sig
# tlog entry created with index: 12345679

3.3.4 无密钥签名(Keyless Signing)

# 使用 OIDC 身份进行无密钥签名
cosign sign-blob \
  --yes \
  --identity-token=$(curl -s -H "Authorization: bearer $GITHUB_TOKEN" \
    "https://api.github.com/meta" | jq -r '.git_signing_key') \
  myartifact.tar.gz

# GitHub Actions 环境(自动检测)
# 只需设置 --yes 即可
cosign sign-blob --yes myartifact.tar.gz

3.4 查询日志条目

3.4.1 根据日志索引查询

每个 Rekor 条目都有一个唯一的日志索引(Log Index):

# 根据索引查询条目
rekor-cli get --log-index=12345678

# 预期输出(JSON 格式):
# {
#   "body": { ... },
#   "integratedTime": 1704067200,
#   "logID": "c0d23d6ad406...",
#   "logIndex": 12345678,
#   "verification": {
#     "inclusionProof": { ... }
#   }
# }

3.4.2 根据 UUID 查询

每个条目还有一个唯一 UUID(由条目内容的哈希决定):

# 根据 UUID 查询
rekor-cli get --uuid=<entry-uuid>

# UUID 通常在上传时返回,也可以通过搜索获得

3.4.3 查询条目的详细信息

# 获取更详细的输出
rekor-cli get --log-index=12345678 --format=json | jq '.'

# 查看条目的关键字段
rekor-cli get --log-index=12345678 --format=json | jq '{
  logIndex: .logIndex,
  integratedTime: .integratedTime,
  logID: .logID,
  bodyKind: .body.kind,
  bodySpec: .body.spec
}'

3.4.4 条目字段说明

字段 类型 说明
body Object 条目主体,包含签名和验证数据
body.kind String 条目类型(hashedrekord, intoto, dsse 等)
body.apiVersion String API 版本
integratedTime Integer 写入时间戳(Unix 时间)
logID String 日志树 ID
logIndex Integer 条目在日志中的位置
verification Object 包含证明和签名数据
verification.inclusionProof Object Merkle 包含证明

3.5 搜索日志条目

3.5.1 根据公钥搜索

# 搜索使用特定公钥签名的所有条目
rekor-cli search --public-key=mykey.pub

# 输出:匹配的日志索引列表
# Found matching entries (listed by LogIndex):
# 12345678
# 12345690
# 12345700

3.5.2 根据哈希搜索

# 根据构件哈希搜索
rekor-cli search --sha256=$(sha256sum myartifact.tar.gz | awk '{print $1}')

3.5.3 根据 Email 搜索

# 搜索与特定 Email 关联的条目
rekor-cli search --email=[email protected]

3.5.4 根据 PKI 属性搜索

# 根据 x509 证书的 Subject 搜索
rekor-cli search --pki-format=x509 \
  --public-key=cert.pem

3.5.5 批量搜索并获取详情

# 搜索并批量获取条目详情
for index in $(rekor-cli search --sha256=$(sha256sum myartifact.tar.gz | awk '{print $1}') | grep -oE '[0-9]+'); do
  echo "=== Entry at index $index ==="
  rekor-cli get --log-index=$index --format=json | jq '{
    logIndex: .logIndex,
    integratedTime: (.integratedTime | todate),
    bodyKind: .body.kind
  }'
done

3.6 验证包含证明

包含证明(Inclusion Proof)是透明日志的核心能力之一,它能数学证明某个条目确实存在于日志中。

3.6.1 基本验证

# 验证一个条目的包含证明
rekor-cli verify --log-index=12345678

# 预期输出:
# OK: Entry is included in the transparency log

3.6.2 根据 UUID 验证

rekor-cli verify --uuid=<entry-uuid>

3.6.3 验证并输出证明详情

# 获取详细的包含证明信息
rekor-cli get --log-index=12345678 --format=json | jq '.verification.inclusionProof'

# 预期输出:
# {
#   "hashes": [
#     "abc123...",
#     "def456...",
#     ...
#   ],
#   "logIndex": 12345678,
#   "rootHash": "4b8e2b5a...",
#   "treeSize": 534218392
# }

3.6.4 包含证明的组成部分

组件 说明
hashes Merkle Tree 中从叶子到根的路径上的兄弟节点哈希
logIndex 条目在日志中的索引位置
rootHash 计算得到的 Merkle Tree 根哈希
treeSize 创建证明时的树大小

3.6.5 包含证明验证过程

叶子哈希 (entry hash)
    │
    ├─ 与 sibling hash 1 合并
    │   │
    │   ├─ 与 sibling hash 2 合并
    │   │   │
    │   │   └─ ... 递归合并 ...
    │   │
    │   └─ 中间节点
    │
    └─ 最终应等于 Root Hash

验证逻辑:

# 简化的 Python 验证逻辑
import hashlib

def verify_inclusion(entry_hash, proof_hashes, log_index, root_hash):
    current_hash = entry_hash
    idx = log_index
    
    for sibling_hash in proof_hashes:
        if idx % 2 == 0:
            # 当前节点是左子节点
            combined = current_hash + sibling_hash
        else:
            # 当前节点是右子节点
            combined = sibling_hash + current_hash
        
        current_hash = hashlib.sha256(combined).digest()
        idx //= 2
    
    return current_hash == root_hash

3.7 时间戳验证

3.7.1 获取条目的集成时间

# 获取条目写入时间
rekor-cli get --log-index=12345678 --format=json | jq '.integratedTime'

# 将 Unix 时间戳转换为可读格式
date -d @1704067200 "+%Y-%m-%d %H:%M:%S %Z"
# macOS:
date -r 1704067200 "+%Y-%m-%d %H:%M:%S %Z"

3.7.2 时间戳的意义

Rekor 的 integratedTime 代表签名被写入透明日志的精确时间,这对于:

  1. 证明签名在某个时间点之前存在
  2. 追溯密钥泄露后的历史签名
  3. 满足合规要求中的时间证明
场景 时间戳的用途
密钥泄露 区分泄露前后的签名
证书过期 证明签名时证书仍在有效期
法律合规 提供不可否认的时间证据

3.8 条目类型详解

Rekor 支持多种条目类型(Entry Types),每种类型对应不同的签名格式:

3.8.1 支持的条目类型

条目类型 说明 使用场景
hashedrekord 哈希记录 cosign 签名、普通文件签名
intoto In-toto 布局/链接 软件供应链完整性框架
dsse Dead Simple Signing Envelope 通用签名信封
alpine Alpine 包 Alpine Linux 包验证
cose COSE 签名 CBOR 对象签名
jar Java JAR 包 Java 应用签名
helm Helm Chart Kubernetes Helm Chart
rfc3161 RFC 3161 时间戳 传统时间戳协议
rpm RPM 包 Red Hat 系包管理
tuf TUF 元数据 The Update Framework
x509 X.509 证书 证书记录

3.8.2 查看条目类型

# 查询条目并查看类型
rekor-cli get --log-index=12345678 --format=json | jq '.body.kind'

# 查看条目的 API 版本
rekor-cli get --log-index=12345678 --format=json | jq '.body.apiVersion'

3.8.3 hashedrekord 类型详解

这是最常见的条目类型,由 cosign 创建:

{
  "kind": "hashedrekord",
  "apiVersion": "0.0.1",
  "spec": {
    "data": {
      "hash": {
        "algorithm": "sha256",
        "value": "a]abc123def456..."
      }
    },
    "signature": {
      "content": "base64-encoded-signature",
      "publicKey": {
        "content": "base64-encoded-public-key-or-certificate"
      }
    }
  }
}

3.9 完整工作流示例

3.9.1 签名 → 上传 → 查询 → 验证

#!/bin/bash
set -e

echo "=== 步骤 1: 准备测试文件 ==="
echo "Hello, Rekor!" > test-file.txt
echo "文件已创建: test-file.txt"

echo "=== 步骤 2: 生成密钥对 ==="
COSIGN_PASSWORD=test123 cosign generate-key-pair
echo "密钥对已生成"

echo "=== 步骤 3: 签名并上传到 Rekor ==="
SIGNATURE=$(COSIGN_PASSWORD=test123 cosign sign-blob \
  --key cosign.key \
  --yes \
  --output-signature test-file.sig \
  --output-certificate test-file.cert \
  test-file.txt 2>&1)
echo "签名完成: $SIGNATURE"

echo "=== 步骤 4: 提取日志索引 ==="
LOG_INDEX=$(echo "$SIGNATURE" | grep -oP 'index: \K[0-9]+' || echo "")
echo "日志索引: $LOG_INDEX"

echo "=== 步骤 5: 查询条目 ==="
if [ -n "$LOG_INDEX" ]; then
  rekor-cli get --log-index=$LOG_INDEX --format=json | jq '{
    logIndex: .logIndex,
    integratedTime: (.integratedTime | todate),
    bodyKind: .body.kind
  }'
fi

echo "=== 步骤 6: 验证签名 ==="
cosign verify-blob \
  --key cosign.pub \
  --signature test-file.sig \
  --certificate test-file.cert \
  test-file.txt
echo "签名验证通过!"

echo "=== 步骤 7: 搜索条目 ==="
rekor-cli search --sha256=$(sha256sum test-file.txt | awk '{print $1}')

echo "=== 清理 ==="
rm -f test-file.txt test-file.sig test-file.cert cosign.key cosign.pub
echo "完成!"

3.9.2 无密钥签名工作流

#!/bin/bash
set -e

# 无密钥签名(适用于 CI/CD 环境)
echo "=== 无密钥签名 ==="
cosign sign-blob --yes myartifact.tar.gz

echo "=== 验证签名 ==="
# 验证需要提供身份信息
cosign verify-blob \
  --certificate-identity=[email protected] \
  --certificate-oidc-issuer=https://accounts.google.com \
  myartifact.tar.gz

3.10 API 直接调用

除了使用 CLI 工具,你也可以直接调用 Rekor 的 REST API:

3.10.1 查询日志信息

# 获取日志树信息
curl -s https://rekor.sigstore.dev/api/v1/log | jq '.'

# 获取日志检查点(Signed Tree Head)
curl -s https://rekor.sigstore.dev/api/v1/log | jq '.signedTreeHead'

3.10.2 查询条目

# 根据 UUID 查询
curl -s "https://rekor.sigstore.dev/api/v1/log/entries/<UUID>" | jq '.'

# 根据搜索条件查询
curl -s -X POST "https://rekor.sigstore.dev/api/v1/index/retrieve" \
  -H "Content-Type: application/json" \
  -d '{
    "hash": {
      "algorithm": "sha256",
      "value": "<sha256-of-artifact>"
    }
  }' | jq '.'

3.10.3 上传条目

# 上传一个 hashedrekord 条目
curl -s -X POST "https://rekor.sigstore.dev/api/v1/log/entries" \
  -H "Content-Type: application/json" \
  -d '{
    "apiVersion": "0.0.1",
    "kind": "hashedrekord",
    "spec": {
      "data": {
        "hash": {
          "algorithm": "sha256",
          "value": "<sha256-value>"
        }
      },
      "signature": {
        "content": "<base64-signature>",
        "publicKey": {
          "content": "<base64-public-key>"
        }
      }
    }
  }' | jq '.'

3.10.4 获取包含证明

# 获取包含证明
curl -s "https://rekor.sigstore.dev/api/v1/log/proof" \
  -G \
  --data-urlencode "firstSize=0" \
  --data-urlencode "lastSize=<tree-size>" | jq '.'

# 获取条目的包含证明
curl -s "https://rekor.sigstore.dev/api/v1/log/entries/<UUID>/proof" | jq '.'

3.11 注意事项

速率限制:公共 Rekor 实例有请求频率限制。频繁查询可能返回 429 错误。企业场景建议部署私有实例。

数据不可删除:Rekor 日志是不可篡改的。一旦条目被写入,就无法删除或修改。

条目内容公开:写入公共 Rekor 实例的条目对所有人可见。不要在条目中包含敏感信息。

网络延迟:公共实例的写入可能有短暂延迟,写入后几秒内查询可能失败。


3.12 本章小结

操作 命令 说明
查看日志状态 rekor-cli loginfo 获取树大小和根哈希
签名并上传 cosign sign-blob --key key --yes file 自动创建 Rekor 条目
查询条目 rekor-cli get --log-index=N 根据索引查询
搜索条目 rekor-cli search --sha256=HASH 根据条件搜索
验证包含 rekor-cli verify --log-index=N 验证包含证明
验证签名 cosign verify-blob --key pub --sig sig file 验证签名和 Rekor 记录

扩展阅读


下一章04 - 架构详解 — 深入了解 Rekor 的内部架构、Merkle Tree、Trillian 和透明日志原理。