191 lines
11 KiB
Markdown
191 lines
11 KiB
Markdown
# Architecture Overview
|
|
|
|
NexusGuard is a three-component SD-WAN system: a central API server, a web dashboard, and cross-platform device agents. All communication is encrypted. Tunnels are fileless. Access is zero-trust.
|
|
|
|
## High-Level Architecture
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────────────────┐
|
|
│ Dashboard (Vue 3) │
|
|
│ Glassmorphism Web Interface │
|
|
│ Manages: Nodes, Devices, Rules │
|
|
└───────────────────────────────────┬─────────────────────────────────┘
|
|
│ HTTP (port 80)
|
|
▼
|
|
┌─────────────────────────────────────────────────────────────────────┐
|
|
│ Nginx Reverse Proxy │
|
|
│ Routes: /api/ → :8080, / → SPA │
|
|
└───────────────────────────────────┬─────────────────────────────────┘
|
|
│
|
|
▼
|
|
┌─────────────────────────────────────────────────────────────────────┐
|
|
│ Server Core (Go/Gin) │
|
|
│ │
|
|
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────────────┐ │
|
|
│ │ HTTP API │ │ gRPC │ │ IPAM │ │ nftables │ │
|
|
│ │ (20+ │ │ Signaling│ │ Manager │ │ Firewall │ │
|
|
│ │ handlers)│ │ (cmux) │ │ │ │ │ │
|
|
│ └────┬─────┘ └────┬─────┘ └────┬─────┘ └────────┬─────────┘ │
|
|
│ │ │ │ │ │
|
|
│ ▼ ▼ ▼ ▼ │
|
|
│ ┌─────────────────────────────────────────────────────────────┐ │
|
|
│ │ PostgreSQL Database │ │
|
|
│ │ (wg_servers, devices, rules, users) │ │
|
|
│ └─────────────────────────────────────────────────────────────┘ │
|
|
│ │
|
|
│ ┌──────────────────────┐ ┌──────────────────────┐ │
|
|
│ │ Redis │ │ WireGuard │ │
|
|
│ │ (Heartbeat TTL) │ │ (wg0 interface) │ │
|
|
│ └──────────────────────┘ └──────────────────────┘ │
|
|
└─────────────────────────────────────────────────────────────────────┘
|
|
│
|
|
┌───────────────┴───────────────┐
|
|
│ │
|
|
▼ ▼
|
|
┌───────────────────────────┐ ┌───────────────────────────┐
|
|
│ Device Agent (Linux) │ │ Device Agent (Win/Mac) │
|
|
│ Systemd Daemon │ │ System Tray │
|
|
│ Memory-injected WG │ │ Memory-injected WG │
|
|
└───────────────────────────┘ └───────────────────────────┘
|
|
```
|
|
|
|
## Component Breakdown
|
|
|
|
### Server Core
|
|
|
|
The central API and VPN hub. Written in Go with Gin framework.
|
|
|
|
| Responsibility | Implementation |
|
|
|----------------|----------------|
|
|
| API endpoints | 20+ Gin handlers (`api/` directory) |
|
|
| gRPC signaling | Bidirectional streaming via cmux (port 8080) |
|
|
| IPAM | IP pool allocation from CIDR per node |
|
|
| Firewall | nftables rule management (add/remove per peer) |
|
|
| WireGuard | Interface control, peer sync, config push |
|
|
| Auth | JWT middleware, admin-only enforcement |
|
|
| Heartbeat | Config sync, handshake monitoring |
|
|
|
|
### Dashboard UI
|
|
|
|
Admin web interface. Built with Vue 3 and glassmorphism design system.
|
|
|
|
| Responsibility | Implementation |
|
|
|----------------|----------------|
|
|
| Node management | Register/edit WireGuard servers |
|
|
| Device management | CRUD, provisioning tokens, QR codes |
|
|
| Firewall rules | Per-peer nftables rule editor |
|
|
| Live telemetry | 10s polling for device health |
|
|
| Traffic history | Time-range filtering, export |
|
|
|
|
### Device Agent
|
|
|
|
Stealth VPN daemon. Cross-platform Go binary.
|
|
|
|
| Responsibility | Implementation |
|
|
|----------------|----------------|
|
|
| Provisioning | HTTP POST with AES-256-GCM encrypted response |
|
|
| Tunnel | Memory-injected WireGuard (no disk files) |
|
|
| Heartbeat | HTTP/gRPC, config sync, handshake monitoring |
|
|
| gRPC | Bidirectional stream for real-time commands |
|
|
| Self-healing | Exponential backoff reconnection |
|
|
|
|
## Data Flow
|
|
|
|
### Provisioning Flow
|
|
|
|
```
|
|
1. Admin creates device via Dashboard → API generates registration token
|
|
2. Agent sends token + HWID to POST /api/v1/provision
|
|
3. Server validates token, allocates IP from pool
|
|
4. Server responds with WireGuard config (AES-256-GCM encrypted)
|
|
5. Agent decrypts config, injects into WireGuard via IpcSet
|
|
6. Tunnel established — no files written to disk
|
|
```
|
|
|
|
### Heartbeat Flow
|
|
|
|
```
|
|
Every 30 seconds:
|
|
1. Agent reads last_handshake_time from WireGuard IPC
|
|
2. Agent computes config_hash = endpoint + internalIP + serverPub
|
|
3. Agent POSTs {config_hash, last_handshake, tunnel_up} to server
|
|
4. Server compares with stored config
|
|
5. If config changed → server responds with new config
|
|
6. Agent detects change → rebuilds tunnel
|
|
```
|
|
|
|
### Suspend/Resume Flow
|
|
|
|
```
|
|
Suspend:
|
|
1. Admin clicks "Suspend" in Dashboard
|
|
2. Dashboard POSTs /api/v1/devices/:id/suspend
|
|
3. Server updates DB (is_suspended = true)
|
|
4. Server sends gRPC SuspendCommand to agent
|
|
5. Server removes WireGuard peer from kernel
|
|
6. Agent receives command → stops tunnel
|
|
|
|
Resume:
|
|
1. Admin clicks "Resume" in Dashboard
|
|
2. Server updates DB (is_suspended = false)
|
|
3. Server re-adds WireGuard peer to kernel
|
|
4. Server sends gRPC ResumeCommand with full ConfigUpdate
|
|
5. Agent receives command → rebuilds tunnel
|
|
```
|
|
|
|
## Security Model
|
|
|
|
### Zero-Trust Principles
|
|
|
|
| Principle | Implementation |
|
|
|-----------|----------------|
|
|
| No public registration | `/auth/register` locked; admin via CLI only |
|
|
| Encrypted provisioning | AES-256-GCM for WireGuard config transfer |
|
|
| Fileless tunnels | WireGuard config in process memory only |
|
|
| Hardware binding | HWID (DMI/CPU serial) bound to registration token |
|
|
| Per-peer isolation | nftables rules per device, default deny |
|
|
| JWT authentication | All API endpoints require valid token |
|
|
|
|
### Trust Boundaries
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────┐
|
|
│ Trusted Zone │
|
|
│ │
|
|
│ ┌──────────┐ ┌──────────┐ ┌──────────────────────┐ │
|
|
│ │ Server │ │ Database │ │ WireGuard Interface │ │
|
|
│ │ Core │ │ (PG) │ │ (wg0) │ │
|
|
│ └──────────┘ └──────────┘ └──────────────────────┘ │
|
|
│ │
|
|
└─────────────────────────────────────────────────────────┘
|
|
│
|
|
Encrypted Channel
|
|
(AES-256-GCM / WG)
|
|
│
|
|
┌─────────────────────────────────────────────────────────┐
|
|
│ Untrusted Zone │
|
|
│ │
|
|
│ ┌──────────────────────────────────────────────────┐ │
|
|
│ │ Device Agent │ │
|
|
│ │ (Memory-only WireGuard config) │ │
|
|
│ └──────────────────────────────────────────────────┘ │
|
|
│ │
|
|
└─────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
## Port Multiplexing
|
|
|
|
Server Core uses cmux to serve both HTTP and gRPC on port 8080:
|
|
|
|
```go
|
|
m := cmux.New(lis)
|
|
grpcLis := m.MatchWithWriters(cmux.HTTP2MatchHeaderFieldSendSettings(
|
|
"content-type", "application/grpc",
|
|
))
|
|
httpLis := m.Match(cmux.Any())
|
|
```
|
|
|
|
- gRPC matched by `content-type: application/grpc` header
|
|
- HTTP matched by `Any()` (catch-all)
|
|
- Single port, single listener, zero extra config
|