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

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-server1 实例3+ 实例
Trillian Log Server1 实例2+ 实例
Trillian Log Signer1 实例1 实例(单主)
MySQL/PostgreSQL1 实例主从复制
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_totalHTTP 请求总数-
rekor_http_request_duration_seconds请求延迟P99 > 1s
trillian_sequencer_tree_size树大小持续不增长
trillian_sequencer_latency_seconds排序延迟> 10s
mysql_global_status_threads_connectedMySQL 连接数> 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-server1 实例, 2C4G3 实例, 4C8G
Trillian Log Server1 实例, 2C4G2 实例, 4C8G
Trillian Log Signer1 实例, 1C2G1 实例, 2C4G
MySQL1 实例, 2C4G, 50GB SSD主从, 4C8G, 200GB SSD
Redis可选集群模式, 4G 内存

扩展阅读


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