Architecture
Deep dive into BlueSentinel's system architecture — server, agent, and communication flow.
System Overview
BlueSentinel uses a hub-and-spoke architecture with a central server managing multiple endpoint agents.
┌─────────────────────────────┐
│ Central Server │
│ Flask + PostgreSQL │
│ Port 5100 │
│ │
│ ┌─────────┐ ┌──────────┐ │
│ │ Admin │ │ Agent │ │
│ │ API │ │ API │ │
│ │ /admin │ │ /api/v1 │ │
│ └─────────┘ └──────────┘ │
└──────────┬────────────────────┘
│ HTTPS/TLS
┌────────────────┼────────────────┐
│ │ │
┌─────▼─────┐ ┌─────▼─────┐ ┌─────▼─────┐
│ Agent 1 │ │ Agent 2 │ │ Agent N │
│ Windows │ │ macOS │ │ Windows │
│ 10 Guards │ │ 10 Guards │ │ 10 Guards │
└────────────┘ └────────────┘ └────────────┘Central Server Components
Application Layer (Flask)
- App Factory Pattern —
create_app()configures DB, CORS, JWT middleware, and registers blueprints - Dual Authentication — JWT Bearer tokens for API clients + Flask-Login sessions for browser users
- Two API Blueprints:
- agent_bp at /api/v1 — enrollment, heartbeat, policy, alerts, commands, recovery keys
- admin_bp at /api/admin — device/group/policy/alert CRUD, enrollment tokens, reports, RBAC
Data Layer (PostgreSQL)
- 11 models with UUID primary keys and JSONB columns
- Multi-tenant isolation — Every query scoped by
tenant_id - Connection pool — Size 10, recycle every 300s, pre-ping enabled
- Key indexes — Partial indexes on unacknowledged alerts, pending commands, default policies
Multi-Tenancy
Each tenant gets isolated:
- Devices, groups, and policies
- Admin users with RBAC roles
- Alerts and audit logs
- Enrollment tokens and recovery keys
RBAC Roles: super_admin → tenant_admin → tenant_manager → viewer
DLP Agent Architecture
Startup Sequence
The agent follows a strict 10-step startup:
- Check privileges — Require root (macOS) or Administrator (Windows)
- Create directories — Set up data, logs, certs, queue directories
- Load policy — Read
policy.jsonfrom disk (offline fallback) - Load offline queue — Resume any queued alerts from disk
- Apply OS enforcement — USB block, firewall rules, proxy settings, AirDrop/BT disable
- Start guard threads — 10 daemon threads, one per guard
- Start anti-tamper loop — Check and repair every 10 seconds
- Start device manager — Heartbeat, policy sync, command polling every 60 seconds
- Register signal handlers — Graceful shutdown on SIGTERM/SIGINT
- Main thread loop — Block with 1-second sleep loop
Guard Threading Model
Each guard runs as an independent daemon thread:
Main Thread
├── USB Guard Thread
├── Network Guard Thread
├── Browser Guard Thread (includes MITM proxy on port 8889)
├── Process Guard Thread
├── Clipboard Guard Thread
├── Screenshot Guard Thread
├── File Watcher Thread
├── AirDrop/BT Guard Thread
├── Print Guard Thread
├── Encryption Guard Thread
├── Anti-Tamper Loop Thread (every 10s)
└── Device Manager Loop Thread (every 60s)Offline Mode
When the server is unreachable:
- Agent continues enforcing the last-known policy from
policy.json - Alerts are queued to disk in the
queue/directory - When connectivity resumes, queued alerts are pushed in batches of up to 50
Communication Protocol
Agent → Server
| Endpoint | Method | Frequency | Purpose |
|---|---|---|---|
| `/api/v1/enroll` | POST | Once | Device registration |
| `/api/v1/heartbeat` | POST | Every 60s | Status update, policy version check |
| `/api/v1/alerts` | POST | As needed | Batch alert upload (max 200/call) |
| `/api/v1/commands/{id}/ack` | PUT | As needed | Command execution acknowledgement |
| `/api/v1/recovery-key` | POST | On detection | Disk encryption recovery key escrow |
Server → Agent (via polling)
| Endpoint | Method | Trigger | Purpose |
|---|---|---|---|
| `/api/v1/policy/{id}` | GET | Policy version mismatch | Full policy download |
| `/api/v1/commands/{id}` | GET | Every heartbeat | Pending command retrieval |
Authentication
- Enrollment uses a one-time enrollment token
- All subsequent requests use
X-API-Key+X-Device-IDheaders - API keys are 48-byte URL-safe tokens, stored as SHA-256 hashes in the database
- Server validates the hash match on every request
Data Flow
Policy Push Flow
Admin changes policy in dashboard
→ Policy version incremented in DB
→ Agent heartbeat detects version mismatch
→ Agent fetches full policy via GET /api/v1/policy/{id}
→ Policy saved to local policy.json
→ Guards reconfigured with new settingsAlert Flow
Guard detects violation (e.g., USB inserted)
→ Alert created with guard name, severity, details
→ Alert queued to in-memory list
→ Device manager pushes batch to POST /api/v1/alerts
→ Server stores in alerts table with BIGSERIAL PK
→ Dashboard shows real-time alert streamCommand Flow
Admin sends command from dashboard
→ Command stored in DB with status "pending"
→ Agent polls GET /api/v1/commands/{id}
→ Command marked "delivered"
→ Agent executes command
→ Agent acknowledges via PUT /api/v1/commands/{cmd_id}/ack
→ Command marked "executed" or "failed"File System Layout
Agent (macOS)
/Library/Application Support/BlueSentinel/
├── policy.json # Current policy (offline fallback)
├── bluesentinel.db # Local SQLite database
├── logs/ # Agent log files
├── certs/ # TLS certificates
└── queue/ # Offline alert queueAgent (Windows)
C:\ProgramData\BlueSentinel\
├── policy.json
├── bluesentinel.db
├── logs\
├── certs\
└── queue\Anti-Tamper Architecture
Four layers of protection prevent users from disabling the agent:
- Dual Watchdog — Two independent processes monitor each other and the main agent
- Self-Healing — Watchdog downloads fresh agent copies from server if files are corrupted
- File Locking — Critical files locked at OS level while agent runs
- OS Service — Registered as Windows Service / macOS LaunchDaemon with auto-restart
The anti-tamper loop runs every 10 seconds, calling the platform enforcer's check_and_repair_all() method. If any OS-level settings have been reversed (USB re-enabled, firewall rules removed, proxy cleared), they are immediately reapplied and a tamper_detected alert is sent.