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 代表签名被写入透明日志的精确时间,这对于:
- 证明签名在某个时间点之前存在
- 追溯密钥泄露后的历史签名
- 满足合规要求中的时间证明
| 场景 | 时间戳的用途 |
|---|---|
| 密钥泄露 | 区分泄露前后的签名 |
| 证书过期 | 证明签名时证书仍在有效期 |
| 法律合规 | 提供不可否认的时间证据 |
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 和透明日志原理。