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

Rekor 透明日志完整教程 / 08 - 私有实例部署

第 8 章:私有实例部署

本章介绍如何部署和运维私有 Rekor 实例,适用于企业内网、离线环境或需要自定义配置的场景。


8.1 为什么需要私有实例?

8.1.1 公共实例 vs 私有实例

考量 公共实例 (rekor.sigstore.dev) 私有实例
成本 免费 需要服务器和运维成本
速率限制 有 自定义
数据主权 数据公开,存储在 Sigstore 基础设施 数据完全自控
网络访问 需要互联网 内网可用
定制化 不可定制 完全可定制
高可用 由 Sigstore 维护 自行保障
审计合规 数据在外部 数据在企业内部

8.1.2 适用场景

场景 原因
企业内网开发 无法访问公网
合规要求 数据必须留在企业内部
高写入量 公共实例速率限制无法满足
定制化需求 需要自定义条目类型或验证逻辑
混合部署 公共 + 私有双日志策略

8.2 架构设计

8.2.1 私有 Rekor 部署架构

┌────────────────────────────────────────────────────────────────────┐
│                    私有 Rekor 部署架构                              │
│                                                                    │
│  ┌──────────┐     ┌─────────────────────────────────────────────┐ │
│  │ 客户端   │────►│              负载均衡器 (Nginx/HAProxy)     │ │
│  │ rekor-cli│     └──────────────────┬──────────────────────────┘ │
│  │ cosign   │                        │                            │
│  └──────────┘           ┌────────────┼────────────┐              │
│                         │            │            │              │
│                    ┌────▼────┐  ┌────▼────┐  ┌────▼────┐        │
│                    │rekor-   │  │rekor-   │  │rekor-   │        │
│                    │server-1 │  │server-2 │  │server-3 │        │
│                    └────┬────┘  └────┬────┘  └────┬────┘        │
│                         │            │            │              │
│                         └────────────┼────────────┘              │
│                                      │                            │
│                              ┌───────▼───────┐                  │
│                              │   Trillian    │                  │
│                              │  Log Server   │                  │
│                              └───────┬───────┘                  │
│                                      │                            │
│                              ┌───────▼───────┐                  │
│                              │   Trillian    │                  │
│                              │  Log Signer   │                  │
│                              └───────┬───────┘                  │
│                                      │                            │
│                              ┌───────▼───────┐                  │
│                              │    MySQL /    │                  │
│                              │   PostgreSQL  │                  │
│                              └───────────────┘                  │
│                                                                    │
│                              ┌───────────────┐                  │
│                              │     Redis     │                  │
│                              │   (可选缓存)  │                  │
│                              └───────────────┘                  │
└────────────────────────────────────────────────────────────────────┘

8.2.2 最小化部署 vs 生产部署

组件 最小化部署 生产部署
rekor-server 1 实例 3+ 实例
Trillian Log Server 1 实例 2+ 实例
Trillian Log Signer 1 实例 1 实例(单主)
MySQL/PostgreSQL 1 实例 主从复制
Redis 不需要 集群模式
负载均衡器 不需要 Nginx/HAProxy
监控 不需要 Prometheus + Grafana

8.3 前置依赖安装

8.3.1 安装 MySQL

# Ubuntu/Debian
sudo apt update
sudo apt install -y mysql-server

# 启动 MySQL
sudo systemctl start mysql
sudo systemctl enable mysql

# 创建 Trillian 数据库
mysql -u root -p << 'EOF'
CREATE DATABASE trillian;
CREATE USER 'trillian'@'localhost' IDENTIFIED BY 'trillian_password';
GRANT ALL PRIVILEGES ON trillian.* TO 'trillian'@'localhost';
FLUSH PRIVILEGES;
EOF

8.3.2 安装 Trillian

# 克隆 Trillian 仓库
git clone https://github.com/google/trillian.git
cd trillian

# 编译
go build -o trillian-log-server ./cmd/trillian_log_server
go build -o trillian-log-signer ./cmd/trillian_log_signer
go build -o createtree ./cmd/createtree

# 移动到 PATH
sudo mv trillian-log-server trillian-log-signer createtree /usr/local/bin/

# 初始化数据库
mysql -u root -p trillian < storage/mysql/schema/storage.sql

8.3.3 安装 Redis(可选)

# Ubuntu/Debian
sudo apt install -y redis-server
sudo systemctl start redis-server
sudo systemctl enable redis-server

# 验证
redis-cli ping
# PONG

8.4 Trillian 配置

8.4.1 启动 Trillian Log Server

# 启动 Trillian Log Server
trillian-log-server \
  --mysql_uri="trillian:trillian_password@tcp(localhost:3306)/trillian" \
  --rpc_endpoint=localhost:8090 \
  --http_endpoint=localhost:8091 \
  --logtostderr

# 后台运行
nohup trillian-log-server \
  --mysql_uri="trillian:trillian_password@tcp(localhost:3306)/trillian" \
  --rpc_endpoint=localhost:8090 \
  --http_endpoint=localhost:8091 \
  --logtostderr \
  > /var/log/trillian-server.log 2>&1 &

8.4.2 启动 Trillian Log Signer

# 启动 Trillian Log Signer
trillian-log-signer \
  --mysql_uri="trillian:trillian_password@tcp(localhost:3306)/trillian" \
  --rpc_endpoint=localhost:8092 \
  --http_endpoint=localhost:8093 \
  --logtostderr \
  --force_master

# 后台运行
nohup trillian-log-signer \
  --mysql_uri="trillian:trillian_password@tcp(localhost:3306)/trillian" \
  --rpc_endpoint=localhost:8092 \
  --http_endpoint=localhost:8093 \
  --logtostderr \
  --force_master \
  > /var/log/trillian-signer.log 2>&1 &

8.4.3 创建 Trillian 树

# 创建透明日志树
createtree \
  --admin_server=localhost:8090 \
  --tree_type=LOG \
  --signature_algorithm=ECDSA

# 记录返回的 Tree ID,后续配置 rekor-server 需要
# 例如: Created tree with ID: 1234567890

8.5 Rekor Server 配置

8.5.1 配置文件

创建 Rekor Server 配置文件:

# /etc/rekor/rekor-config.yaml
rekor_server:
  address: 0.0.0.0
  port: 3000

trillian:
  log_server:
    address: localhost
    port: 8090
  
  log_id: 1234567890  # 使用 createtree 返回的 ID

redis:
  address: localhost
  port: 6379
  # 如果不需要 Redis,注释以上两行

enable_attestation_storage: true

attestation_storage:
  backend: blob
  blob:
    bucket: "rekor-attestations"
    # 或使用本地文件系统
    path: "/var/lib/rekor/attestations"

max_apibase_log_entries: 0

log:
  type: "log"
  level: "info"

8.5.2 启动 Rekor Server

# 基本启动
rekor-server serve \
  --trillian_log_server.address=localhost \
  --trillian_log_server.port=8090 \
  --rekor_server.address=0.0.0.0 \
  --rekor_server.port=3000 \
  --log_type=log \
  --log_level=info

# 使用配置文件启动(如果支持)
rekor-server serve --config=/etc/rekor/rekor-config.yaml

# 后台运行
nohup rekor-server serve \
  --trillian_log_server.address=localhost \
  --trillian_log_server.port=8090 \
  --rekor_server.address=0.0.0.0 \
  --rekor_server.port=3000 \
  > /var/log/rekor-server.log 2>&1 &

8.5.3 验证服务

# 测试 Rekor Server
curl -s http://localhost:3000/api/v1/log | jq '.'

# 使用 rekor-cli
rekor-cli loginfo --rekor_server=http://localhost:3000

# 测试写入
echo "test" > /tmp/test.txt
cosign sign-blob \
  --rekor-url=http://localhost:3000 \
  --key cosign.key \
  --yes \
  /tmp/test.txt

8.6 系统服务配置

8.6.1 systemd 服务文件

创建 systemd 服务文件以管理 Rekor 和 Trillian:

# /etc/systemd/system/trillian-log-server.service
[Unit]
Description=Trillian Log Server
After=network.target mysql.service
Requires=mysql.service

[Service]
Type=simple
User=trillian
Group=trillian
ExecStart=/usr/local/bin/trillian-log-server \
  --mysql_uri=trillian:trillian_password@tcp(localhost:3306)/trillian \
  --rpc_endpoint=localhost:8090 \
  --http_endpoint=localhost:8091 \
  --logtostderr
Restart=always
RestartSec=5
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target
# /etc/systemd/system/trillian-log-signer.service
[Unit]
Description=Trillian Log Signer
After=network.target mysql.service trillian-log-server.service
Requires=mysql.service

[Service]
Type=simple
User=trillian
Group=trillian
ExecStart=/usr/local/bin/trillian-log-signer \
  --mysql_uri=trillian:trillian_password@tcp(localhost:3306)/trillian \
  --rpc_endpoint=localhost:8092 \
  --http_endpoint=localhost:8093 \
  --logtostderr \
  --force_master
Restart=always
RestartSec=5
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target
# /etc/systemd/system/rekor-server.service
[Unit]
Description=Rekor Server
After=network.target trillian-log-server.service redis.service
Requires=trillian-log-server.service

[Service]
Type=simple
User=rekor
Group=rekor
ExecStart=/usr/local/bin/rekor-server serve \
  --trillian_log_server.address=localhost \
  --trillian_log_server.port=8090 \
  --rekor_server.address=0.0.0.0 \
  --rekor_server.port=3000 \
  --redis_server.address=localhost \
  --redis_server.port=6379 \
  --log_type=log \
  --log_level=info
Restart=always
RestartSec=5
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target

8.6.2 启用服务

# 创建用户
sudo useradd -r -s /bin/false trillian
sudo useradd -r -s /bin/false rekor

# 创建目录
sudo mkdir -p /var/lib/rekor/attestations
sudo chown rekor:rekor /var/lib/rekor/attestations

# 重载 systemd
sudo systemctl daemon-reload

# 启动服务
sudo systemctl start trillian-log-server
sudo systemctl start trillian-log-signer
sudo systemctl start rekor-server

# 设置开机自启
sudo systemctl enable trillian-log-server
sudo systemctl enable trillian-log-signer
sudo systemctl enable rekor-server

# 检查状态
sudo systemctl status rekor-server

8.7 Nginx 反向代理

8.7.1 Nginx 配置

# /etc/nginx/sites-available/rekor
upstream rekor_backend {
    server 127.0.0.1:3000;
    # 多实例时添加更多后端
    # server 127.0.0.1:3001;
    # server 127.0.0.1:3002;
}

server {
    listen 80;
    server_name rekor.internal.mycompany.com;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name rekor.internal.mycompany.com;

    ssl_certificate /etc/nginx/ssl/rekor.crt;
    ssl_certificate_key /etc/nginx/ssl/rekor.key;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;

    # 速率限制
    limit_req_zone $binary_remote_addr zone=rekor_limit:10m rate=100r/s;

    location / {
        limit_req zone=rekor_limit burst=200 nodelay;
        
        proxy_pass http://rekor_backend;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        
        # 超时设置
        proxy_connect_timeout 10s;
        proxy_read_timeout 30s;
        proxy_send_timeout 30s;
        
        # 缓冲设置
        proxy_buffering on;
        proxy_buffer_size 4k;
        proxy_buffers 8 16k;
    }

    # 健康检查
    location /healthz {
        access_log off;
        proxy_pass http://rekor_backend/api/v1/log;
    }
}

8.7.2 启用配置

sudo ln -s /etc/nginx/sites-available/rekor /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

8.8 存储配置

8.8.1 数据库优化

-- MySQL 优化配置 (my.cnf)
[mysqld]
# InnoDB 设置
innodb_buffer_pool_size = 4G
innodb_log_file_size = 256M
innodb_flush_log_at_trx_commit = 2
innodb_flush_method = O_DIRECT

# 连接设置
max_connections = 200
wait_timeout = 600

# 查询缓存(MySQL 8.0 之前)
# query_cache_type = 1
# query_cache_size = 256M

# 慢查询日志
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 1

8.8.2 存储容量规划

数据项 大小(估算) 说明
叶子节点 ~1KB/条 每个 Rekor 条目
Merkle 节点 ~32B/节点 SHA-256 哈希值
索引数据 ~200B/条 搜索索引
证明数据 ~1KB/证明 包含证明

容量计算示例(100 万条目):

叶子节点:  1,000,000 × 1KB  = ~1 GB
Merkle 节点: 1,000,000 × 32B × 2 = ~64 MB
索引数据:  1,000,000 × 200B = ~200 MB
总计:      ~1.3 GB(不含日志和备份)

8.8.3 备份策略

#!/bin/bash
# backup-rekor.sh - Rekor 数据库备份脚本

BACKUP_DIR="/var/backup/rekor"
DATE=$(date +%Y%m%d_%H%M%S)
MYSQL_USER="trillian"
MYSQL_PASS="trillian_password"
DATABASE="trillian"

mkdir -p "$BACKUP_DIR"

# 数据库备份
mysqldump -u "$MYSQL_USER" -p"$MYSQL_PASS" "$DATABASE" | gzip > "$BACKUP_DIR/trillian_$DATE.sql.gz"

# 清理 30 天前的备份
find "$BACKUP_DIR" -name "*.sql.gz" -mtime +30 -delete

echo "备份完成: $BACKUP_DIR/trillian_$DATE.sql.gz"
# 设置定时备份
# crontab -e
0 2 * * * /opt/rekor/scripts/backup-rekor.sh >> /var/log/rekor-backup.log 2>&1

8.9 高可用配置

8.9.1 高可用架构

┌────────────────────────────────────────────────────────────────────┐
│                    高可用 Rekor 部署                                │
│                                                                    │
│  ┌──────────────────────────────────────────────────────────────┐ │
│  │                  负载均衡器 (Keepalived)                      │ │
│  │                  VIP: 192.168.1.100                          │ │
│  └────────────────────────┬─────────────────────────────────────┘ │
│                           │                                        │
│          ┌────────────────┼────────────────┐                      │
│          │                │                │                      │
│    ┌─────▼─────┐    ┌─────▼─────┐    ┌─────▼─────┐              │
│    │ rekor-1   │    │ rekor-2   │    │ rekor-3   │              │
│    │ 192.168.1.1│    │ 192.168.1.2│    │ 192.168.1.3│              │
│    └─────┬─────┘    └─────┬─────┘    └─────┬─────┘              │
│          │                │                │                      │
│          └────────────────┼────────────────┘                      │
│                           │                                        │
│    ┌──────────────────────────────────────────────────┐          │
│    │              Trillian Cluster                     │          │
│    │  ┌──────────┐  ┌──────────┐  ┌──────────┐      │          │
│    │  │Log Svr 1 │  │Log Svr 2 │  │Log Signer│      │          │
│    │  └──────────┘  └──────────┘  └──────────┘      │          │
│    └────────────────────────┬─────────────────────────┘          │
│                             │                                     │
│    ┌────────────────────────┴─────────────────────────┐          │
│    │              MySQL Cluster                        │          │
│    │  ┌──────────┐  ┌──────────┐  ┌──────────┐      │          │
│    │  │  Master  │  │  Slave 1 │  │  Slave 2 │      │          │
│    │  └──────────┘  └──────────┘  └──────────┘      │          │
│    └──────────────────────────────────────────────────┘          │
└────────────────────────────────────────────────────────────────────┘

8.9.2 MySQL 主从复制

-- 主服务器配置 (my.cnf)
[mysqld]
server-id = 1
log_bin = /var/log/mysql/mysql-bin.log
binlog_do_db = trillian

-- 从服务器配置 (my.cnf)
[mysqld]
server-id = 2
relay_log = /var/log/mysql/mysql-relay-bin.log
log_bin = /var/log/mysql/mysql-bin.log
binlog_do_db = trillian
read_only = 1
-- 在从服务器上设置复制
CHANGE MASTER TO
  MASTER_HOST='192.168.1.10',
  MASTER_USER='replication_user',
  MASTER_PASSWORD='replication_password',
  MASTER_LOG_FILE='mysql-bin.000001',
  MASTER_LOG_POS=0;

START SLAVE;
SHOW SLAVE STATUS\G

8.10 监控配置

8.10.1 Prometheus 配置

# prometheus.yml
scrape_configs:
  - job_name: 'rekor-server'
    static_configs:
      - targets: ['localhost:3000']
    metrics_path: /metrics
    scrape_interval: 15s

  - job_name: 'trillian-log-server'
    static_configs:
      - targets: ['localhost:8091']
    metrics_path: /metrics
    scrape_interval: 15s

  - job_name: 'trillian-log-signer'
    static_configs:
      - targets: ['localhost:8093']
    metrics_path: /metrics
    scrape_interval: 15s

8.10.2 关键监控指标

指标 说明 警告阈值
rekor_http_requests_total HTTP 请求总数 -
rekor_http_request_duration_seconds 请求延迟 P99 > 1s
trillian_sequencer_tree_size 树大小 持续不增长
trillian_sequencer_latency_seconds 排序延迟 > 10s
mysql_global_status_threads_connected MySQL 连接数 > 150
mysql_global_status_slow_queries 慢查询数量 > 0

8.10.3 Grafana Dashboard

{
  "dashboard": {
    "title": "Rekor Server Dashboard",
    "panels": [
      {
        "title": "Request Rate",
        "type": "graph",
        "targets": [
          {
            "expr": "rate(rekor_http_requests_total[5m])",
            "legendFormat": "{{method}} {{path}}"
          }
        ]
      },
      {
        "title": "Request Latency (P99)",
        "type": "graph",
        "targets": [
          {
            "expr": "histogram_quantile(0.99, rate(rekor_http_request_duration_seconds_bucket[5m]))",
            "legendFormat": "P99 Latency"
          }
        ]
      },
      {
        "title": "Tree Size",
        "type": "stat",
        "targets": [
          {
            "expr": "trillian_sequencer_tree_size",
            "legendFormat": "Entries"
          }
        ]
      }
    ]
  }
}

8.11 安全加固

8.11.1 TLS 配置

# 生成自签名证书(测试环境)
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
  -keyout /etc/ssl/private/rekor.key \
  -out /etc/ssl/certs/rekor.crt \
  -subj "/CN=rekor.internal.mycompany.com"

# 生产环境建议使用企业 CA 签发的证书

8.11.2 认证配置

# 如果需要 API 认证,配置 Nginx basic auth
sudo apt install -y apache2-utils
sudo htpasswd -c /etc/nginx/.htpasswd rekor_user

# 在 Nginx 配置中添加
# auth_basic "Rekor API";
# auth_basic_user_file /etc/nginx/.htpasswd;

8.11.3 防火墙规则

# UFW 配置
sudo ufw allow 22/tcp    # SSH
sudo ufw allow 443/tcp   # HTTPS
sudo ufw allow 80/tcp    # HTTP (重定向到 HTTPS)
sudo ufw deny 3000/tcp   # 阻止直接访问 Rekor
sudo ufw deny 8090/tcp   # 阻止直接访问 Trillian RPC
sudo ufw deny 3306/tcp   # 阻止直接访问 MySQL
sudo ufw enable

8.12 注意事项

日志同步:私有实例与公共实例是独立的,签名记录不会互相同步。如果需要跨实例验证,需要使用一致性证明。

数据库性能:Trillian 的 Sequencer 对数据库性能敏感。建议使用 SSD 存储并优化 MySQL 配置。

证书管理:确保 TLS 证书的定期更新,建议使用 Let’s Encrypt 或企业 CA。

容量规划:随着日志增长,数据库大小会持续增加。定期监控存储使用情况。


8.13 本章小结

组件 最小配置 推荐配置
rekor-server 1 实例, 2C4G 3 实例, 4C8G
Trillian Log Server 1 实例, 2C4G 2 实例, 4C8G
Trillian Log Signer 1 实例, 1C2G 1 实例, 2C4G
MySQL 1 实例, 2C4G, 50GB SSD 主从, 4C8G, 200GB SSD
Redis 可选 集群模式, 4G 内存

扩展阅读


下一章:09 - Docker 部署 — 使用 Docker 和 Kubernetes 部署 Rekor。