package security import ( "context" "crypto/tls" "fmt" "net/http" "os" "sync" "time" "golang.org/x/time/rate" "github.com/fraktal/mev-beta/internal/logger" ) // SecurityManager provides centralized security management for the MEV bot type SecurityManager struct { keyManager *KeyManager inputValidator *InputValidator rateLimiter *RateLimiter monitor *SecurityMonitor config *SecurityConfig logger *logger.Logger // Circuit breakers for different components rpcCircuitBreaker *CircuitBreaker arbitrageCircuitBreaker *CircuitBreaker // TLS configuration tlsConfig *tls.Config // Rate limiters for different operations transactionLimiter *rate.Limiter rpcLimiter *rate.Limiter // Security state emergencyMode bool securityAlerts []SecurityAlert alertsMutex sync.RWMutex // Metrics managerMetrics *ManagerMetrics } // SecurityConfig contains all security-related configuration type SecurityConfig struct { // Key management KeyStoreDir string `yaml:"keystore_dir"` EncryptionEnabled bool `yaml:"encryption_enabled"` // Rate limiting TransactionRPS int `yaml:"transaction_rps"` RPCRPS int `yaml:"rpc_rps"` MaxBurstSize int `yaml:"max_burst_size"` // Circuit breaker settings FailureThreshold int `yaml:"failure_threshold"` RecoveryTimeout time.Duration `yaml:"recovery_timeout"` // TLS settings TLSMinVersion uint16 `yaml:"tls_min_version"` TLSCipherSuites []uint16 `yaml:"tls_cipher_suites"` // Emergency settings EmergencyStopFile string `yaml:"emergency_stop_file"` MaxGasPrice string `yaml:"max_gas_price"` // Monitoring AlertWebhookURL string `yaml:"alert_webhook_url"` LogLevel string `yaml:"log_level"` } // Additional security metrics for SecurityManager type ManagerMetrics struct { AuthenticationAttempts int64 `json:"authentication_attempts"` FailedAuthentications int64 `json:"failed_authentications"` CircuitBreakerTrips int64 `json:"circuit_breaker_trips"` EmergencyStops int64 `json:"emergency_stops"` TLSHandshakeFailures int64 `json:"tls_handshake_failures"` } // CircuitBreaker implements the circuit breaker pattern for fault tolerance type CircuitBreaker struct { name string failureCount int lastFailureTime time.Time state CircuitBreakerState config CircuitBreakerConfig mutex sync.RWMutex } type CircuitBreakerState int const ( CircuitBreakerClosed CircuitBreakerState = iota CircuitBreakerOpen CircuitBreakerHalfOpen ) type CircuitBreakerConfig struct { FailureThreshold int RecoveryTimeout time.Duration MaxRetries int } // NewSecurityManager creates a new security manager with comprehensive protection func NewSecurityManager(config *SecurityConfig) (*SecurityManager, error) { if config == nil { return nil, fmt.Errorf("security config cannot be nil") } // Initialize key manager - get encryption key from environment or fail encryptionKey := os.Getenv("MEV_BOT_ENCRYPTION_KEY") if encryptionKey == "" { return nil, fmt.Errorf("MEV_BOT_ENCRYPTION_KEY environment variable is required") } keyManagerConfig := &KeyManagerConfig{ KeyDir: config.KeyStoreDir, KeystorePath: config.KeyStoreDir, EncryptionKey: encryptionKey, BackupEnabled: true, MaxFailedAttempts: 3, LockoutDuration: 5 * time.Minute, } keyManager, err := NewKeyManager(keyManagerConfig, logger.New("info", "json", "logs/keymanager.log")) if err != nil { return nil, fmt.Errorf("failed to initialize key manager: %w", err) } // Initialize input validator inputValidator := NewInputValidator(1) // Default chain ID // Initialize rate limiter rateLimiterConfig := &RateLimiterConfig{ IPRequestsPerSecond: 100, IPBurstSize: config.MaxBurstSize, IPBlockDuration: 5 * time.Minute, UserRequestsPerSecond: config.TransactionRPS, UserBurstSize: config.MaxBurstSize, UserBlockDuration: 5 * time.Minute, CleanupInterval: 5 * time.Minute, } rateLimiter := NewRateLimiter(rateLimiterConfig) // Initialize security monitor monitorConfig := &MonitorConfig{ EnableAlerts: true, AlertBuffer: 1000, AlertRetention: 24 * time.Hour, MaxEvents: 10000, EventRetention: 7 * 24 * time.Hour, MetricsInterval: time.Minute, CleanupInterval: time.Hour, } monitor := NewSecurityMonitor(monitorConfig) // Create TLS configuration with security best practices tlsConfig := &tls.Config{ MinVersion: tls.VersionTLS12, // Enforce TLS 1.2 minimum CipherSuites: config.TLSCipherSuites, InsecureSkipVerify: false, PreferServerCipherSuites: true, } // Initialize circuit breakers rpcCircuitBreaker := &CircuitBreaker{ name: "rpc", config: CircuitBreakerConfig{ FailureThreshold: config.FailureThreshold, RecoveryTimeout: config.RecoveryTimeout, MaxRetries: 3, }, state: CircuitBreakerClosed, } arbitrageCircuitBreaker := &CircuitBreaker{ name: "arbitrage", config: CircuitBreakerConfig{ FailureThreshold: config.FailureThreshold, RecoveryTimeout: config.RecoveryTimeout, MaxRetries: 3, }, state: CircuitBreakerClosed, } // Initialize rate limiters transactionLimiter := rate.NewLimiter(rate.Limit(config.TransactionRPS), config.MaxBurstSize) rpcLimiter := rate.NewLimiter(rate.Limit(config.RPCRPS), config.MaxBurstSize) // Create logger instance securityLogger := logger.New("info", "json", "logs/security.log") sm := &SecurityManager{ keyManager: keyManager, inputValidator: inputValidator, rateLimiter: rateLimiter, monitor: monitor, config: config, logger: securityLogger, rpcCircuitBreaker: rpcCircuitBreaker, arbitrageCircuitBreaker: arbitrageCircuitBreaker, tlsConfig: tlsConfig, transactionLimiter: transactionLimiter, rpcLimiter: rpcLimiter, emergencyMode: false, securityAlerts: make([]SecurityAlert, 0), managerMetrics: &ManagerMetrics{}, } // Start security monitoring go sm.startSecurityMonitoring() sm.logger.Info("Security manager initialized successfully") return sm, nil } // ValidateTransaction performs comprehensive transaction validation func (sm *SecurityManager) ValidateTransaction(ctx context.Context, txParams *TransactionParams) error { // Check rate limiting if !sm.transactionLimiter.Allow() { if sm.monitor != nil { sm.monitor.RecordEvent(EventTypeError, "security_manager", "Transaction rate limit exceeded", SeverityMedium, map[string]interface{}{ "limit_type": "transaction", }) } return fmt.Errorf("transaction rate limit exceeded") } // Check emergency mode if sm.emergencyMode { return fmt.Errorf("system in emergency mode - transactions disabled") } // Validate input parameters (simplified validation) if txParams.To == nil { return fmt.Errorf("transaction validation failed: missing recipient") } if txParams.Value == nil { return fmt.Errorf("transaction validation failed: missing value") } // Check circuit breaker state if sm.arbitrageCircuitBreaker.state == CircuitBreakerOpen { return fmt.Errorf("arbitrage circuit breaker is open") } return nil } // SecureRPCCall performs RPC calls with security controls func (sm *SecurityManager) SecureRPCCall(ctx context.Context, method string, params interface{}) (interface{}, error) { // Check rate limiting if !sm.rpcLimiter.Allow() { if sm.monitor != nil { sm.monitor.RecordEvent(EventTypeError, "security_manager", "RPC rate limit exceeded", SeverityMedium, map[string]interface{}{ "limit_type": "rpc", "method": method, }) } return nil, fmt.Errorf("RPC rate limit exceeded") } // Check circuit breaker if sm.rpcCircuitBreaker.state == CircuitBreakerOpen { return nil, fmt.Errorf("RPC circuit breaker is open") } // Create secure HTTP client (placeholder for actual RPC implementation) _ = &http.Client{ Timeout: 30 * time.Second, Transport: &http.Transport{ TLSClientConfig: sm.tlsConfig, }, } // Implement actual RPC call logic here // This is a placeholder - actual implementation would depend on the RPC client // For now, just return a simple response return map[string]interface{}{"status": "success"}, nil } // TriggerEmergencyStop activates emergency mode func (sm *SecurityManager) TriggerEmergencyStop(reason string) error { sm.emergencyMode = true sm.managerMetrics.EmergencyStops++ alert := SecurityAlert{ ID: fmt.Sprintf("emergency-%d", time.Now().Unix()), Timestamp: time.Now(), Level: AlertLevelCritical, Type: AlertTypeConfiguration, Title: "Emergency Stop Activated", Description: fmt.Sprintf("Emergency stop triggered: %s", reason), Source: "security_manager", Data: map[string]interface{}{ "reason": reason, }, Actions: []string{"investigate_cause", "review_logs", "manual_restart_required"}, } sm.addSecurityAlert(alert) sm.logger.Error("Emergency stop triggered: " + reason) return nil } // RecordFailure records a failure for circuit breaker logic func (sm *SecurityManager) RecordFailure(component string, err error) { var cb *CircuitBreaker switch component { case "rpc": cb = sm.rpcCircuitBreaker case "arbitrage": cb = sm.arbitrageCircuitBreaker default: return } cb.mutex.Lock() defer cb.mutex.Unlock() cb.failureCount++ cb.lastFailureTime = time.Now() if cb.failureCount >= cb.config.FailureThreshold && cb.state == CircuitBreakerClosed { cb.state = CircuitBreakerOpen sm.managerMetrics.CircuitBreakerTrips++ alert := SecurityAlert{ ID: fmt.Sprintf("circuit-breaker-%s-%d", component, time.Now().Unix()), Timestamp: time.Now(), Level: AlertLevelError, Type: AlertTypePerformance, Title: "Circuit Breaker Opened", Description: fmt.Sprintf("Circuit breaker opened for component: %s", component), Source: "security_manager", Data: map[string]interface{}{ "component": component, "failure_count": cb.failureCount, "error": err.Error(), }, Actions: []string{"investigate_failures", "check_component_health", "manual_intervention_required"}, } sm.addSecurityAlert(alert) sm.logger.Warn(fmt.Sprintf("Circuit breaker opened for component: %s, failure count: %d", component, cb.failureCount)) } } // RecordSuccess records a success for circuit breaker logic func (sm *SecurityManager) RecordSuccess(component string) { var cb *CircuitBreaker switch component { case "rpc": cb = sm.rpcCircuitBreaker case "arbitrage": cb = sm.arbitrageCircuitBreaker default: return } cb.mutex.Lock() defer cb.mutex.Unlock() if cb.state == CircuitBreakerHalfOpen { cb.state = CircuitBreakerClosed cb.failureCount = 0 sm.logger.Info(fmt.Sprintf("Circuit breaker closed for component: %s", component)) } } // addSecurityAlert adds a security alert to the system func (sm *SecurityManager) addSecurityAlert(alert SecurityAlert) { sm.alertsMutex.Lock() defer sm.alertsMutex.Unlock() sm.securityAlerts = append(sm.securityAlerts, alert) // Send alert to monitor if available if sm.monitor != nil { sm.monitor.TriggerAlert(alert.Level, alert.Type, alert.Title, alert.Description, alert.Source, alert.Data, alert.Actions) } // Keep only last 1000 alerts if len(sm.securityAlerts) > 1000 { sm.securityAlerts = sm.securityAlerts[len(sm.securityAlerts)-1000:] } } // startSecurityMonitoring starts background security monitoring func (sm *SecurityManager) startSecurityMonitoring() { ticker := time.NewTicker(1 * time.Minute) defer ticker.Stop() for { select { case <-ticker.C: sm.performSecurityChecks() } } } // performSecurityChecks performs periodic security checks func (sm *SecurityManager) performSecurityChecks() { // Check circuit breakers for recovery sm.checkCircuitBreakerRecovery(sm.rpcCircuitBreaker) sm.checkCircuitBreakerRecovery(sm.arbitrageCircuitBreaker) // Check for emergency stop file if sm.config.EmergencyStopFile != "" { if _, err := os.Stat(sm.config.EmergencyStopFile); err == nil { sm.TriggerEmergencyStop("emergency stop file detected") } } } // checkCircuitBreakerRecovery checks if circuit breakers can transition to half-open func (sm *SecurityManager) checkCircuitBreakerRecovery(cb *CircuitBreaker) { cb.mutex.Lock() defer cb.mutex.Unlock() if cb.state == CircuitBreakerOpen && time.Since(cb.lastFailureTime) > cb.config.RecoveryTimeout { cb.state = CircuitBreakerHalfOpen sm.logger.Info(fmt.Sprintf("Circuit breaker transitioned to half-open for component: %s", cb.name)) } } // GetManagerMetrics returns current manager metrics func (sm *SecurityManager) GetManagerMetrics() *ManagerMetrics { return sm.managerMetrics } // GetSecurityMetrics returns current security metrics from monitor func (sm *SecurityManager) GetSecurityMetrics() *SecurityMetrics { if sm.monitor != nil { return sm.monitor.GetMetrics() } return &SecurityMetrics{} } // GetSecurityAlerts returns recent security alerts func (sm *SecurityManager) GetSecurityAlerts(limit int) []SecurityAlert { sm.alertsMutex.RLock() defer sm.alertsMutex.RUnlock() if limit <= 0 || limit > len(sm.securityAlerts) { limit = len(sm.securityAlerts) } start := len(sm.securityAlerts) - limit if start < 0 { start = 0 } alerts := make([]SecurityAlert, limit) copy(alerts, sm.securityAlerts[start:]) return alerts } // Shutdown gracefully shuts down the security manager func (sm *SecurityManager) Shutdown(ctx context.Context) error { sm.logger.Info("Shutting down security manager") // Shutdown components if sm.keyManager != nil { // Key manager shutdown - simplified (no shutdown method needed) sm.logger.Info("Key manager stopped") } if sm.rateLimiter != nil { // Rate limiter shutdown - simplified sm.logger.Info("Rate limiter stopped") } if sm.monitor != nil { // Monitor shutdown - simplified sm.logger.Info("Security monitor stopped") } return nil }