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

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。