A lightweight, local-first Security Information and Event Management (SIEM) tool built with Rust and Tauri.
Guardian uses a Decoupled Binary Pattern consisting of:
- Lightweight background service for system event collection
- Monitors: File integrity, Event logs, Network sockets, Process activity
- Outputs structured JSON logs to stdout
- Minimal CPU/RAM footprint
- React/TypeScript dashboard for visualization
- Real-time event streaming via Tauri IPC
- SQLite-backed historical log storage and search
- Rule-based alerting system
Guardian/
├── Cargo.toml # Workspace definition
├── guardian-common/ # Shared data structures
│ ├── Cargo.toml
│ └── src/
│ └── lib.rs # LogEvent, Severity, EventType
├── guardian-daemon/ # Headless monitoring agent
│ ├── Cargo.toml
│ └── src/
│ ├── main.rs # Event collection & JSON output
│ └── rules.rs # Rule engine
└── guardian-sentinel/ # Tauri frontend application
├── src-tauri/
│ ├── Cargo.toml
│ ├── tauri.conf.json # Sidecar configuration
│ ├── build.rs
│ └── src/
│ ├── main.rs # Tauri setup & sidecar spawning
│ ├── lib.rs # App state management
│ └── database.rs # SQLite persistence
├── src/ # React frontend (to be implemented)
└── package.json
- Runtime:
tokio- Async runtime - Logging:
tracing- Structured logging - Serialization:
serde- Data serialization
- sysinfo: Hardware/process monitoring
- notify: Real-time file system events
- Tauri v2: Desktop application framework
- SQLite (via
sqlx): Event persistence - React + TypeScript: UI dashboard
- Rust 1.75+ (
rustup) - Node.js 18+ (for Tauri frontend)
- SQLite3
# Build in release mode for optimal performance
cargo build --release -p guardian-daemon
# The binary will be at: target/release/guardian-daemon# Set watch path (optional, defaults to /tmp/guardian-test)
export GUARDIAN_WATCH_PATH=/path/to/monitor
# Run the daemon - outputs JSON to stdout
./target/release/guardian-daemon
# Test it by creating files in the monitored directory
echo "test" > /tmp/guardian-test/testfile.txtcd guardian-sentinel
# Install frontend dependencies
npm install
# Run in development mode
npm run tauri dev
# Build for production
npm run tauri buildThe Sentinel application spawns the Guardian daemon as a sidecar process:
{
"bundle": {
"externalBin": ["binaries/guardian-daemon"]
},
"plugins": {
"shell": {
"sidecar": [
{
"name": "guardian-daemon",
"command": "binaries/guardian-daemon",
"args": []
}
]
}
}
}// Spawn the sidecar
let sidecar = shell.sidecar("guardian-daemon")?;
let (mut rx, _child) = sidecar.spawn()?;
// Read JSON lines from stdout
if let Some(stdout) = rx.stdout.take() {
let reader = BufReader::new(stdout);
let mut lines = reader.lines();
while let Some(line) = lines.next_line().await? {
let event: LogEvent = serde_json::from_str(&line)?;
// Emit to frontend
app.emit("log-event", &event)?;
// Store in database
database::insert_event(&pool, &event).await?;
}
}The guardian-common crate defines the core LogEvent structure:
pub struct LogEvent {
pub id: Uuid,
pub timestamp: DateTime<Utc>,
pub severity: Severity, // INFO, LOW, MEDIUM, HIGH, CRITICAL
pub event_type: EventType, // FileIntegrity, NetworkSocket, etc.
pub hostname: String,
pub tags: Vec<String>,
pub rule_triggered: bool,
pub rule_name: Option<String>,
}
pub enum EventType {
FileIntegrity { path: String, operation: FileOperation, hash: Option<String> },
NetworkSocket { local_addr: String, remote_addr: Option<String>, ... },
SystemLog { source: String, level: String, message: String },
ProcessMonitor { pid: u32, name: String, cpu_usage: f32, ... },
}The daemon includes a simple pattern-matching rule engine (rules.rs):
pub struct RuleEngine {
rules: Vec<Rule>,
}
impl RuleEngine {
pub fn evaluate(&self, event: &LogEvent) -> Option<String> {
for rule in &self.rules {
if (rule.matcher)(event) {
return Some(rule.name.clone());
}
}
None
}
}- Critical File Modification: Flags changes to
/etc/passwd,/etc/shadow,/etc/sudoers - High Severity Alert: Triggers on events with severity ≥ HIGH
- Suspicious Network: Detects connections to non-standard ports (4444, 31337)
- High CPU Usage: Alerts when process CPU usage > 90%
engine.add_rule(
"my_custom_rule",
Box::new(|event| {
// Your matching logic here
matches!(event.event_type, EventType::FileIntegrity { path, .. }
if path.ends_with(".secret"))
})
);SQLite table for event persistence:
CREATE TABLE events (
id TEXT PRIMARY KEY,
timestamp TEXT NOT NULL,
severity TEXT NOT NULL,
event_type TEXT NOT NULL,
event_data TEXT NOT NULL, -- JSON blob
hostname TEXT NOT NULL,
tags TEXT NOT NULL, -- JSON array
rule_triggered INTEGER NOT NULL,
rule_name TEXT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
-- Indexes for performance
CREATE INDEX idx_timestamp ON events(timestamp DESC);
CREATE INDEX idx_severity ON events(severity);
CREATE INDEX idx_rule_triggered ON events(rule_triggered);Frontend can invoke these commands:
import { invoke } from "@tauri-apps/api/core";
// Get recent events
const events = await invoke("get_recent_events", { limit: 100 });
// Get statistics
const stats = await invoke("get_event_stats");
// Search events
const results = await invoke("search_events", {
query: "passwd",
severity: "HIGH",
});Listen to real-time events in the frontend:
import { listen } from "@tauri-apps/api/event";
await listen("log-event", (event) => {
console.log("New event:", event.payload);
// Update UI with new event
});# Copy daemon to system location
sudo cp target/release/guardian-daemon /usr/local/bin/
# Create systemd service
sudo nano /etc/systemd/system/guardian-daemon.service
# Enable and start
sudo systemctl enable guardian-daemon
sudo systemctl start guardian-daemonUse the windows-service crate integration (see guardian-daemon/src/main.rs for hooks).
- Daemon Memory: ~5-10 MB idle
- Daemon CPU: <1% idle, <5% during event bursts
- Database Size: ~1 KB per event (varies by event type)
- Event Throughput: 1000+ events/sec
- Network socket monitoring implementation
- Windows Event Log integration
- React dashboard UI
- Real-time charts and visualizations
- Rule configuration UI
- Alert notifications (email, webhook)
- Multi-host aggregation
- Log rotation and retention policies
MIT
Contributions welcome! Please open an issue or PR.