package config import ( "fmt" "log" "os" "path/filepath" "sync" ) var ( instance *Config once sync.Once ) type Config struct { ServerPort string DatabasePath string JWTSecret string EncryptionKey string // 独立加密密钥,必须与JWT_SECRET分离 DataDir string KubeDir string LogLevel string // 新增:日志级别 debug/info/warn/error HostKeyDir string // 新增:SSH主机密钥存储目录 } func GetConfig() *Config { once.Do(func() { dataDir := getEnv("DATA_DIR", "./data") jwtSecret := os.Getenv("JWT_SECRET") encKey := os.Getenv("ENCRYPTION_KEY") // 生产环境强制校验:JWT_SECRET和ENCRYPTION_KEY必须设置 if jwtSecret == "" { log.Fatal("[SECURITY] JWT_SECRET environment variable is required. Please set a strong random secret.") } if encKey == "" { log.Fatal("[SECURITY] ENCRYPTION_KEY environment variable is required. Please set a strong 32-byte random key (base64 or hex encoded).") } // ENCRYPTION_KEY 长度校验:至少32字节(256位) if len(encKey) < 32 { log.Fatal(fmt.Sprintf("[SECURITY] ENCRYPTION_KEY must be at least 32 bytes, got %d bytes", len(encKey))) } instance = &Config{ ServerPort: getEnv("SERVER_PORT", "8080"), DatabasePath: filepath.Join(dataDir, "lokideploy.json"), JWTSecret: jwtSecret, EncryptionKey: encKey, DataDir: dataDir, KubeDir: filepath.Join(dataDir, "kubeconfigs"), LogLevel: getEnv("LOG_LEVEL", "info"), HostKeyDir: filepath.Join(dataDir, "known_hosts"), } _ = os.MkdirAll(instance.KubeDir, 0700) _ = os.MkdirAll(instance.HostKeyDir, 0700) }) return instance } func getEnv(key, defaultVal string) string { if val := os.Getenv(key); val != "" { return val } return defaultVal }