Skip to main content

Architecture

CHAD is designed as a modern, scalable detection platform. This page explains the key architectural decisions and how components interact.

System Overview

Core Components

Frontend (React)

The frontend is a single-page application built with:
  • React 19 with TypeScript for type safety
  • React Router for client-side routing
  • React Query for server state management
  • Tailwind CSS + shadcn/ui for styling
  • Monaco Editor for YAML editing with Sigma schema support
Key design decisions:
  • All routes are protected - no public pages except login
  • Optimistic UI updates with React Query
  • WebSocket connection for live alert feed
  • Dark mode support throughout

Backend (FastAPI)

The backend is an async Python application:
  • FastAPI for high-performance async API
  • SQLAlchemy 2.0 with async support for database access
  • pySigma for Sigma rule parsing and translation
  • APScheduler for background tasks (health checks, SigmaHQ sync)
The backend handles:
  • Authentication and authorization (JWT + RBAC)
  • Rule validation and translation to OpenSearch queries
  • Alert processing and enrichment
  • Integration with external services

Database (PostgreSQL)

PostgreSQL stores all configuration and metadata:
  • Users and permissions - accounts, roles, API keys
  • Rules and versions - Sigma YAML, deployment state, history
  • Alert metadata - status, comments, enrichment results
  • Configuration - OpenSearch connection, integrations, settings
  • Audit logs - complete action history

OpenSearch

OpenSearch handles the detection workload:
  • Percolator indices - Store compiled detection queries
  • Alert indices - Store alert documents with full log context
  • Audit indices - Optional audit log storage for search

Detection Flow

Rule Deployment

When you deploy a rule, CHAD:
  1. Load the Sigma rule from PostgreSQL
  2. Translate to OpenSearch query using pySigma with your ECS field mappings
  3. Create percolator document in chad-percolator-{index} index
  4. Update status to deployed in PostgreSQL

Alert Generation

Logs flow to both CHAD and OpenSearch. CHAD performs real-time detection:
  1. Fluentd sends log to CHAD’s HTTP endpoint (POST /api/logs/{index_suffix})
  2. CHAD authenticates request using index pattern’s auth token
  3. IP allowlist checked (if configured on index pattern)
  4. Rate limits applied (if enabled)
  5. CHAD performs percolate query against OpenSearch percolator index
  6. Matching rules identified from percolator response
  7. Exception rules checked - if matched, alert suppressed
  8. GeoIP enrichment applied to configured fields
  9. TI enrichment - IOCs extracted and looked up
  10. Alert stored in OpenSearch with deterministic deduplication ID
  11. WebSocket broadcast for real-time UI updates
  12. Notifications sent via webhooks, Jira, etc.
Fluentd should be configured with two outputs: one to CHAD for detection, one to OpenSearch for log storage and search.

Data Model

Rules

rules
├── id (UUID)
├── title
├── yaml_content (Sigma YAML)
├── severity (informational, low, medium, high, critical)
├── status (deployed, undeployed, snoozed)
├── threshold_enabled
├── threshold_count
├── threshold_window_minutes
├── tags (MITRE ATT&CK, etc.)
├── created_at, updated_at
└── version_number

rule_versions
├── rule_id (FK)
├── version_number
├── yaml_content (snapshot)
├── changed_by
└── created_at

Alerts

alerts (PostgreSQL - metadata only)
├── id (UUID)
├── rule_id (FK)
├── opensearch_id (reference)
├── status (new, acknowledged, resolved, false_positive)
├── severity
└── created_at

chad-alerts-{index} (OpenSearch - full data)
├── alert_id
├── rule_id, rule_title
├── matched_log (full document)
├── enrichment (TI results)
├── timestamp
└── severity

Exception Rules

rule_exceptions
├── id (UUID)
├── rule_id (FK)
├── field_name
├── operator (equals, contains, regex, in_list, etc.)
├── value
├── group_id (for AND grouping)
└── enabled
Exception logic:
  • Conditions with same group_id are ANDed
  • Different groups are ORed
  • If any group fully matches, alert is suppressed

Security Architecture

Authentication

  • JWT tokens with 8-hour expiration
  • Token versioning - password change invalidates all tokens
  • Optional TOTP 2FA with backup codes
  • SSO support via OIDC/SAML

Authorization (RBAC)

RolePermissions
AdminFull access - users, settings, rules, alerts
AnalystRules, alerts, exceptions - no user management
ViewerRead-only access to rules and alerts

Data Protection

  • Credentials encrypted with Fernet (symmetric encryption)
  • Passwords hashed with bcrypt
  • CSRF protection for state-changing operations
  • Security headers (HSTS, CSP, X-Frame-Options)

Scalability Considerations

Current Design (Single Instance)

CHAD is currently designed for single-instance deployment:
  • Single FastAPI process with async workers
  • Background tasks via APScheduler
  • PostgreSQL for all state
This handles:
  • Thousands of rules
  • Millions of alerts
  • Small to medium security teams

Future: Horizontal Scaling

For larger deployments, the architecture supports:
  • Multiple API instances behind load balancer
  • Celery + Redis for distributed background tasks
  • Read replicas for PostgreSQL
  • OpenSearch cluster for alert storage

Integration Points

Inbound

IntegrationPurpose
OpenSearchDetection engine, alert storage
PostgreSQLConfiguration, metadata
SigmaHQRule repository

Outbound

IntegrationPurpose
WebhooksAlert notifications (Slack, Discord, custom)
Jira CloudAutomatic ticket creation
Threat Intel APIsIOC enrichment

Next Steps