Event Bus Architecture
The Event Bus is the central nervous system of Sentinel AI SOC — a 10-step pipeline that processes every security event from ingestion to response.
Design Philosophy
Why HTTP/2 JSON (Not gRPC)?
Sentinel uses HTTP/2 JSON for all inter-component communication. This is a deliberate architectural decision:
| Factor | gRPC | HTTP/2 JSON |
|---|---|---|
| CGO Dependency | ❌ Requires CGO for protobuf | ✅ Zero CGO (pure Go) |
| Deployment | Complex (proto gen, shared types) | Simple (standard HTTP client) |
| Debuggability | Opaque binary frames | Human-readable JSON |
| Throughput | ~550 events/sec | ~520 events/sec |
| Latency (p50) | 0.8ms | 1.1ms |
| Binary size | +12MB (grpc-go + protobuf) | 0 additional |
Red Team Validation: In production red team exercises, the ~5% throughput difference was negligible for SOC workloads (target: ≥500 events/sec). The Zero CGO invariant eliminates entire classes of build and deployment issues.
Pipeline Architecture
┌─────────────┐
│ Sensor │ (sentinel-core, Shield, immune, custom)
└──────┬──────┘
│ HTTP POST /api/v1/soc/events
▼
┌──────────────────────────────────────────────────────┐
│ EVENT BUS │
│ │
│ Step 0: Secret Scanner (INVARIANT — non-disableable)│
│ ↓ │
│ Step 1: Sensor Authentication (PSK / mTLS) │
│ ↓ │
│ Step 2: Rate Limiter (≤100/sec per sensor) │
│ ↓ │
│ Step 3: Deduplication (10s sliding window) │
│ ↓ │
│ Step 4: Schema Validation (AlertEvent JSON Schema) │
│ ↓ │
│ Step 5: Decision Logger (SHA-256 hash chain) │
│ ↓ │
│ Step 6: Persistence (SQLite WAL mode) │
│ ↓ │
│ Step 7: Correlation Engine (15 rules) │
│ ↓ │
│ Step 8: Playbook Trigger (auto-response ≤ MEDIUM) │
│ ↓ │
│ Step 9: Webhook / SSE Push (dashboard + external) │
│ │
└──────────────────────────────────────────────────────┘
Step Details
Step 0: Secret Scanner
Type: INVARIANT — cannot be disabled by any configuration.
Scans every incoming event payload for leaked secrets:
| Pattern | Examples |
|---|---|
| API Keys | sk-..., AKIA..., gsk_... |
| Tokens | ghp_..., xoxb-..., Bearer ... |
| Credentials | Passwords, connection strings |
| Private Keys | -----BEGIN RSA PRIVATE KEY----- |
If a secret is detected, the event is:
- Redacted — secret replaced with
[REDACTED:key_type] - Flagged —
secret_detected: truemetadata added - Forwarded — processing continues with clean payload
// pipeline.go — Secret Scanner is always first
func (p *Pipeline) Process(event *AlertEvent) error {
// Step 0: Secret Scanner (INVARIANT — never skip)
event.Payload = p.secretScanner.Scan(event.Payload)
// All subsequent steps...
}
Step 1: Sensor Authentication
Every sensor must authenticate before events are accepted:
| Method | Configuration | Use Case |
|---|---|---|
| PSK | Pre-shared key in header | Simple deployments |
| mTLS | Client certificate | Production deployments |
| None | Disabled | Development only |
# syntrex.yaml
sensors:
- type: sentinel-core
auth:
type: "psk"
key: "${SENSOR_CORE_PSK}"
Step 2: Rate Limiter
Token bucket algorithm per sensor_id:
- Default: 100 events/sec per sensor
- Burst: 150 events (1.5x bucket)
- Overflow: Events queued, then dropped with warning
Sensor → [Token Bucket: 100/sec] → Accept or Queue
When a sensor exceeds its rate limit:
- SOC generates a
rate_limit_exceededalert - Events are queued (up to buffer capacity)
- If queue is full, events are dropped with
dropped_eventsmetric increment
Step 3: Deduplication
Sliding window deduplication using event fingerprinting:
Fingerprint = SHA256(source + category + description + severity)
| Setting | Default | Description |
|---|---|---|
dedup_window | 10s | Time window for duplicate detection |
| Algorithm | SHA-256 fingerprint | Exact match dedup |
If a duplicate is found, it is silently dropped. The dedup_count metric tracks filtered duplicates.
Step 4: Schema Validation
Every event must conform to the AlertEvent schema:
{
"source": "sentinel-core", // Required: sensor identifier
"severity": "HIGH", // Required: INFO|LOW|MEDIUM|HIGH|CRITICAL
"category": "jailbreak", // Required: attack category
"description": "...", // Required: human-readable description
"confidence": 0.95, // Optional: 0.0-1.0
"payload": {}, // Optional: additional data
"timestamp": "2026-03-13T..." // Auto-set if not provided
}
Invalid events are rejected with HTTP 400 and logged.
Step 5: Decision Logger
Immutable audit trail using SHA-256 hash chains:
Entry N:
event_id: EVT-1710295200-042
action: "accepted"
timestamp: 2026-03-13T01:00:00Z
prev_hash: "a3b8c1d2e5f6..."
hash: SHA256(entry_data + prev_hash) = "7f8e9d0c..."
Each entry is cryptographically linked to the previous one. Any modification breaks the chain and is detected by gomcp doctor.
Storage: Append-only JSONL file with O_APPEND flag (kernel-level atomicity).
Optional: TPM 2.0 sealing for hardware-bound integrity (SEC-006).
Step 6: Persistence
Events are persisted to SQLite in WAL (Write-Ahead Logging) mode:
| Setting | Value |
|---|---|
| Engine | SQLite 3.40+ |
| Mode | WAL (concurrent reads) |
| Journal | WAL mode |
| Synchronous | NORMAL |
| Max DB size | Configurable (default: 10GB) |
Step 7: Correlation
Events are matched against 15 correlation rules. See Correlation Engine for full details.
Step 8: Playbook Trigger
If a correlation rule matches and a playbook is configured:
| Severity | Action |
|---|---|
| INFO / LOW | Auto-execute playbook (if configured) |
| MEDIUM | Auto-execute playbook |
| HIGH | Require operator approval (Zero-G mode) |
| CRITICAL | Require operator approval (Zero-G mode) |
Step 9: Webhook / SSE Push
After processing, events and incidents are pushed to:
| Target | Protocol | Purpose |
|---|---|---|
| Dashboard | SSE | Real-time UI updates |
| Webhooks | HTTP POST | External SIEM integration |
| Slack/Teams | Webhook | Operator notifications |
Ring Buffer
The Event Bus uses a lock-free ring buffer for ingestion:
┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┐
│ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │ 9 │
└───┴───┴───┴───┴───┴───┴───┴───┴───┴───┘
↑ ↑
Read pointer Write pointer
| Setting | Default | Description |
|---|---|---|
buffer_size | 10,000 | Ring buffer capacity |
batch_size | 100 | Events per processing batch |
flush_interval | 1s | Max wait before batch flush |
Metrics
The Event Bus exposes Prometheus metrics:
| Metric | Type | Description |
|---|---|---|
sentinel_events_total | counter | Total events received |
sentinel_events_processed | counter | Events successfully processed |
sentinel_events_dropped | counter | Events dropped (rate limit / buffer full) |
sentinel_events_deduplicated | counter | Duplicate events filtered |
sentinel_pipeline_latency_ms | histogram | End-to-end pipeline latency |
sentinel_secrets_detected | counter | Secrets found by scanner |
sentinel_buffer_usage | gauge | Current ring buffer utilization |
Error Handling
| Error | Behavior |
|---|---|
| Sensor auth failure | HTTP 401, logged, auth_failures metric |
| Rate limit exceeded | HTTP 429, queued, rate_limited metric |
| Schema validation failure | HTTP 400, logged, validation_failures metric |
| Database write failure | Retry 3x, then queue, alert generated |
| Correlation failure | Event persisted, correlation skipped, alert |
Next Steps
- Correlation Engine — Rules and clustering
- AlertEvent Schema — Full JSON schema
- Metrics Reference — All Prometheus metrics