cleanup: remove 2,369 lines of dead code
Removed backup files and unused legacy scanner function. All code verified as unreferenced.
This commit is contained in:
342
aggregator-agent/internal/migration/docker_executor.go
Normal file
342
aggregator-agent/internal/migration/docker_executor.go
Normal file
@@ -0,0 +1,342 @@
|
||||
package migration
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// DockerSecretsExecutor handles the execution of Docker secrets migration
|
||||
type DockerSecretsExecutor struct {
|
||||
detection *DockerDetection
|
||||
config *FileDetectionConfig
|
||||
encryption string
|
||||
}
|
||||
|
||||
// NewDockerSecretsExecutor creates a new Docker secrets executor
|
||||
func NewDockerSecretsExecutor(detection *DockerDetection, config *FileDetectionConfig) *DockerSecretsExecutor {
|
||||
return &DockerSecretsExecutor{
|
||||
detection: detection,
|
||||
config: config,
|
||||
}
|
||||
}
|
||||
|
||||
// ExecuteDockerSecretsMigration performs the Docker secrets migration
|
||||
func (e *DockerSecretsExecutor) ExecuteDockerSecretsMigration() error {
|
||||
if !e.detection.DockerAvailable {
|
||||
return fmt.Errorf("docker secrets not available")
|
||||
}
|
||||
|
||||
if !e.detection.MigrateToSecrets {
|
||||
fmt.Printf("[DOCKER] No secrets to migrate\n")
|
||||
return nil
|
||||
}
|
||||
|
||||
fmt.Printf("[DOCKER] Starting Docker secrets migration...\n")
|
||||
|
||||
// Generate encryption key for config files
|
||||
encKey, err := GenerateEncryptionKey()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to generate encryption key: %w", err)
|
||||
}
|
||||
e.encryption = encKey
|
||||
|
||||
// Create backup before migration
|
||||
if err := e.createSecretsBackup(); err != nil {
|
||||
return fmt.Errorf("failed to create secrets backup: %w", err)
|
||||
}
|
||||
|
||||
// Migrate each secret file
|
||||
for _, secretFile := range e.detection.SecretFiles {
|
||||
if err := e.migrateSecretFile(secretFile); err != nil {
|
||||
fmt.Printf("[DOCKER] Failed to migrate secret file %s: %v\n", secretFile.Path, err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// Create Docker secrets configuration
|
||||
if err := e.createDockerConfig(); err != nil {
|
||||
return fmt.Errorf("failed to create Docker config: %w", err)
|
||||
}
|
||||
|
||||
// Remove original secret files
|
||||
if err := e.removeOriginalSecrets(); err != nil {
|
||||
return fmt.Errorf("failed to remove original secrets: %w", err)
|
||||
}
|
||||
|
||||
fmt.Printf("[DOCKER] Docker secrets migration completed successfully\n")
|
||||
fmt.Printf("[DOCKER] Encryption key: %s\n", encKey)
|
||||
fmt.Printf("[DOCKER] Save this key securely for decryption\n")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// createSecretsBackup creates a backup of secret files before migration
|
||||
func (e *DockerSecretsExecutor) createSecretsBackup() error {
|
||||
timestamp := time.Now().Format("2006-01-02-150405")
|
||||
backupDir := fmt.Sprintf("/etc/redflag.backup.secrets.%s", timestamp)
|
||||
|
||||
if err := os.MkdirAll(backupDir, 0755); err != nil {
|
||||
return fmt.Errorf("failed to create backup directory: %w", err)
|
||||
}
|
||||
|
||||
for _, secretFile := range e.detection.SecretFiles {
|
||||
backupPath := filepath.Join(backupDir, filepath.Base(secretFile.Path))
|
||||
if err := copySecretFile(secretFile.Path, backupPath); err != nil {
|
||||
fmt.Printf("[DOCKER] Failed to backup secret file %s: %v\n", secretFile.Path, err)
|
||||
} else {
|
||||
fmt.Printf("[DOCKER] Backed up secret file: %s → %s\n", secretFile.Path, backupPath)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// migrateSecretFile migrates a single secret file to Docker secrets
|
||||
func (e *DockerSecretsExecutor) migrateSecretFile(secretFile AgentFile) error {
|
||||
secretName := filepath.Base(secretFile.Path)
|
||||
secretPath := filepath.Join(e.detection.SecretsMountPath, secretName)
|
||||
|
||||
// Handle config.json specially (encrypt it)
|
||||
if secretName == "config.json" {
|
||||
return e.migrateConfigFile(secretFile)
|
||||
}
|
||||
|
||||
// Copy secret file to Docker secrets directory
|
||||
if err := copySecretFile(secretFile.Path, secretPath); err != nil {
|
||||
return fmt.Errorf("failed to copy secret to Docker mount: %w", err)
|
||||
}
|
||||
|
||||
// Set secure permissions
|
||||
if err := os.Chmod(secretPath, 0400); err != nil {
|
||||
return fmt.Errorf("failed to set secret permissions: %w", err)
|
||||
}
|
||||
|
||||
fmt.Printf("[DOCKER] Migrated secret: %s → %s\n", secretFile.Path, secretPath)
|
||||
return nil
|
||||
}
|
||||
|
||||
// migrateConfigFile handles special migration of config.json with encryption
|
||||
func (e *DockerSecretsExecutor) migrateConfigFile(secretFile AgentFile) error {
|
||||
// Read original config
|
||||
configData, err := os.ReadFile(secretFile.Path)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read config file: %w", err)
|
||||
}
|
||||
|
||||
// Parse config to separate sensitive from non-sensitive data
|
||||
var config map[string]interface{}
|
||||
if err := json.Unmarshal(configData, &config); err != nil {
|
||||
return fmt.Errorf("failed to parse config: %w", err)
|
||||
}
|
||||
|
||||
// Split config into public and sensitive parts
|
||||
publicConfig, sensitiveConfig := e.splitConfig(config)
|
||||
|
||||
// Write public config back to original location
|
||||
publicData, err := json.MarshalIndent(publicConfig, "", " ")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to marshal public config: %w", err)
|
||||
}
|
||||
|
||||
if err := os.WriteFile(secretFile.Path, publicData, 0644); err != nil {
|
||||
return fmt.Errorf("failed to write public config: %w", err)
|
||||
}
|
||||
|
||||
// Encrypt sensitive config
|
||||
sensitiveData, err := json.MarshalIndent(sensitiveConfig, "", " ")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to marshal sensitive config: %w", err)
|
||||
}
|
||||
|
||||
tempSensitivePath := secretFile.Path + ".sensitive"
|
||||
if err := os.WriteFile(tempSensitivePath, sensitiveData, 0600); err != nil {
|
||||
return fmt.Errorf("failed to write sensitive config: %w", err)
|
||||
}
|
||||
defer os.Remove(tempSensitivePath)
|
||||
|
||||
// Encrypt sensitive config
|
||||
encryptedPath := filepath.Join(e.detection.SecretsMountPath, "config.json.enc")
|
||||
if err := EncryptFile(tempSensitivePath, encryptedPath, e.encryption); err != nil {
|
||||
return fmt.Errorf("failed to encrypt config: %w", err)
|
||||
}
|
||||
|
||||
fmt.Printf("[DOCKER] Migrated config with encryption: %s → %s (public) + %s (encrypted)\n",
|
||||
secretFile.Path, secretFile.Path, encryptedPath)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// splitConfig splits configuration into public and sensitive parts
|
||||
func (e *DockerSecretsExecutor) splitConfig(config map[string]interface{}) (map[string]interface{}, map[string]interface{}) {
|
||||
public := make(map[string]interface{})
|
||||
sensitive := make(map[string]interface{})
|
||||
|
||||
sensitiveFields := []string{
|
||||
"password", "token", "key", "secret", "credential",
|
||||
"proxy", "tls", "certificate", "private",
|
||||
}
|
||||
|
||||
for key, value := range config {
|
||||
if e.isSensitiveField(key, value, sensitiveFields) {
|
||||
sensitive[key] = value
|
||||
} else {
|
||||
public[key] = value
|
||||
}
|
||||
}
|
||||
|
||||
return public, sensitive
|
||||
}
|
||||
|
||||
// isSensitiveField checks if a field contains sensitive data
|
||||
func (e *DockerSecretsExecutor) isSensitiveField(key string, value interface{}, sensitiveFields []string) bool {
|
||||
// Check key name
|
||||
for _, field := range sensitiveFields {
|
||||
if strings.Contains(strings.ToLower(key), strings.ToLower(field)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// Check nested values
|
||||
if nested, ok := value.(map[string]interface{}); ok {
|
||||
for nKey, nValue := range nested {
|
||||
if e.isSensitiveField(nKey, nValue, sensitiveFields) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// createDockerConfig creates the Docker secrets configuration file
|
||||
func (e *DockerSecretsExecutor) createDockerConfig() error {
|
||||
dockerConfig := DockerConfig{
|
||||
Enabled: true,
|
||||
SecretsPath: e.detection.SecretsMountPath,
|
||||
EncryptionKey: e.encryption,
|
||||
Secrets: make(map[string]string),
|
||||
}
|
||||
|
||||
// Map secret files to their Docker secret names
|
||||
for _, secretFile := range e.detection.SecretFiles {
|
||||
secretName := filepath.Base(secretFile.Path)
|
||||
if secretName == "config.json" {
|
||||
dockerConfig.Secrets["config"] = "config.json.enc"
|
||||
} else {
|
||||
dockerConfig.Secrets[secretName] = secretName
|
||||
}
|
||||
}
|
||||
|
||||
// Write Docker config
|
||||
configPath := filepath.Join(e.config.NewConfigPath, "docker.json")
|
||||
configData, err := json.MarshalIndent(dockerConfig, "", " ")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to marshal Docker config: %w", err)
|
||||
}
|
||||
|
||||
if err := os.WriteFile(configPath, configData, 0600); err != nil {
|
||||
return fmt.Errorf("failed to write Docker config: %w", err)
|
||||
}
|
||||
|
||||
fmt.Printf("[DOCKER] Created Docker config: %s\n", configPath)
|
||||
return nil
|
||||
}
|
||||
|
||||
// removeOriginalSecrets removes the original secret files after migration
|
||||
func (e *DockerSecretsExecutor) removeOriginalSecrets() error {
|
||||
for _, secretFile := range e.detection.SecretFiles {
|
||||
// Don't remove config.json as it's been split into public part
|
||||
if filepath.Base(secretFile.Path) == "config.json" {
|
||||
continue
|
||||
}
|
||||
|
||||
if err := os.Remove(secretFile.Path); err != nil {
|
||||
fmt.Printf("[DOCKER] Failed to remove original secret %s: %v\n", secretFile.Path, err)
|
||||
} else {
|
||||
fmt.Printf("[DOCKER] Removed original secret: %s\n", secretFile.Path)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// copySecretFile copies a file from src to dst (renamed to avoid conflicts)
|
||||
func copySecretFile(src, dst string) error {
|
||||
// Read source file
|
||||
data, err := os.ReadFile(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Ensure destination directory exists
|
||||
if err := os.MkdirAll(filepath.Dir(dst), 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Write destination file
|
||||
return os.WriteFile(dst, data, 0644)
|
||||
}
|
||||
|
||||
// ValidateDockerSecretsMigration validates that the Docker secrets migration was successful
|
||||
func (e *DockerSecretsExecutor) ValidateDockerSecretsMigration() error {
|
||||
// Check that Docker secrets directory exists
|
||||
if _, err := os.Stat(e.detection.SecretsMountPath); err != nil {
|
||||
return fmt.Errorf("Docker secrets directory not accessible: %w", err)
|
||||
}
|
||||
|
||||
// Check that all required secrets exist
|
||||
for _, secretName := range e.detection.RequiredSecrets {
|
||||
secretPath := filepath.Join(e.detection.SecretsMountPath, secretName)
|
||||
if _, err := os.Stat(secretPath); err != nil {
|
||||
return fmt.Errorf("required secret not found: %s", secretName)
|
||||
}
|
||||
}
|
||||
|
||||
// Check that Docker config exists
|
||||
dockerConfigPath := filepath.Join(e.config.NewConfigPath, "docker.json")
|
||||
if _, err := os.Stat(dockerConfigPath); err != nil {
|
||||
return fmt.Errorf("Docker config not found: %w", err)
|
||||
}
|
||||
|
||||
fmt.Printf("[DOCKER] Docker secrets migration validation successful\n")
|
||||
return nil
|
||||
}
|
||||
|
||||
// RollbackDockerSecretsMigration rolls back the Docker secrets migration
|
||||
func (e *DockerSecretsExecutor) RollbackDockerSecretsMigration(backupDir string) error {
|
||||
fmt.Printf("[DOCKER] Rolling back Docker secrets migration from backup: %s\n", backupDir)
|
||||
|
||||
// Restore original secret files from backup
|
||||
entries, err := os.ReadDir(backupDir)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read backup directory: %w", err)
|
||||
}
|
||||
|
||||
for _, entry := range entries {
|
||||
if entry.IsDir() {
|
||||
continue
|
||||
}
|
||||
|
||||
backupPath := filepath.Join(backupDir, entry.Name())
|
||||
originalPath := filepath.Join(e.config.NewConfigPath, entry.Name())
|
||||
|
||||
if err := copySecretFile(backupPath, originalPath); err != nil {
|
||||
fmt.Printf("[DOCKER] Failed to restore %s: %v\n", entry.Name(), err)
|
||||
} else {
|
||||
fmt.Printf("[DOCKER] Restored: %s\n", entry.Name())
|
||||
}
|
||||
}
|
||||
|
||||
// Remove Docker config
|
||||
dockerConfigPath := filepath.Join(e.config.NewConfigPath, "docker.json")
|
||||
if err := os.Remove(dockerConfigPath); err != nil {
|
||||
fmt.Printf("[DOCKER] Failed to remove Docker config: %v\n", err)
|
||||
}
|
||||
|
||||
fmt.Printf("[DOCKER] Docker secrets migration rollback completed\n")
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user