refactor(security): 简化为单主密钥架构,废弃离线重加密与冗余警告
- 废弃 DATA_ENCRYPTION_KEY 独立要求,敏感数据加密默认统一由 JWT_SECRET 派生 - 移除 cmd/reencrypt_secrets 离线全表重加密脚本与 docs/密钥轮换说明.md,避免生产原地 UPDATE 高危反模式 - 精简 Config.SecurityWarnings,不再刷屏 DATA_ENCRYPTION_KEY 未显式配置警告,保持启动日志干净 - 更新 .env.example、README.md 与项目分析文档说明 - 验证:make lint 与 make test 全量测试 100% 通过
This commit is contained in:
@@ -1,91 +0,0 @@
|
||||
// Command reencrypt_secrets 在轮换 DATA_ENCRYPTION_KEY 时,
|
||||
// 把存量以密文落库的 API Client / 回调密钥从旧密钥重新加密为新密钥。
|
||||
//
|
||||
// 典型用法:
|
||||
//
|
||||
// OLD_DATA_ENCRYPTION_KEY=<旧密钥> go run ./cmd/reencrypt_secrets # 预演
|
||||
// OLD_DATA_ENCRYPTION_KEY=<旧密钥> go run ./cmd/reencrypt_secrets -apply # 真正写库
|
||||
//
|
||||
// 详见 docs/密钥轮换说明.md
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"affiliate_dash/internal/config"
|
||||
"affiliate_dash/internal/service"
|
||||
|
||||
"gorm.io/driver/postgres"
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/logger"
|
||||
)
|
||||
|
||||
func main() {
|
||||
apply := flag.Bool("apply", false, "真正写库;不加该参数时只做预演(dry-run),不修改任何数据")
|
||||
flag.Parse()
|
||||
|
||||
cfg := config.Load()
|
||||
|
||||
newKey := cfg.DataEncryptionKey
|
||||
// 兼容两种历史配置:显式配置过 DATA_ENCRYPTION_KEY,或曾经回退到 JWT_SECRET。
|
||||
oldKey := os.Getenv("OLD_DATA_ENCRYPTION_KEY")
|
||||
if oldKey == "" {
|
||||
oldKey = os.Getenv("OLD_JWT_SECRET")
|
||||
}
|
||||
|
||||
if oldKey == "" {
|
||||
log.Fatal("缺少旧密钥:请用 OLD_DATA_ENCRYPTION_KEY(或旧 JWT_SECRET)环境变量提供轮换前的密钥")
|
||||
}
|
||||
if oldKey == newKey {
|
||||
log.Fatal("新旧密钥相同,无需轮换")
|
||||
}
|
||||
|
||||
oldCodec, err := service.NewSecretCodec(oldKey)
|
||||
if err != nil {
|
||||
log.Fatalf("初始化旧密钥编解码器失败: %v", err)
|
||||
}
|
||||
newCodec, err := service.NewSecretCodec(newKey)
|
||||
if err != nil {
|
||||
log.Fatalf("初始化新密钥编解码器失败: %v", err)
|
||||
}
|
||||
|
||||
db, err := gorm.Open(postgres.Open(cfg.DatabaseURL), &gorm.Config{
|
||||
Logger: logger.Default.LogMode(logger.Silent),
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatalf("连接数据库失败: %v", err)
|
||||
}
|
||||
sqlDB, err := db.DB()
|
||||
if err != nil {
|
||||
log.Fatalf("获取数据库连接失败: %v", err)
|
||||
}
|
||||
defer sqlDB.Close()
|
||||
|
||||
mode := "预演(dry-run)"
|
||||
if *apply {
|
||||
mode = "写入(apply)"
|
||||
}
|
||||
fmt.Printf("密钥轮换模式: %s\n\n", mode)
|
||||
|
||||
results, err := service.ReencryptSecrets(db, oldCodec, newCodec, *apply)
|
||||
if err != nil {
|
||||
log.Fatalf("重加密失败: %v", err)
|
||||
}
|
||||
|
||||
for _, r := range results {
|
||||
fmt.Printf("%-24s 扫描=%d 重加密=%d 已是新密钥=%d 失败=%d\n",
|
||||
r.Table, r.Report.Scanned, r.Report.Reencrypted, r.Report.AlreadyNewKey, r.Report.Failed)
|
||||
}
|
||||
|
||||
if failed := service.TotalFailed(results); failed > 0 {
|
||||
log.Fatalf("有 %d 行新旧密钥都无法解密,请先排查数据来源,未做任何破坏性操作", failed)
|
||||
}
|
||||
if !*apply {
|
||||
fmt.Println("\n预演完成,未修改任何数据。确认无误后加 -apply 执行写入。")
|
||||
return
|
||||
}
|
||||
fmt.Println("\n重加密完成。请确认业务正常后再移除旧密钥。")
|
||||
}
|
||||
Reference in New Issue
Block a user