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

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 HashMerkle 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 条目字段说明

字段类型说明
bodyObject条目主体,包含签名和验证数据
body.kindString条目类型(hashedrekord, intoto, dsse 等)
body.apiVersionStringAPI 版本
integratedTimeInteger写入时间戳(Unix 时间)
logIDString日志树 ID
logIndexInteger条目在日志中的位置
verificationObject包含证明和签名数据
verification.inclusionProofObjectMerkle 包含证明

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 包含证明的组成部分

组件说明
hashesMerkle 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 签名、普通文件签名
intotoIn-toto 布局/链接软件供应链完整性框架
dsseDead Simple Signing Envelope通用签名信封
alpineAlpine 包Alpine Linux 包验证
coseCOSE 签名CBOR 对象签名
jarJava JAR 包Java 应用签名
helmHelm ChartKubernetes Helm Chart
rfc3161RFC 3161 时间戳传统时间戳协议
rpmRPM 包Red Hat 系包管理
tufTUF 元数据The Update Framework
x509X.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 和透明日志原理。