Architecture et sécurité
Comment les composants de Watchflare s'articulent : les agents transmettent via gRPC/TLS 1.3 au Hub, qui stocke les métriques dans TimescaleDB et envoie des mises à jour en direct via SSE.
Watchflare est construit autour de quatre composants : les agents, le Hub, une base de séries temporelles, et un tableau de bord dans le navigateur connecté via Server-Sent Events.
┌──────────────────────────────────────────────────────┐
│ Monitored Hosts │
│ [ Agent ] [ Agent ] [ Agent ] │
└──────────┬───────────┬──────────────┬───────────────┘
│ │ │
│ gRPC / TLS 1.3 │
▼ ▼ ▼
┌──────────────────────────────────────────────────────┐
│ Hub (Go) │
│ │
│ gRPC server ──▶ HeartbeatCache │
│ HTTP server ──▶ TimescaleDB │
│ SSE broker ──▶ Browser │
└──────────────────────────────────────────────────────┘
Composants
Hub
Le Hub est un seul binaire Go qui embarque l’interface et expose deux ports :
:8080sert l’API HTTP, le tableau de bord web et le flux SSE:50051exécute le serveur gRPC qui reçoit les heartbeats, les métriques et l’inventaire des paquets des agents
Le Hub s’exécute aux côtés d’une instance TimescaleDB (PostgreSQL avec extensions time-series) pour le stockage persistant. Les deux sont déployés en tant que conteneurs Docker.
Agent
L’agent est un démon Go léger installé sur chaque hôte surveillé. Il ne communique qu’en sortie, sans ouvrir de ports entrants. Sous Linux, il s’exécute en tant qu’utilisateur système dédié (watchflare). Sous macOS, il est géré par Homebrew sous le compte de l’utilisateur courant.
L’agent exécute ces boucles indépendamment :
| Boucle | Intervalle | Ce qu’elle fait |
|---|---|---|
| Heartbeat | 5 s | Envoie un ping de présence avec les adresses IP actuelles |
| Métriques | 30 s | Collecte et envoie les métriques système |
| Inventaire des paquets | 60 s après le démarrage, puis quotidiennement à 03:00 | Analyse les paquets installés, envoie le delta |
| Inventaire des services | 60 s après le démarrage, puis toutes les 15 min | Répertorie les unités systemd (Linux avec systemd uniquement) |
| Santé des services | 30 s | Signale l’état en temps réel des services systemd (Linux avec systemd uniquement) |
Base de données
TimescaleDB stocke les métriques dans une hypertable automatiquement partitionnée par le temps. Les agrégats continus précalculent des tranches de 10 minutes, 15 minutes, 2 heures et 8 heures. Le Hub interroge ces agrégats plutôt que les lignes brutes pour les plages de temps plus longues.
Tableau de bord dans le navigateur
L’interface (SvelteKit) reçoit toutes les mises à jour en direct via une connexion SSE persistante vers le Hub. Le statut des hôtes, les métriques et les agrégats sont envoyés sous forme d’événements. La page n’interroge jamais le serveur.
Flux de données
Heartbeat et détection en ligne / hors ligne
Agent (every 5s) ──▶ Hub ──▶ HeartbeatCache (memory)
│
└──▶ SSE → browser (status: online)
StaleChecker (every 10s):
no heartbeat > 15s ──▶ mark offline in cache
└──▶ SSE → browser (status: offline)
SyncWorker (every 5min):
flush cache (status, last_seen, IPs) ──▶ database
À chaque heartbeat, le Hub met à jour le cache en mémoire et diffuse immédiatement un événement SSE vers le tableau de bord. Aucune écriture en base n’a lieu. Les identifiants sont vérifiés en une seule lecture. Le SyncWorker envoie le statut, les horodatages et les adresses IP vers la base toutes les 5 minutes. Lorsque le StaleChecker détecte un heartbeat manqué, il marque l’agent hors ligne dans le cache et diffuse l’événement hors ligne directement.
Collecte des métriques
Agent:
1. Collect metrics
2. Append to WAL (local file)
3. Send to Hub via gRPC
4. Clear WAL only if send succeeds
Hub:
→ INSERT into TimescaleDB
→ SSE metrics_update → browser
Si le Hub est injoignable, les métriques s’accumulent dans le Write-Ahead Log de l’agent. À la prochaine connexion réussie, tous les enregistrements en attente sont rejoués dans l’ordre avant l’envoi des nouvelles métriques.
Inventaire des paquets
Agent (60s after start, then daily at 03:00):
First run → full inventory → Hub upserts all packages
Next runs → delta only → Hub processes added/removed/updated
L’approche par delta maintient les charges utiles quotidiennes petites, quel que soit le nombre de paquets installés.
Services systemd (Linux)
Agent (systemd hosts only):
Inventory (60s after start, then every 15 min) → full unit catalog → Hub refreshes service list
Health (every 30s) → live unit state → SSE → browser
L’agent lit systemd via D-Bus en tant qu’utilisateur sans privilèges, sans jamais invoquer systemctl. La boucle de santé retire en moins de 30 secondes les services qui quittent l’ensemble suivi. Voir services systemd.
Enrôlement d’un agent
L’enrôlement est un amorçage unique qui établit la confiance entre un agent et le Hub :
1. Admin creates a host in the dashboard
→ Hub generates a registration token (wf_reg_...) valid for 24 hours
2. Token is pasted into the install command on the target host
→ Agent calls RegisterHost gRPC (TLS without cert verification, as the agent has no CA
cert yet, so it authenticates with the registration token)
→ Hub validates token, returns: agent_id, agent_key, CA certificate
3. Agent saves credentials + CA cert to disk
→ CA is pinned immediately, so the agent rejects any certificate not signed by this CA
→ All future gRPC calls use mutual auth (HMAC-SHA256 + pinned CA)
Modèle de sécurité
- TLS 1.3 sur toute la communication agent ↔ Hub
- HMAC-SHA256 signe chaque requête gRPC (
agent_id+ horodatage + payload). Hors d’une fenêtre de ±5 minutes, la requête est rejetée. - Épinglage de la CA. L’agent épingle le certificat CA du Hub à l’enrôlement. Il refusera tout certificat qui n’est pas signé par cette CA.
- Agent sans privilèges. Sous Linux, il s’exécute en tant qu’utilisateur système
watchflare, sans shell, sans répertoire home, et avec un accès en écriture uniquement à son propre répertoire de données. Sous macOS, il est géré par Homebrew sous le compte de l’utilisateur courant. - Jetons à usage unique. Les jetons d’enrôlement sont stockés sous forme d’empreintes SHA-256. La valeur en clair s’affiche une fois et n’est jamais conservée.
Remarque
Le Hub génère automatiquement sa propre CA TLS et son certificat serveur au premier démarrage. Vous pouvez fournir vos propres certificats en définissant TLS_MODE=custom. Voir certificats TLS.
Détection d’environnement
L’agent adapte ce qu’il collecte selon l’endroit où il s’exécute :
| Environnement | Omet |
|---|---|
| Conteneur d’application (Docker, Podman) | Disque, E/S disque, réseau, swap, température |
| Conteneur système (LXC) | Rien, surveillé comme un hôte complet |
| Machine virtuelle | Capteurs de température (pas d’accès au matériel physique) |
| Hôte physique | Rien, collecte complète |