← retour aux projetsmonitoring · devsecops

Bientôt

Système de monitoring agent/serveur en Go. Push-only, token par machine, docker-socket-proxy, corrélation CTI. Remplace Grafana+Prometheus sur petite infra.

TypeProjet personnel
Période2024 - en cours
StackGo, SQLite, HTMX, uPlot, Docker, Ansible, Ntfy

// Le problème

Sur une petite infra perso (un VPS + un Raspberry Pi), déployer Prometheus, Grafana, vmagent et node-exporter ça fait 4-5 containers juste pour du monitoring. C'est absurde. Il me fallait un truc léger qui surveille plusieurs machines sans bouffer la moitié des ressources, et qui soit pensé sécurité dès le départ.

// L'approche

Bientôt est un système de monitoring agent/serveur en Go. Un agent léger par machine et un serveur central. L'agent auto-détecte ce qui est installé (Docker, ZFS, CrowdSec, Traefik, NetBird…), collecte les métriques et les push vers le serveur. Le dashboard s'adapte dynamiquement aux modules détectés.

L'architecture est push-only : les agents n'exposent aucun port, ils poussent leurs données vers le serveur via le mesh NetBird. Le serveur écoute sur deux ports séparés : le dashboard derrière Traefik avec TLS et CrowdSec, les agents en direct sur le mesh. Si les agents passaient par Traefik, CrowdSec générerait des faux positifs sur leurs IPs et le module Traefik de Bientôt loggerait ses propres pushes.

Le tout dans deux images Alpine : l'agent fait environ 15MB, le serveur environ 30MB. SQLite en stockage avec downsampling automatique. Le nom est un clin d'œil à "maintenant", un projet open source français de monitoring qui partage la même philosophie.

// La sécurité

Chaque agent a un token unique. Le serveur associe token et machine ; un push avec le token du VPS pour les données du Pi est rejeté. Les pushes sont signés en HMAC-SHA256 avec un nonce UUID et un contrôle de timestamp pour bloquer le replay.

L'agent n'accède jamais au Docker socket directement. Un docker-socket-proxy filtre les appels autorisés, uniquement du GET en lecture seule. Les containers tournent en user non-root avec no-new-privileges. Le build inclut go mod verify, le déploiement Ansible épingle un SHA de commit avec vérification post-clone, et un dependabot surveille les CVE dans les dépendances.

Le command channel (exécution de commandes à distance sur les agents) existe mais est désactivé par défaut. Chaque agent contrôle localement ce qu'il autorise (read, manage ou danger), indépendamment du serveur.

// Choix techniques

Go plutôt que Python : l'agent compile en binaire statique CGO_ENABLED=0, cross-platform amd64 et arm64 depuis le même Dockerfile multi-target. Pas de runtime, pas de dépendances, empreinte mémoire minimale.

SQLite plutôt qu'une TSDB : pour deux machines c'est largement suffisant, avec du downsampling automatique pour le stockage long terme.

Dual-listen plutôt que tout derrière le reverse proxy : pour isoler le trafic agents du trafic dashboard et éviter la pollution des logs et des détections CrowdSec.

// Ce qui arrive

Intégration CTI avec veille-sécu, mon moteur de veille CVE. L'agent remonte un inventaire logiciel (noms et versions des services déployés), le serveur le corrèle avec les CVE connues pour afficher si un service est vulnérable. Même logique avec l'enrichissement des IPs attaquantes : GeoIP, blocklists, réputation via AbuseIPDB.

// Ce que j'en retiens

C'est le projet où j'ai le plus réfléchi au modèle de menace avant d'écrire du code. "Et si l'agent est compromis ? Et si le serveur est compromis ? Et si quelqu'un intercepte les pushes ?" Chaque décision d'architecture (push-only, token par machine, docker-socket-proxy, command channel opt-in) est une réponse à une menace spécifique. C'est ça, penser sécurité dès le design.

GoSQLiteHTMXuPlotDockerAnsibleNtfy