/** * Интеграция с внешними системами мониторинга * * Обеспечивает интеграцию системы безопасности SFERA с внешними SIEM/SOC системами, * мониторингом инфраструктуры и системами уведомлений */ import { EventEmitter } from 'events' import { PrismaClient } from '@prisma/client' import { SecurityLogger } from '../../lib/security-logger' import { SecurityAlert } from './types' /** * Конфигурация интеграций */ interface IntegrationConfig { siem: { enabled: boolean type: 'SPLUNK' | 'ELASTIC_SIEM' | 'QRADAR' | 'SENTINEL' endpoint: string apiKey: string format: 'CEF' | 'JSON' | 'SYSLOG' } prometheus: { enabled: boolean pushGateway: string jobName: string instance: string } grafana: { enabled: boolean apiUrl: string apiKey: string dashboardId: string } datadog: { enabled: boolean apiKey: string appKey: string site: string } newrelic: { enabled: boolean licenseKey: string appId: string } slack: { enabled: boolean webhookUrl: string channel: string } teams: { enabled: boolean webhookUrl: string } pagerduty: { enabled: boolean integrationKey: string severity: 'critical' | 'error' | 'warning' | 'info' } webhook: { enabled: boolean url: string headers: Record retries: number } } /** * Метрики для экспорта */ interface SecurityMetrics { timestamp: Date totalAlerts: number alertsBySeverity: Record alertsByType: Record activeThreats: number riskScore: number systemHealth: { monitoring: number alerts: number audit: number filtering: number } userActivity: { totalAccesses: number uniqueUsers: number suspiciousActivity: number } performance: { avgResponseTime: number processingRate: number errorRate: number } } /** * События для внешних систем */ interface SecurityEvent { id: string timestamp: Date eventType: 'ALERT_GENERATED' | 'THREAT_DETECTED' | 'SYSTEM_STATUS' | 'USER_ACTIVITY' severity: 'LOW' | 'MEDIUM' | 'HIGH' | 'CRITICAL' source: string data: Record tags: string[] } export class ExternalMonitoringIntegration extends EventEmitter { private static instance: ExternalMonitoringIntegration private config: IntegrationConfig private isActive = false private metricsBuffer: SecurityMetrics[] = [] private eventsBuffer: SecurityEvent[] = [] constructor(private prisma: PrismaClient) { super() this.loadConfiguration() } /** * Получить singleton instance */ static getInstance(prisma: PrismaClient): ExternalMonitoringIntegration { if (!ExternalMonitoringIntegration.instance) { ExternalMonitoringIntegration.instance = new ExternalMonitoringIntegration(prisma) } return ExternalMonitoringIntegration.instance } /** * Запуск интеграций */ async start(): Promise { if (this.isActive) { return } this.isActive = true // Периодическая отправка метрик (каждые 30 секунд) setInterval(() => { this.pushMetrics() }, 30000) // Периодическая отправка событий (каждые 5 секунд) setInterval(() => { this.pushEvents() }, 5000) // Проверка состояния интеграций (каждые 5 минут) setInterval(() => { this.healthCheck() }, 5 * 60 * 1000) SecurityLogger.logSecurityInfo({ message: 'External monitoring integration started', integrations: Object.keys(this.config).filter((key) => this.config[key as keyof IntegrationConfig]?.enabled), }) this.emit('integration_started', { timestamp: new Date(), activeIntegrations: this.getActiveIntegrations(), }) } /** * Остановка интеграций */ stop(): void { this.isActive = false this.removeAllListeners() SecurityLogger.logSecurityInfo({ message: 'External monitoring integration stopped' }) } /** * Отправка алерта во внешние системы */ async sendSecurityAlert(alert: SecurityAlert): Promise { if (!this.isActive) { return } const event: SecurityEvent = { id: alert.id, timestamp: alert.timestamp, eventType: 'ALERT_GENERATED', severity: alert.severity, source: 'SFERA_SECURITY', data: { alertType: alert.type, userId: alert.userId, message: alert.message, metadata: alert.metadata, }, tags: ['security', 'alert', alert.type.toLowerCase(), alert.severity.toLowerCase()], } this.eventsBuffer.push(event) // Для критичных алертов - немедленная отправка if (alert.severity === 'CRITICAL' || alert.severity === 'HIGH') { await this.pushCriticalEvent(event) } } /** * Отправка метрик безопасности */ async sendSecurityMetrics(metrics: SecurityMetrics): Promise { if (!this.isActive) { return } this.metricsBuffer.push(metrics) // Если буфер переполнен - принудительная отправка if (this.metricsBuffer.length > 100) { await this.pushMetrics() } } /** * Отправка события обнаружения угрозы */ async sendThreatDetection(threat: { id: string modelId: string userId: string threatType: string confidence: number riskScore: number indicators: string[] evidence: Record }): Promise { if (!this.isActive) { return } const event: SecurityEvent = { id: threat.id, timestamp: new Date(), eventType: 'THREAT_DETECTED', severity: threat.riskScore > 80 ? 'CRITICAL' : threat.riskScore > 60 ? 'HIGH' : 'MEDIUM', source: 'SFERA_THREAT_DETECTION', data: { modelId: threat.modelId, userId: threat.userId, threatType: threat.threatType, confidence: threat.confidence, riskScore: threat.riskScore, indicators: threat.indicators, evidence: threat.evidence, }, tags: ['security', 'threat', 'detection', threat.threatType.toLowerCase()], } this.eventsBuffer.push(event) // Для высокого risk score - немедленная отправка if (threat.riskScore > 70) { await this.pushCriticalEvent(event) } } /** * Обновление статуса системы */ async sendSystemStatus(status: { monitoring: { status: string; uptime: number; metrics: Record } alerts: { status: string; uptime: number; metrics: Record } audit: { status: string; uptime: number; metrics: Record } dataFiltering: { status: string; uptime: number; metrics: Record } overallHealth: number }): Promise { if (!this.isActive) { return } const event: SecurityEvent = { id: `system-status-${Date.now()}`, timestamp: new Date(), eventType: 'SYSTEM_STATUS', severity: status.overallHealth > 95 ? 'LOW' : status.overallHealth > 80 ? 'MEDIUM' : 'HIGH', source: 'SFERA_SYSTEM', data: status, tags: ['system', 'status', 'health'], } this.eventsBuffer.push(event) } /** * Загрузка конфигурации */ private loadConfiguration(): void { this.config = { siem: { enabled: process.env.SIEM_INTEGRATION_ENABLED === 'true', type: (process.env.SIEM_TYPE as any) || 'ELASTIC_SIEM', endpoint: process.env.SIEM_ENDPOINT || '', apiKey: process.env.SIEM_API_KEY || '', format: (process.env.SIEM_FORMAT as any) || 'JSON', }, prometheus: { enabled: process.env.PROMETHEUS_ENABLED === 'true', pushGateway: process.env.PROMETHEUS_PUSH_GATEWAY || 'http://localhost:9091', jobName: process.env.PROMETHEUS_JOB_NAME || 'sfera-security', instance: process.env.PROMETHEUS_INSTANCE || 'sfera-api-01', }, grafana: { enabled: process.env.GRAFANA_ENABLED === 'true', apiUrl: process.env.GRAFANA_API_URL || '', apiKey: process.env.GRAFANA_API_KEY || '', dashboardId: process.env.GRAFANA_DASHBOARD_ID || '', }, datadog: { enabled: process.env.DATADOG_ENABLED === 'true', apiKey: process.env.DATADOG_API_KEY || '', appKey: process.env.DATADOG_APP_KEY || '', site: process.env.DATADOG_SITE || 'datadoghq.com', }, newrelic: { enabled: process.env.NEWRELIC_ENABLED === 'true', licenseKey: process.env.NEWRELIC_LICENSE_KEY || '', appId: process.env.NEWRELIC_APP_ID || '', }, slack: { enabled: process.env.SLACK_INTEGRATION_ENABLED === 'true', webhookUrl: process.env.SLACK_WEBHOOK_URL || '', channel: process.env.SLACK_CHANNEL || '#security-alerts', }, teams: { enabled: process.env.TEAMS_INTEGRATION_ENABLED === 'true', webhookUrl: process.env.TEAMS_WEBHOOK_URL || '', }, pagerduty: { enabled: process.env.PAGERDUTY_ENABLED === 'true', integrationKey: process.env.PAGERDUTY_INTEGRATION_KEY || '', severity: (process.env.PAGERDUTY_SEVERITY as any) || 'error', }, webhook: { enabled: process.env.WEBHOOK_INTEGRATION_ENABLED === 'true', url: process.env.WEBHOOK_URL || '', headers: JSON.parse(process.env.WEBHOOK_HEADERS || '{}'), retries: parseInt(process.env.WEBHOOK_RETRIES || '3'), }, } } /** * Отправка метрик */ private async pushMetrics(): Promise { if (this.metricsBuffer.length === 0) { return } const metrics = [...this.metricsBuffer] this.metricsBuffer.length = 0 const promises: Promise[] = [] if (this.config.prometheus.enabled) { promises.push(this.sendToPrometheus(metrics)) } if (this.config.datadog.enabled) { promises.push(this.sendToDatadog(metrics)) } if (this.config.newrelic.enabled) { promises.push(this.sendToNewRelic(metrics)) } if (this.config.grafana.enabled) { promises.push(this.sendToGrafana(metrics)) } await Promise.allSettled(promises) } /** * Отправка событий */ private async pushEvents(): Promise { if (this.eventsBuffer.length === 0) { return } const events = [...this.eventsBuffer] this.eventsBuffer.length = 0 const promises: Promise[] = [] if (this.config.siem.enabled) { promises.push(this.sendToSIEM(events)) } if (this.config.webhook.enabled) { promises.push(this.sendToWebhook(events)) } await Promise.allSettled(promises) } /** * Немедленная отправка критичного события */ private async pushCriticalEvent(event: SecurityEvent): Promise { const promises: Promise[] = [] if (this.config.slack.enabled) { promises.push(this.sendToSlack([event])) } if (this.config.teams.enabled) { promises.push(this.sendToTeams([event])) } if (this.config.pagerduty.enabled && event.severity === 'CRITICAL') { promises.push(this.sendToPagerDuty([event])) } await Promise.allSettled(promises) } /** * Отправка в SIEM систему */ private async sendToSIEM(events: SecurityEvent[]): Promise { try { const payload = events.map((event) => this.formatSIEMEvent(event)) const response = await fetch(this.config.siem.endpoint, { method: 'POST', headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${this.config.siem.apiKey}`, }, body: JSON.stringify({ events: payload }), }) if (!response.ok) { throw new Error(`SIEM API error: ${response.status} ${response.statusText}`) } SecurityLogger.logSecurityInfo({ message: 'Events sent to SIEM', count: events.length, siemType: this.config.siem.type, }) } catch (error) { SecurityLogger.logSecurityError(error as Error, { operation: 'sendToSIEM', eventsCount: events.length, }) } } /** * Отправка в Prometheus */ private async sendToPrometheus(metrics: SecurityMetrics[]): Promise { try { const latestMetrics = metrics[metrics.length - 1] const prometheusMetrics = this.formatPrometheusMetrics(latestMetrics) const response = await fetch(`${this.config.prometheus.pushGateway}/metrics/job/${this.config.prometheus.jobName}/instance/${this.config.prometheus.instance}`, { method: 'POST', headers: { 'Content-Type': 'text/plain', }, body: prometheusMetrics, }) if (!response.ok) { throw new Error(`Prometheus API error: ${response.status} ${response.statusText}`) } SecurityLogger.logSecurityInfo({ message: 'Metrics sent to Prometheus', metricsCount: Object.keys(latestMetrics).length, }) } catch (error) { SecurityLogger.logSecurityError(error as Error, { operation: 'sendToPrometheus', metricsCount: metrics.length, }) } } /** * Отправка в Slack */ private async sendToSlack(events: SecurityEvent[]): Promise { try { for (const event of events.filter(e => e.severity === 'CRITICAL' || e.severity === 'HIGH')) { const slackPayload = { channel: this.config.slack.channel, username: 'SFERA Security Bot', icon_emoji: ':warning:', attachments: [ { color: this.getSlackColor(event.severity), title: `🚨 Security Alert: ${event.eventType}`, text: `${event.data.message || 'Security event detected'}`, fields: [ { title: 'Severity', value: event.severity, short: true }, { title: 'Source', value: event.source, short: true }, { title: 'Event ID', value: event.id, short: true }, { title: 'Timestamp', value: event.timestamp.toISOString(), short: true }, ], footer: 'SFERA Security System', ts: Math.floor(event.timestamp.getTime() / 1000), }, ], } const response = await fetch(this.config.slack.webhookUrl, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(slackPayload), }) if (!response.ok) { throw new Error(`Slack API error: ${response.status} ${response.statusText}`) } } SecurityLogger.logSecurityInfo({ message: 'Critical events sent to Slack', count: events.length, }) } catch (error) { SecurityLogger.logSecurityError(error as Error, { operation: 'sendToSlack', eventsCount: events.length, }) } } /** * Отправка в Microsoft Teams */ private async sendToTeams(events: SecurityEvent[]): Promise { try { for (const event of events.filter(e => e.severity === 'CRITICAL' || e.severity === 'HIGH')) { const teamsPayload = { '@type': 'MessageCard', '@context': 'http://schema.org/extensions', themeColor: this.getTeamsColor(event.severity), summary: `SFERA Security Alert: ${event.eventType}`, sections: [ { activityTitle: `🚨 Security Alert: ${event.eventType}`, activitySubtitle: event.data.message || 'Security event detected', facts: [ { name: 'Severity', value: event.severity }, { name: 'Source', value: event.source }, { name: 'Event ID', value: event.id }, { name: 'Timestamp', value: event.timestamp.toISOString() }, ], markdown: true, }, ], } const response = await fetch(this.config.teams.webhookUrl, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(teamsPayload), }) if (!response.ok) { throw new Error(`Teams API error: ${response.status} ${response.statusText}`) } } SecurityLogger.logSecurityInfo({ message: 'Critical events sent to Teams', count: events.length, }) } catch (error) { SecurityLogger.logSecurityError(error as Error, { operation: 'sendToTeams', eventsCount: events.length, }) } } /** * Отправка в PagerDuty */ private async sendToPagerDuty(events: SecurityEvent[]): Promise { try { for (const event of events.filter(e => e.severity === 'CRITICAL')) { const pagerDutyPayload = { routing_key: this.config.pagerduty.integrationKey, event_action: 'trigger', payload: { summary: `SFERA Security Alert: ${event.eventType}`, severity: this.config.pagerduty.severity, source: event.source, timestamp: event.timestamp.toISOString(), custom_details: { event_id: event.id, event_type: event.eventType, data: event.data, tags: event.tags, }, }, } const response = await fetch('https://events.pagerduty.com/v2/enqueue', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(pagerDutyPayload), }) if (!response.ok) { throw new Error(`PagerDuty API error: ${response.status} ${response.statusText}`) } } SecurityLogger.logSecurityInfo({ message: 'Critical events sent to PagerDuty', count: events.length, }) } catch (error) { SecurityLogger.logSecurityError(error as Error, { operation: 'sendToPagerDuty', eventsCount: events.length, }) } } /** * Отправка в webhook */ private async sendToWebhook(events: SecurityEvent[]): Promise { let attempts = 0 const maxAttempts = this.config.webhook.retries while (attempts < maxAttempts) { try { const response = await fetch(this.config.webhook.url, { method: 'POST', headers: { 'Content-Type': 'application/json', ...this.config.webhook.headers, }, body: JSON.stringify({ events, timestamp: new Date().toISOString(), source: 'SFERA_SECURITY', }), }) if (!response.ok) { throw new Error(`Webhook API error: ${response.status} ${response.statusText}`) } SecurityLogger.logSecurityInfo({ message: 'Events sent to webhook', count: events.length, attempts: attempts + 1, }) return } catch (error) { attempts++ if (attempts >= maxAttempts) { SecurityLogger.logSecurityError(error as Error, { operation: 'sendToWebhook', eventsCount: events.length, attempts, }) return } // Экспоненциальная задержка await new Promise(resolve => setTimeout(resolve, Math.pow(2, attempts) * 1000)) } } } /** * Заглушки для других интеграций */ private async sendToDatadog(metrics: SecurityMetrics[]): Promise { // TODO: Реализовать интеграцию с Datadog console.log('📊 Datadog integration placeholder', metrics.length) } private async sendToNewRelic(metrics: SecurityMetrics[]): Promise { // TODO: Реализовать интеграцию с New Relic console.log('📈 New Relic integration placeholder', metrics.length) } private async sendToGrafana(metrics: SecurityMetrics[]): Promise { // TODO: Реализовать интеграцию с Grafana console.log('📋 Grafana integration placeholder', metrics.length) } /** * Форматирование события для SIEM */ private formatSIEMEvent(event: SecurityEvent): Record { switch (this.config.siem.format) { case 'CEF': return this.formatCEF(event) case 'SYSLOG': return this.formatSyslog(event) default: return { timestamp: event.timestamp.toISOString(), id: event.id, event_type: event.eventType, severity: event.severity, source: event.source, data: event.data, tags: event.tags, } } } /** * Форматирование в CEF */ private formatCEF(event: SecurityEvent): Record { return { cef_version: '0', device_vendor: 'SFERA', device_product: 'Security System', device_version: '3.0.0', signature_id: event.eventType, name: event.id, severity: this.mapCEFSeverity(event.severity), extension: { rt: event.timestamp.getTime(), src: event.source, msg: JSON.stringify(event.data), }, } } /** * Форматирование в Syslog */ private formatSyslog(event: SecurityEvent): Record { const priority = this.mapSyslogPriority(event.severity) return { priority, timestamp: event.timestamp.toISOString(), hostname: 'sfera-security', tag: 'SFERA-SEC', message: `[${event.eventType}] ${event.id}: ${JSON.stringify(event.data)}`, } } /** * Форматирование метрик для Prometheus */ private formatPrometheusMetrics(metrics: SecurityMetrics): string { const lines: string[] = [] const timestamp = metrics.timestamp.getTime() lines.push('# HELP sfera_security_alerts_total Total number of security alerts') lines.push('# TYPE sfera_security_alerts_total counter') lines.push(`sfera_security_alerts_total ${metrics.totalAlerts} ${timestamp}`) lines.push('# HELP sfera_security_active_threats Current number of active threats') lines.push('# TYPE sfera_security_active_threats gauge') lines.push(`sfera_security_active_threats ${metrics.activeThreats} ${timestamp}`) lines.push('# HELP sfera_security_risk_score Current overall risk score') lines.push('# TYPE sfera_security_risk_score gauge') lines.push(`sfera_security_risk_score ${metrics.riskScore} ${timestamp}`) lines.push('# HELP sfera_security_user_accesses_total Total number of user data accesses') lines.push('# TYPE sfera_security_user_accesses_total counter') lines.push(`sfera_security_user_accesses_total ${metrics.userActivity.totalAccesses} ${timestamp}`) return lines.join('\n') } /** * Получение активных интеграций */ private getActiveIntegrations(): string[] { const active: string[] = [] Object.entries(this.config).forEach(([name, config]) => { if (config.enabled) { active.push(name) } }) return active } /** * Проверка здоровья интеграций */ private async healthCheck(): Promise { const healthStatus: Record = {} // Проверяем доступность каждой интеграции if (this.config.siem.enabled) { healthStatus.siem = await this.checkSIEMHealth() } if (this.config.prometheus.enabled) { healthStatus.prometheus = await this.checkPrometheusHealth() } if (this.config.slack.enabled) { healthStatus.slack = await this.checkSlackHealth() } SecurityLogger.logSecurityInfo({ message: 'Integration health check completed', status: healthStatus, }) this.emit('health_check', { timestamp: new Date(), status: healthStatus, }) } /** * Заглушки для проверки здоровья */ private async checkSIEMHealth(): Promise { // TODO: Реализовать проверку SIEM return true } private async checkPrometheusHealth(): Promise { // TODO: Реализовать проверку Prometheus return true } private async checkSlackHealth(): Promise { // TODO: Реализовать проверку Slack return true } /** * Вспомогательные функции для форматирования */ private getSlackColor(severity: string): string { const colors: Record = { CRITICAL: '#FF0000', HIGH: '#FF8C00', MEDIUM: '#FFD700', LOW: '#00FF00', } return colors[severity] || '#808080' } private getTeamsColor(severity: string): string { const colors: Record = { CRITICAL: 'FF0000', HIGH: 'FF8C00', MEDIUM: 'FFD700', LOW: '00FF00', } return colors[severity] || '808080' } private mapCEFSeverity(severity: string): number { const mapping: Record = { LOW: 3, MEDIUM: 5, HIGH: 7, CRITICAL: 10, } return mapping[severity] || 5 } private mapSyslogPriority(severity: string): number { const mapping: Record = { LOW: 22, // local0.info MEDIUM: 20, // local0.warning HIGH: 19, // local0.error CRITICAL: 18, // local0.critical } return mapping[severity] || 20 } }