1use anyhow::Result;
7use chrono::{DateTime, Utc};
8use serde::{Deserialize, Serialize};
9use std::collections::HashMap;
10use std::fmt;
11use std::path::PathBuf;
12use std::sync::Arc;
13use tokio::sync::RwLock;
14use tracing::{debug, info};
15use uuid::Uuid;
16
17#[derive(Debug, Clone, Serialize, Deserialize)]
19pub struct EnterpriseAuditConfig {
20 pub enabled: bool,
22 pub storage: AuditStorageConfig,
24 pub filtering: AuditFilterConfig,
26 pub retention: AuditRetentionConfig,
28 pub compliance: ComplianceConfig,
30 pub encryption: AuditEncryptionConfig,
32 pub streaming: AuditStreamingConfig,
34}
35
36impl Default for EnterpriseAuditConfig {
37 fn default() -> Self {
38 Self {
39 enabled: true,
40 storage: AuditStorageConfig::default(),
41 filtering: AuditFilterConfig::default(),
42 retention: AuditRetentionConfig::default(),
43 compliance: ComplianceConfig::default(),
44 encryption: AuditEncryptionConfig::default(),
45 streaming: AuditStreamingConfig::default(),
46 }
47 }
48}
49
50#[derive(Debug, Clone, Serialize, Deserialize)]
52pub struct AuditStorageConfig {
53 pub backend: AuditStorageBackend,
55 pub file_path: Option<PathBuf>,
57 pub database_url: Option<String>,
59 pub s3_config: Option<S3AuditConfig>,
61 pub buffer_size: usize,
63 pub flush_interval_secs: u64,
65}
66
67impl Default for AuditStorageConfig {
68 fn default() -> Self {
69 Self {
70 backend: AuditStorageBackend::File,
71 file_path: Some(PathBuf::from("/var/log/oxirs/audit.jsonl")),
72 database_url: None,
73 s3_config: None,
74 buffer_size: 1000,
75 flush_interval_secs: 60,
76 }
77 }
78}
79
80#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
82pub enum AuditStorageBackend {
83 File,
85 Database,
87 S3,
89 Elasticsearch,
91 Splunk,
93 Custom,
95}
96
97#[derive(Debug, Clone, Serialize, Deserialize)]
99pub struct S3AuditConfig {
100 pub bucket: String,
102 pub region: String,
104 pub prefix: String,
106 pub access_key_id: Option<String>,
108 pub secret_access_key: Option<String>,
110 pub server_side_encryption: bool,
112}
113
114#[derive(Debug, Clone, Serialize, Deserialize)]
116pub struct AuditFilterConfig {
117 pub min_severity: AuditSeverity,
119 pub include_event_types: Vec<AuditEventType>,
121 pub exclude_event_types: Vec<AuditEventType>,
123 pub exclude_users: Vec<String>,
125 pub exclude_resources: Vec<String>,
127}
128
129impl Default for AuditFilterConfig {
130 fn default() -> Self {
131 Self {
132 min_severity: AuditSeverity::Info,
133 include_event_types: vec![],
134 exclude_event_types: vec![],
135 exclude_users: vec![],
136 exclude_resources: vec![],
137 }
138 }
139}
140
141#[derive(Debug, Clone, Serialize, Deserialize)]
143pub struct AuditRetentionConfig {
144 pub retention_days: u32,
146 pub archive_enabled: bool,
148 pub archive_destination: Option<String>,
150 pub archive_compression: CompressionType,
152 pub auto_cleanup: bool,
154}
155
156impl Default for AuditRetentionConfig {
157 fn default() -> Self {
158 Self {
159 retention_days: 365, archive_enabled: true,
161 archive_destination: None,
162 archive_compression: CompressionType::Gzip,
163 auto_cleanup: true,
164 }
165 }
166}
167
168#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
170pub enum CompressionType {
171 None,
172 Gzip,
173 Zstd,
174 Bzip2,
175}
176
177#[derive(Debug, Clone, Serialize, Deserialize)]
179pub struct ComplianceConfig {
180 pub standards: Vec<ComplianceStandard>,
182 pub reporting_enabled: bool,
184 pub report_interval_days: u32,
186 pub report_destination: Option<String>,
188}
189
190impl Default for ComplianceConfig {
191 fn default() -> Self {
192 Self {
193 standards: vec![ComplianceStandard::SOC2],
194 reporting_enabled: true,
195 report_interval_days: 30,
196 report_destination: None,
197 }
198 }
199}
200
201#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
203pub enum ComplianceStandard {
204 GDPR,
206 HIPAA,
208 SOC2,
210 PCIDSS,
212 ISO27001,
214}
215
216impl fmt::Display for ComplianceStandard {
217 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
218 match self {
219 ComplianceStandard::GDPR => write!(f, "GDPR"),
220 ComplianceStandard::HIPAA => write!(f, "HIPAA"),
221 ComplianceStandard::SOC2 => write!(f, "SOC2"),
222 ComplianceStandard::PCIDSS => write!(f, "PCI-DSS"),
223 ComplianceStandard::ISO27001 => write!(f, "ISO 27001"),
224 }
225 }
226}
227
228#[derive(Debug, Clone, Serialize, Deserialize)]
230pub struct AuditEncryptionConfig {
231 pub enabled: bool,
233 pub algorithm: EncryptionAlgorithm,
235 pub key_management: KeyManagementConfig,
237}
238
239impl Default for AuditEncryptionConfig {
240 fn default() -> Self {
241 Self {
242 enabled: true,
243 algorithm: EncryptionAlgorithm::AES256GCM,
244 key_management: KeyManagementConfig::default(),
245 }
246 }
247}
248
249#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
251pub enum EncryptionAlgorithm {
252 AES256GCM,
253 ChaCha20Poly1305,
254 AES256CBC,
255}
256
257#[derive(Debug, Clone, Serialize, Deserialize)]
259pub struct KeyManagementConfig {
260 pub kms_type: KmsType,
262 pub kms_url: Option<String>,
264 pub rotation_interval_days: u32,
266}
267
268impl Default for KeyManagementConfig {
269 fn default() -> Self {
270 Self {
271 kms_type: KmsType::Local,
272 kms_url: None,
273 rotation_interval_days: 90,
274 }
275 }
276}
277
278#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
280pub enum KmsType {
281 Local,
283 AwsKms,
285 AzureKeyVault,
287 GcpKms,
289 HashiCorpVault,
291}
292
293#[derive(Debug, Clone, Serialize, Deserialize, Default)]
295pub struct AuditStreamingConfig {
296 pub enabled: bool,
298 pub destinations: Vec<StreamingDestination>,
300}
301
302#[derive(Debug, Clone, Serialize, Deserialize)]
304pub struct StreamingDestination {
305 pub destination_type: DestinationType,
307 pub endpoint: String,
309 pub auth: Option<DestinationAuth>,
311}
312
313#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
315pub enum DestinationType {
316 Kafka,
317 Kinesis,
318 Webhook,
319 SIEM,
320}
321
322#[derive(Debug, Clone, Serialize, Deserialize)]
324pub struct DestinationAuth {
325 pub auth_type: AuthType,
326 pub credentials: HashMap<String, String>,
327}
328
329#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
331pub enum AuthType {
332 ApiKey,
333 OAuth2,
334 Basic,
335 Certificate,
336}
337
338#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Hash)]
340pub enum AuditEventType {
341 Authentication,
343 Authorization,
345 DataAccess,
347 DataModification,
349 ConfigurationChange,
351 Security,
353 System,
355 Administrative,
357 Compliance,
359}
360
361impl fmt::Display for AuditEventType {
362 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
363 match self {
364 AuditEventType::Authentication => write!(f, "Authentication"),
365 AuditEventType::Authorization => write!(f, "Authorization"),
366 AuditEventType::DataAccess => write!(f, "DataAccess"),
367 AuditEventType::DataModification => write!(f, "DataModification"),
368 AuditEventType::ConfigurationChange => write!(f, "ConfigurationChange"),
369 AuditEventType::Security => write!(f, "Security"),
370 AuditEventType::System => write!(f, "System"),
371 AuditEventType::Administrative => write!(f, "Administrative"),
372 AuditEventType::Compliance => write!(f, "Compliance"),
373 }
374 }
375}
376
377#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
379pub enum AuditSeverity {
380 Debug,
381 Info,
382 Warning,
383 Error,
384 Critical,
385}
386
387impl fmt::Display for AuditSeverity {
388 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
389 match self {
390 AuditSeverity::Debug => write!(f, "DEBUG"),
391 AuditSeverity::Info => write!(f, "INFO"),
392 AuditSeverity::Warning => write!(f, "WARNING"),
393 AuditSeverity::Error => write!(f, "ERROR"),
394 AuditSeverity::Critical => write!(f, "CRITICAL"),
395 }
396 }
397}
398
399#[derive(Debug, Clone, Serialize, Deserialize)]
401pub struct EnterpriseAuditEvent {
402 pub event_id: String,
404 pub timestamp: DateTime<Utc>,
406 pub event_type: AuditEventType,
408 pub severity: AuditSeverity,
410 pub user_id: Option<String>,
412 pub source_ip: Option<String>,
414 pub resource: String,
416 pub action: String,
418 pub result: ActionResult,
420 pub details: HashMap<String, serde_json::Value>,
422 pub compliance_tags: Vec<ComplianceStandard>,
424 pub session_id: Option<String>,
426 pub request_id: Option<String>,
428 pub correlation_id: Option<String>,
430}
431
432#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
434pub enum ActionResult {
435 Success,
436 Failure,
437 PartialSuccess,
438 Denied,
439}
440
441impl fmt::Display for ActionResult {
442 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
443 match self {
444 ActionResult::Success => write!(f, "SUCCESS"),
445 ActionResult::Failure => write!(f, "FAILURE"),
446 ActionResult::PartialSuccess => write!(f, "PARTIAL_SUCCESS"),
447 ActionResult::Denied => write!(f, "DENIED"),
448 }
449 }
450}
451
452pub struct EnterpriseAuditLogger {
454 config: EnterpriseAuditConfig,
455 buffer: Arc<RwLock<Vec<EnterpriseAuditEvent>>>,
456 metrics: Arc<RwLock<AuditMetrics>>,
457}
458
459#[derive(Debug, Clone, Default, Serialize, Deserialize)]
461pub struct AuditMetrics {
462 pub events_total: u64,
464 pub events_by_type: HashMap<String, u64>,
466 pub events_by_severity: HashMap<String, u64>,
468 pub events_by_result: HashMap<String, u64>,
470 pub events_failed: u64,
472 pub buffer_flushes: u64,
474 pub last_flush: Option<DateTime<Utc>>,
476}
477
478impl EnterpriseAuditLogger {
479 pub fn new(config: EnterpriseAuditConfig) -> Self {
481 Self {
482 config,
483 buffer: Arc::new(RwLock::new(Vec::new())),
484 metrics: Arc::new(RwLock::new(AuditMetrics::default())),
485 }
486 }
487
488 pub async fn initialize(&self) -> Result<()> {
490 if !self.config.enabled {
491 info!("Enterprise audit logging is disabled");
492 return Ok(());
493 }
494
495 info!("Initializing enterprise audit logger");
496
497 self.initialize_storage().await?;
499
500 self.start_background_flusher().await?;
502
503 if self.config.streaming.enabled {
505 self.initialize_streaming().await?;
506 }
507
508 info!("Enterprise audit logger initialized successfully");
509 Ok(())
510 }
511
512 async fn initialize_storage(&self) -> Result<()> {
514 match self.config.storage.backend {
515 AuditStorageBackend::File => {
516 if let Some(path) = &self.config.storage.file_path {
517 if let Some(parent) = path.parent() {
519 tokio::fs::create_dir_all(parent).await?;
520 }
521 debug!("File storage initialized: {:?}", path);
522 }
523 }
524 AuditStorageBackend::Database => {
525 debug!("Database storage initialization (placeholder)");
526 }
527 AuditStorageBackend::S3 => {
528 debug!("S3 storage initialization (placeholder)");
529 }
530 AuditStorageBackend::Elasticsearch => {
531 debug!("Elasticsearch storage initialization (placeholder)");
532 }
533 AuditStorageBackend::Splunk => {
534 debug!("Splunk storage initialization (placeholder)");
535 }
536 AuditStorageBackend::Custom => {
537 debug!("Custom storage initialization (placeholder)");
538 }
539 }
540
541 Ok(())
542 }
543
544 async fn start_background_flusher(&self) -> Result<()> {
546 debug!("Starting background audit log flusher");
547 Ok(())
550 }
551
552 async fn initialize_streaming(&self) -> Result<()> {
554 debug!("Initializing audit event streaming");
555 for destination in &self.config.streaming.destinations {
556 debug!(
557 "Setting up streaming to {:?}: {}",
558 destination.destination_type, destination.endpoint
559 );
560 }
561 Ok(())
562 }
563
564 pub async fn log_event(&self, event: EnterpriseAuditEvent) -> Result<()> {
566 if !self.config.enabled {
567 return Ok(());
568 }
569
570 if !self.should_log_event(&event).await {
572 return Ok(());
573 }
574
575 {
577 let mut buffer = self.buffer.write().await;
578 buffer.push(event.clone());
579
580 if buffer.len() >= self.config.storage.buffer_size {
582 drop(buffer);
583 self.flush_buffer().await?;
584 }
585 }
586
587 {
589 let mut metrics = self.metrics.write().await;
590 metrics.events_total += 1;
591 *metrics
592 .events_by_type
593 .entry(event.event_type.to_string())
594 .or_insert(0) += 1;
595 *metrics
596 .events_by_severity
597 .entry(event.severity.to_string())
598 .or_insert(0) += 1;
599 *metrics
600 .events_by_result
601 .entry(event.result.to_string())
602 .or_insert(0) += 1;
603 }
604
605 if self.config.streaming.enabled {
607 self.stream_event(&event).await?;
608 }
609
610 Ok(())
611 }
612
613 async fn should_log_event(&self, event: &EnterpriseAuditEvent) -> bool {
615 if event.severity < self.config.filtering.min_severity {
617 return false;
618 }
619
620 if self
622 .config
623 .filtering
624 .exclude_event_types
625 .contains(&event.event_type)
626 {
627 return false;
628 }
629
630 if !self.config.filtering.include_event_types.is_empty()
632 && !self
633 .config
634 .filtering
635 .include_event_types
636 .contains(&event.event_type)
637 {
638 return false;
639 }
640
641 if let Some(user_id) = &event.user_id {
643 if self.config.filtering.exclude_users.contains(user_id) {
644 return false;
645 }
646 }
647
648 true
649 }
650
651 pub async fn flush_buffer(&self) -> Result<()> {
653 let events = {
654 let mut buffer = self.buffer.write().await;
655 if buffer.is_empty() {
656 return Ok(());
657 }
658 std::mem::take(&mut *buffer)
659 };
660
661 debug!("Flushing {} audit events to storage", events.len());
662
663 self.write_to_storage(&events).await?;
665
666 {
668 let mut metrics = self.metrics.write().await;
669 metrics.buffer_flushes += 1;
670 metrics.last_flush = Some(Utc::now());
671 }
672
673 Ok(())
674 }
675
676 async fn write_to_storage(&self, events: &[EnterpriseAuditEvent]) -> Result<()> {
678 match self.config.storage.backend {
679 AuditStorageBackend::File => {
680 if let Some(path) = &self.config.storage.file_path {
681 let mut content = String::new();
683 for event in events {
684 let json = serde_json::to_string(event)?;
685 content.push_str(&json);
686 content.push('\n');
687 }
688
689 debug!("Would write {} bytes to {:?}", content.len(), path);
692 }
693 }
694 _ => {
695 debug!("Writing to {:?} (placeholder)", self.config.storage.backend);
696 }
697 }
698
699 Ok(())
700 }
701
702 async fn stream_event(&self, event: &EnterpriseAuditEvent) -> Result<()> {
704 for destination in &self.config.streaming.destinations {
705 debug!(
706 "Streaming event {} to {:?}",
707 event.event_id, destination.destination_type
708 );
709 }
711 Ok(())
712 }
713
714 pub async fn get_metrics(&self) -> AuditMetrics {
716 self.metrics.read().await.clone()
717 }
718
719 pub async fn generate_compliance_report(
721 &self,
722 standard: ComplianceStandard,
723 start_date: DateTime<Utc>,
724 end_date: DateTime<Utc>,
725 ) -> Result<ComplianceReport> {
726 info!(
727 "Generating compliance report for {} from {} to {}",
728 standard, start_date, end_date
729 );
730
731 Ok(ComplianceReport {
735 standard,
736 report_id: Uuid::new_v4().to_string(),
737 generated_at: Utc::now(),
738 period_start: start_date,
739 period_end: end_date,
740 total_events: 0,
741 findings: vec![],
742 summary: "Compliance report placeholder".to_string(),
743 })
744 }
745}
746
747#[derive(Debug, Clone, Serialize, Deserialize)]
749pub struct ComplianceReport {
750 pub standard: ComplianceStandard,
752 pub report_id: String,
754 pub generated_at: DateTime<Utc>,
756 pub period_start: DateTime<Utc>,
758 pub period_end: DateTime<Utc>,
760 pub total_events: u64,
762 pub findings: Vec<ComplianceFinding>,
764 pub summary: String,
766}
767
768#[derive(Debug, Clone, Serialize, Deserialize)]
770pub struct ComplianceFinding {
771 pub finding_id: String,
773 pub finding_type: FindingType,
775 pub severity: AuditSeverity,
777 pub description: String,
779 pub affected_events: Vec<String>,
781 pub remediation: Option<String>,
783}
784
785#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
787pub enum FindingType {
788 NonCompliance,
789 Warning,
790 BestPractice,
791}
792
793#[cfg(test)]
794mod tests {
795 use super::*;
796
797 #[tokio::test]
798 async fn test_audit_config_default() {
799 let config = EnterpriseAuditConfig::default();
800 assert!(config.enabled);
801 assert_eq!(config.retention.retention_days, 365);
802 }
803
804 #[tokio::test]
805 async fn test_audit_logger_creation() {
806 let config = EnterpriseAuditConfig::default();
807 let logger = EnterpriseAuditLogger::new(config);
808 let metrics = logger.get_metrics().await;
809 assert_eq!(metrics.events_total, 0);
810 }
811
812 #[tokio::test]
813 async fn test_compliance_standard_display() {
814 assert_eq!(ComplianceStandard::GDPR.to_string(), "GDPR");
815 assert_eq!(ComplianceStandard::HIPAA.to_string(), "HIPAA");
816 assert_eq!(ComplianceStandard::SOC2.to_string(), "SOC2");
817 }
818
819 #[tokio::test]
820 async fn test_audit_severity_ordering() {
821 assert!(AuditSeverity::Critical > AuditSeverity::Error);
822 assert!(AuditSeverity::Error > AuditSeverity::Warning);
823 assert!(AuditSeverity::Warning > AuditSeverity::Info);
824 assert!(AuditSeverity::Info > AuditSeverity::Debug);
825 }
826
827 #[tokio::test]
828 async fn test_action_result_display() {
829 assert_eq!(ActionResult::Success.to_string(), "SUCCESS");
830 assert_eq!(ActionResult::Failure.to_string(), "FAILURE");
831 assert_eq!(ActionResult::Denied.to_string(), "DENIED");
832 }
833}