package security import ( "context" "encoding/json" "fmt" "sync" "time" ) // SecurityMonitor provides comprehensive security monitoring and alerting type SecurityMonitor struct { // Alert channels alertChan chan SecurityAlert stopChan chan struct{} // Event tracking events []SecurityEvent eventsMutex sync.RWMutex maxEvents int // Metrics metrics *SecurityMetrics metricsMutex sync.RWMutex // Configuration config *MonitorConfig // Alert handlers alertHandlers []AlertHandler } // SecurityAlert represents a security alert type SecurityAlert struct { ID string `json:"id"` Timestamp time.Time `json:"timestamp"` Level AlertLevel `json:"level"` Type AlertType `json:"type"` Title string `json:"title"` Description string `json:"description"` Source string `json:"source"` Data map[string]interface{} `json:"data"` Actions []string `json:"recommended_actions"` Resolved bool `json:"resolved"` ResolvedAt *time.Time `json:"resolved_at,omitempty"` ResolvedBy string `json:"resolved_by,omitempty"` } // SecurityEvent represents a security-related event type SecurityEvent struct { ID string `json:"id"` Timestamp time.Time `json:"timestamp"` Type EventType `json:"type"` Source string `json:"source"` Description string `json:"description"` Data map[string]interface{} `json:"data"` Severity EventSeverity `json:"severity"` IPAddress string `json:"ip_address,omitempty"` UserAgent string `json:"user_agent,omitempty"` } // SecurityMetrics tracks security-related metrics type SecurityMetrics struct { // Request metrics TotalRequests int64 `json:"total_requests"` BlockedRequests int64 `json:"blocked_requests"` SuspiciousRequests int64 `json:"suspicious_requests"` // Attack metrics DDoSAttempts int64 `json:"ddos_attempts"` BruteForceAttempts int64 `json:"brute_force_attempts"` SQLInjectionAttempts int64 `json:"sql_injection_attempts"` // Rate limiting metrics RateLimitViolations int64 `json:"rate_limit_violations"` IPBlocks int64 `json:"ip_blocks"` // Key management metrics KeyAccessAttempts int64 `json:"key_access_attempts"` FailedKeyAccess int64 `json:"failed_key_access"` KeyRotations int64 `json:"key_rotations"` // Transaction metrics TransactionsAnalyzed int64 `json:"transactions_analyzed"` SuspiciousTransactions int64 `json:"suspicious_transactions"` BlockedTransactions int64 `json:"blocked_transactions"` // Time series data HourlyMetrics map[string]int64 `json:"hourly_metrics"` DailyMetrics map[string]int64 `json:"daily_metrics"` // Last update LastUpdated time.Time `json:"last_updated"` } // AlertLevel represents the severity level of an alert type AlertLevel string const ( AlertLevelInfo AlertLevel = "INFO" AlertLevelWarning AlertLevel = "WARNING" AlertLevelError AlertLevel = "ERROR" AlertLevelCritical AlertLevel = "CRITICAL" ) // AlertType represents the type of security alert type AlertType string const ( AlertTypeDDoS AlertType = "DDOS" AlertTypeBruteForce AlertType = "BRUTE_FORCE" AlertTypeRateLimit AlertType = "RATE_LIMIT" AlertTypeUnauthorized AlertType = "UNAUTHORIZED_ACCESS" AlertTypeSuspicious AlertType = "SUSPICIOUS_ACTIVITY" AlertTypeKeyCompromise AlertType = "KEY_COMPROMISE" AlertTypeTransaction AlertType = "SUSPICIOUS_TRANSACTION" AlertTypeConfiguration AlertType = "CONFIGURATION_ISSUE" AlertTypePerformance AlertType = "PERFORMANCE_ISSUE" ) // EventType represents the type of security event type EventType string const ( EventTypeLogin EventType = "LOGIN" EventTypeLogout EventType = "LOGOUT" EventTypeKeyAccess EventType = "KEY_ACCESS" EventTypeTransaction EventType = "TRANSACTION" EventTypeConfiguration EventType = "CONFIGURATION_CHANGE" EventTypeError EventType = "ERROR" EventTypeAlert EventType = "ALERT" ) // EventSeverity represents the severity of a security event type EventSeverity string const ( SeverityLow EventSeverity = "LOW" SeverityMedium EventSeverity = "MEDIUM" SeverityHigh EventSeverity = "HIGH" SeverityCritical EventSeverity = "CRITICAL" ) // MonitorConfig provides configuration for security monitoring type MonitorConfig struct { // Alert settings EnableAlerts bool `json:"enable_alerts"` AlertBuffer int `json:"alert_buffer"` AlertRetention time.Duration `json:"alert_retention"` // Event settings MaxEvents int `json:"max_events"` EventRetention time.Duration `json:"event_retention"` // Monitoring intervals MetricsInterval time.Duration `json:"metrics_interval"` CleanupInterval time.Duration `json:"cleanup_interval"` // Thresholds DDoSThreshold int `json:"ddos_threshold"` ErrorRateThreshold float64 `json:"error_rate_threshold"` // Notification settings EmailNotifications bool `json:"email_notifications"` SlackNotifications bool `json:"slack_notifications"` WebhookURL string `json:"webhook_url"` } // AlertHandler defines the interface for handling security alerts type AlertHandler interface { HandleAlert(alert SecurityAlert) error GetName() string } // NewSecurityMonitor creates a new security monitor func NewSecurityMonitor(config *MonitorConfig) *SecurityMonitor { if config == nil { config = &MonitorConfig{ EnableAlerts: true, AlertBuffer: 1000, AlertRetention: 24 * time.Hour, MaxEvents: 10000, EventRetention: 7 * 24 * time.Hour, MetricsInterval: time.Minute, CleanupInterval: time.Hour, DDoSThreshold: 1000, ErrorRateThreshold: 0.05, } } sm := &SecurityMonitor{ alertChan: make(chan SecurityAlert, config.AlertBuffer), stopChan: make(chan struct{}), events: make([]SecurityEvent, 0), maxEvents: config.MaxEvents, config: config, alertHandlers: make([]AlertHandler, 0), metrics: &SecurityMetrics{ HourlyMetrics: make(map[string]int64), DailyMetrics: make(map[string]int64), LastUpdated: time.Now(), }, } // Start monitoring routines go sm.alertProcessor() go sm.metricsCollector() go sm.cleanupRoutine() return sm } // RecordEvent records a security event func (sm *SecurityMonitor) RecordEvent(eventType EventType, source, description string, severity EventSeverity, data map[string]interface{}) { event := SecurityEvent{ ID: fmt.Sprintf("evt_%d", time.Now().UnixNano()), Timestamp: time.Now(), Type: eventType, Source: source, Description: description, Data: data, Severity: severity, } // Extract IP and User Agent from data if available if ip, exists := data["ip_address"]; exists { if ipStr, ok := ip.(string); ok { event.IPAddress = ipStr } } if ua, exists := data["user_agent"]; exists { if uaStr, ok := ua.(string); ok { event.UserAgent = uaStr } } sm.eventsMutex.Lock() defer sm.eventsMutex.Unlock() // Add event to list sm.events = append(sm.events, event) // Trim events if too many if len(sm.events) > sm.maxEvents { sm.events = sm.events[len(sm.events)-sm.maxEvents:] } // Update metrics sm.updateMetricsForEvent(event) // Check if event should trigger an alert sm.checkForAlerts(event) } // TriggerAlert manually triggers a security alert func (sm *SecurityMonitor) TriggerAlert(level AlertLevel, alertType AlertType, title, description, source string, data map[string]interface{}, actions []string) { alert := SecurityAlert{ ID: fmt.Sprintf("alert_%d", time.Now().UnixNano()), Timestamp: time.Now(), Level: level, Type: alertType, Title: title, Description: description, Source: source, Data: data, Actions: actions, Resolved: false, } select { case sm.alertChan <- alert: // Alert sent successfully default: // Alert channel is full, log this issue sm.RecordEvent(EventTypeError, "SecurityMonitor", "Alert channel full", SeverityHigh, map[string]interface{}{ "alert_type": alertType, "alert_level": level, }) } } // checkForAlerts checks if an event should trigger alerts func (sm *SecurityMonitor) checkForAlerts(event SecurityEvent) { switch event.Type { case EventTypeKeyAccess: if event.Severity == SeverityCritical { sm.TriggerAlert( AlertLevelCritical, AlertTypeKeyCompromise, "Critical Key Access Event", "A critical key access event was detected", event.Source, event.Data, []string{"Investigate immediately", "Rotate keys if compromised", "Review access logs"}, ) } case EventTypeTransaction: if event.Severity == SeverityHigh || event.Severity == SeverityCritical { sm.TriggerAlert( AlertLevelError, AlertTypeTransaction, "Suspicious Transaction Detected", "A suspicious transaction was detected and blocked", event.Source, event.Data, []string{"Review transaction details", "Check for pattern", "Update security rules"}, ) } case EventTypeError: if event.Severity == SeverityCritical { sm.TriggerAlert( AlertLevelCritical, AlertTypeConfiguration, "Critical System Error", "A critical system error occurred", event.Source, event.Data, []string{"Check system logs", "Verify configuration", "Restart services if needed"}, ) } } // Check for patterns that might indicate attacks sm.checkAttackPatterns(event) } // checkAttackPatterns checks for attack patterns in events func (sm *SecurityMonitor) checkAttackPatterns(event SecurityEvent) { sm.eventsMutex.RLock() defer sm.eventsMutex.RUnlock() // Look for patterns in recent events recentEvents := make([]SecurityEvent, 0) cutoff := time.Now().Add(-5 * time.Minute) for _, e := range sm.events { if e.Timestamp.After(cutoff) { recentEvents = append(recentEvents, e) } } // Check for DDoS patterns if len(recentEvents) > sm.config.DDoSThreshold { ipCounts := make(map[string]int) for _, e := range recentEvents { if e.IPAddress != "" { ipCounts[e.IPAddress]++ } } for ip, count := range ipCounts { if count > sm.config.DDoSThreshold/10 { sm.TriggerAlert( AlertLevelError, AlertTypeDDoS, "DDoS Attack Detected", fmt.Sprintf("High request volume from IP %s", ip), "SecurityMonitor", map[string]interface{}{ "ip_address": ip, "request_count": count, "time_window": "5 minutes", }, []string{"Block IP address", "Investigate traffic pattern", "Scale infrastructure if needed"}, ) } } } // Check for brute force patterns failedLogins := 0 for _, e := range recentEvents { if e.Type == EventTypeLogin && e.Severity == SeverityHigh { failedLogins++ } } if failedLogins > 10 { sm.TriggerAlert( AlertLevelWarning, AlertTypeBruteForce, "Brute Force Attack Detected", "Multiple failed login attempts detected", "SecurityMonitor", map[string]interface{}{ "failed_attempts": failedLogins, "time_window": "5 minutes", }, []string{"Review access logs", "Consider IP blocking", "Strengthen authentication"}, ) } } // updateMetricsForEvent updates metrics based on an event func (sm *SecurityMonitor) updateMetricsForEvent(event SecurityEvent) { sm.metricsMutex.Lock() defer sm.metricsMutex.Unlock() sm.metrics.TotalRequests++ switch event.Type { case EventTypeKeyAccess: sm.metrics.KeyAccessAttempts++ if event.Severity == SeverityHigh || event.Severity == SeverityCritical { sm.metrics.FailedKeyAccess++ } case EventTypeTransaction: sm.metrics.TransactionsAnalyzed++ if event.Severity == SeverityHigh || event.Severity == SeverityCritical { sm.metrics.SuspiciousTransactions++ } } // Update time-based metrics hour := event.Timestamp.Format("2006-01-02-15") day := event.Timestamp.Format("2006-01-02") sm.metrics.HourlyMetrics[hour]++ sm.metrics.DailyMetrics[day]++ sm.metrics.LastUpdated = time.Now() } // alertProcessor processes alerts from the alert channel func (sm *SecurityMonitor) alertProcessor() { for { select { case alert := <-sm.alertChan: // Handle the alert with all registered handlers for _, handler := range sm.alertHandlers { go func(h AlertHandler, a SecurityAlert) { if err := h.HandleAlert(a); err != nil { sm.RecordEvent( EventTypeError, "AlertHandler", fmt.Sprintf("Failed to handle alert: %v", err), SeverityMedium, map[string]interface{}{ "handler": h.GetName(), "alert_id": a.ID, "error": err.Error(), }, ) } }(handler, alert) } case <-sm.stopChan: return } } } // metricsCollector periodically collects and updates metrics func (sm *SecurityMonitor) metricsCollector() { ticker := time.NewTicker(sm.config.MetricsInterval) defer ticker.Stop() for { select { case <-ticker.C: sm.collectMetrics() case <-sm.stopChan: return } } } // collectMetrics collects current system metrics func (sm *SecurityMonitor) collectMetrics() { sm.metricsMutex.Lock() defer sm.metricsMutex.Unlock() // This would collect metrics from various sources // For now, we'll just update the timestamp sm.metrics.LastUpdated = time.Now() } // cleanupRoutine periodically cleans up old events and alerts func (sm *SecurityMonitor) cleanupRoutine() { ticker := time.NewTicker(sm.config.CleanupInterval) defer ticker.Stop() for { select { case <-ticker.C: sm.cleanup() case <-sm.stopChan: return } } } // cleanup removes old events and metrics func (sm *SecurityMonitor) cleanup() { sm.eventsMutex.Lock() defer sm.eventsMutex.Unlock() // Remove old events cutoff := time.Now().Add(-sm.config.EventRetention) newEvents := make([]SecurityEvent, 0) for _, event := range sm.events { if event.Timestamp.After(cutoff) { newEvents = append(newEvents, event) } } sm.events = newEvents // Clean up old metrics sm.metricsMutex.Lock() defer sm.metricsMutex.Unlock() // Remove old hourly metrics (keep last 48 hours) hourCutoff := time.Now().Add(-48 * time.Hour) for hour := range sm.metrics.HourlyMetrics { if t, err := time.Parse("2006-01-02-15", hour); err == nil && t.Before(hourCutoff) { delete(sm.metrics.HourlyMetrics, hour) } } // Remove old daily metrics (keep last 30 days) dayCutoff := time.Now().Add(-30 * 24 * time.Hour) for day := range sm.metrics.DailyMetrics { if t, err := time.Parse("2006-01-02", day); err == nil && t.Before(dayCutoff) { delete(sm.metrics.DailyMetrics, day) } } } // AddAlertHandler adds an alert handler func (sm *SecurityMonitor) AddAlertHandler(handler AlertHandler) { sm.alertHandlers = append(sm.alertHandlers, handler) } // GetEvents returns recent security events func (sm *SecurityMonitor) GetEvents(limit int) []SecurityEvent { sm.eventsMutex.RLock() defer sm.eventsMutex.RUnlock() if limit <= 0 || limit > len(sm.events) { limit = len(sm.events) } events := make([]SecurityEvent, limit) copy(events, sm.events[len(sm.events)-limit:]) return events } // GetMetrics returns current security metrics func (sm *SecurityMonitor) GetMetrics() *SecurityMetrics { sm.metricsMutex.RLock() defer sm.metricsMutex.RUnlock() // Return a copy to avoid race conditions metrics := *sm.metrics metrics.HourlyMetrics = make(map[string]int64) metrics.DailyMetrics = make(map[string]int64) for k, v := range sm.metrics.HourlyMetrics { metrics.HourlyMetrics[k] = v } for k, v := range sm.metrics.DailyMetrics { metrics.DailyMetrics[k] = v } return &metrics } // GetDashboardData returns data for security dashboard func (sm *SecurityMonitor) GetDashboardData() map[string]interface{} { metrics := sm.GetMetrics() recentEvents := sm.GetEvents(100) // Calculate recent activity recentActivity := make(map[string]int) cutoff := time.Now().Add(-time.Hour) for _, event := range recentEvents { if event.Timestamp.After(cutoff) { recentActivity[string(event.Type)]++ } } return map[string]interface{}{ "metrics": metrics, "recent_events": recentEvents, "recent_activity": recentActivity, "system_status": sm.getSystemStatus(), "alert_summary": sm.getAlertSummary(), } } // getSystemStatus returns current system security status func (sm *SecurityMonitor) getSystemStatus() map[string]interface{} { metrics := sm.GetMetrics() status := "HEALTHY" if metrics.BlockedRequests > 0 || metrics.SuspiciousRequests > 0 { status = "MONITORING" } if metrics.DDoSAttempts > 0 || metrics.BruteForceAttempts > 0 { status = "UNDER_ATTACK" } return map[string]interface{}{ "status": status, "uptime": time.Since(metrics.LastUpdated).String(), "total_requests": metrics.TotalRequests, "blocked_requests": metrics.BlockedRequests, "success_rate": float64(metrics.TotalRequests-metrics.BlockedRequests) / float64(metrics.TotalRequests), } } // getAlertSummary returns summary of recent alerts func (sm *SecurityMonitor) getAlertSummary() map[string]interface{} { // This would typically fetch from an alert store // For now, return basic summary return map[string]interface{}{ "total_alerts": 0, "critical_alerts": 0, "unresolved_alerts": 0, "last_alert": nil, } } // Stop stops the security monitor func (sm *SecurityMonitor) Stop() { close(sm.stopChan) } // ExportEvents exports events to JSON func (sm *SecurityMonitor) ExportEvents() ([]byte, error) { sm.eventsMutex.RLock() defer sm.eventsMutex.RUnlock() return json.MarshalIndent(sm.events, "", " ") } // ExportMetrics exports metrics to JSON func (sm *SecurityMonitor) ExportMetrics() ([]byte, error) { metrics := sm.GetMetrics() return json.MarshalIndent(metrics, "", " ") }