Manuel d'utilisation de RoamSwitch Server Edition
Installation officielle, déploiement et référence opérationnelle pour Cloud VPS (AWS, GCP, Azure, Linode, DigitalOcean), les centres de données nus et les hôtes de conteneurs.
1. Présentation et exigences
RoamSwitch Server Edition est une suite autonome de surveillance de la défense et de l'intégrité sans tête (zéro dépendance graphique) conçue pour les serveurs Linux exposés à l'Internet public.
Contrairement à l'édition client qui change dynamiquement de profil en fonction de l'état du Wi-Fi, l'édition serveur applique Inbound Default Drop, la surveillance de l'intégrité des fichiers du chemin critique (FIM), l'atténuation préventive LPE du noyau (Frag Gap), la détection des menaces d'exécution eBPF, la prévention du verrouillage SSH et les alertes d'urgence multicanaux automatisées (Telegram / LINE / Webhook) .
cve_kernel_map_updates_enabled, activée par défaut). Il s’agit des données CVE du noyau, des règles web et, sur les serveurs Ubuntu, des données CVE des paquets Ubuntu utilisées par la vérification CVE des paquets du système. roamswitch-updater reçoit, par HTTPS GET depuis lafine.net, des données signées Ed25519 (le manifeste signé est vérifié chaque jour, les données CVE elles-mêmes environ tous les 30 jours, les règles web seulement si le manifeste a une version plus récente), sans chaîne de requête ni cookie, avec un User-Agent: RoamSwitch-Updater fixe pour seul en-tête qui nomme le logiciel, et n’envoie rien sur cet hôte. Elle se désactive avec roamswitch server config set cve_kernel_map_updates_enabled false (ou l’assistant de configuration, ou la TUI du serveur), et l’audit continue alors de fonctionner avec la base de référence intégrée, mais la vérification CVE des paquets du système sur un serveur Ubuntu indique « aucune donnée CVE locale ». Tout autre trafic qui quitte l’hôte se limite aux éléments suivants, que l’opérateur a explicitement activés : notifications (Telegram / LINE / webhook), vérification des signatures npm (npm_audit_signatures_enabled, uniquement lorsque la commande est exécutée) et transfert d’événements (forward_enabled, désactivé par défaut ; §16). Le transfert d’événements ne va que vers les destinations que vous nommez vous-même (un SIEM, syslog, un webhook) ; le syslog TLS est envoyé via openssl du système et le webhook structuré via un sous-processus curl. De plus, l'appairage de Sensor (sensor_pairing_enabled, désactivé par défaut) et l'intégration LLM de l'outil distinct fourni accessscope (désactivée par défaut ; en ligne de commande, seulement lorsque --llm est indiqué) ne se connectent à l'extérieur que si l'opérateur les active. La liste des exceptions figure dans la section Zero Telemetry du livre blanc de sécurité de l'édition Server.Configuration système requise
- Distributions prises en charge : Ubuntu 22.04 / 24.04 LTS, Debian 12+, AlmaLinux / Rocky Linux / RHEL 9+, Fedora 39+, openSUSE Leap 15.5+, Raspberry Pi OS (64 bits)
- Architectures :
x86_64(amd64) ouaarch64(arm64) - Kernel : Linux 5.10+ (
nftables,cgroups v2, eBPF BTF recommandé) - Footprint : 20 à 30 Mo de mémoire résidente, <0,1 % de processeur pendant les charges de travail inactives/normales
2. Procédures d'installation
L'utilisation des référentiels officiels signés garantit une résolution automatique des dépendances et des mises à jour transparentes via votre gestionnaire de packages système standard.
2.1 APT (système d'exploitation Ubuntu / Debian / Raspberry Pi)
# 1. Enregistrer la clé de signature du dépôt
curl -fsSL https://lafine.net/apt/roamswitch-archive-keyring.asc \
| sudo gpg --dearmor -o /usr/share/keyrings/roamswitch-archive-keyring.gpg
# 2. Ajouter le dépôt
echo "deb [arch=amd64,arm64 signed-by=/usr/share/keyrings/roamswitch-archive-keyring.gpg] https://lafine.net/apt stable main" \
| sudo tee /etc/apt/sources.list.d/roamswitch.list
# 3. Installer
sudo apt update && sudo apt install roamswitch-server
2.2 DNF/RPM (Fedora/RHEL/AlmaLinux/Rocky Linux)
# 1. Importer la clé GPG
sudo rpm --import https://lafine.net/rpm/RPM-GPG-KEY-roamswitch
# 2. Ajouter le fichier de configuration du dépôt
sudo curl -fsSL -o /etc/yum.repos.d/roamswitch.repo https://lafine.net/rpm/fedora/roamswitch.repo
# 3. Installer
sudo dnf install roamswitch-server
2.3 openSUSE (zypper)
sudo rpm --import https://lafine.net/rpm/RPM-GPG-KEY-roamswitch
sudo zypper addrepo https://lafine.net/rpm/opensuse/roamswitch.repo
sudo zypper refresh && sudo zypper install roamswitch-server
roamswitch) et Server (roamswitch-server) déclarent des conflits de packages réciproques. Sélectionnez toujours roamswitch-server sur les environnements de serveur sans tête.3. Configuration initiale et vérification du service
3.1 État des services
Après l'installation, roamswitch-server.service démarre immédiatement et est activé au démarrage du système.
sudo systemctl status roamswitch-server.service
3.2 Assistant de configuration interactif
Exécutez l'assistant de configuration interactif ci-dessous pour configurer les ports, les IP source de maintenance, les canaux de notification et l'action de confinement de façon interactive (appuyez sur Entrée pour accepter chaque valeur par défaut).
sudo roamswitch server setup
- Ports : saisissez les ports de maintenance SSH (par défaut
22) et les ports de service publics (par défaut80,443), séparés par des virgules. - IP sources de maintenance : IP ou CIDR d'un bastion SSH ou de la supervision (p. ex.
203.0.113.50/32). L'assistant exige une réponse et n'accepte pas une saisie vide. Pour autoriser SSH depuis n'importe quelle source, saisissezANYWHERE(le chemin SSH d'administration reste alors ouvert au monde entier, y compris pendant l'isolement). - Canaux de notification : activez le bot Telegram, l'API Messaging LINE et/ou un webhook générique (Slack / Discord / Teams).
- Réaction à un événement eBPF critique : choisissez
isolate(isoler l'hôte),freeze(geler le processus) oualert_only(notification uniquement). Après l'enregistrement, il vous est proposé d'envoyer une notification de test et de redémarrer le service. - Mise à jour automatique des données CVE (
ypar défaut) : choisissez si la base de CVE du noyau utilisée par l’audit d’isolation des conteneurs, les règles web et, sur les serveurs Ubuntu, les données CVE des paquets Ubuntu utilisées par la vérification CVE des paquets du système sont récupérées anonymement depuis lafine.net (manifeste signé vérifié chaque jour, données CVE elles-mêmes environ tous les 30 jours et règles web seulement si le manifeste a une version plus récente ; HTTPS GET uniquement, sans chaîne de requête ni cookie, avec unUser-Agent: RoamSwitch-Updaterfixe pour seul en-tête qui nomme le logiciel, signature Ed25519 vérifiée). Rien sur cet hôte n’est envoyé. C’est la seule communication externe activée par défaut dans l’édition Server ; répondrenl’arrête (l’audit fonctionne alors avec la base de référence intégrée, mais la vérification CVE des paquets du système sur un serveur Ubuntu indique « aucune donnée CVE locale »). Si elle est déjà désactivée dans unserver.confexistant, la réponse par défaut resten. - Paramètres du File Scan Guard : choisissez d'activer ou non l'analyse antivirus pour les relais de messagerie, les dossiers partagés et les destinations de téléversement (§13), et définissez les répertoires cibles. Facultatif, désactivé par défaut.
- Paramètres du Resource Guard : activez la garde d'épuisement des ressources qui détecte une croissance RSS soutenue (fuite mémoire/DoS) ou des boucles de plantage dans les services exposés au réseau.
- Présentation des protections principales toujours actives : affiche les défenses principales qui fonctionnent en permanence indépendamment de l'assistant — rejet entrant par défaut, FIM, intégration eBPF, etc. (aucune saisie requise).
- Paramètres de délégation à un agent d'investigation (investigation) : choisissez de déléguer ou non automatiquement l'investigation initiale — pour les événements eBPF critiques, ou les détections d'altération de FIM Critical-Path/fichiers de verrouillage de dépendances, lorsqu'elles n'ont donné lieu qu'à une notification — à une CLI d'agent IA externe (Claude Code / agy / Codex CLI / OpenCode, ou une commande personnalisée) (§10.1). Désactivé par défaut.
-100 (ex. -1001234567890). Vérifiez la valeur correcte dans le champ "chat":{"id":...} de la réponse de curl -s "https://api.telegram.org/bot<token>/getUpdates".3.3 Audit de sécurité du serveur en 34 éléments
sudo roamswitch status --server
Effectue un audit instantané de 34 vérifications des règles de pare-feu, de l'atténuation Frag Gap, des restrictions Yama LSM, des autorisations et de l'exposition du port Docker, produisant un score et une note de sécurité de 0 à 100 (S à C).
Chaque élément de contrôle est désormais également associé, à des fins de reporting de conformité, à une fonction/catégorie NIST CSF 2.0 (toujours présente lorsque applicable) et, uniquement lorsqu'une correspondance fiable existe, à un numéro de contrôle CIS Controls v8.
4. Règles de pare-feu et de port
Le fichier de configuration /etc/roamswitch/server.conf est soumis à des permissions 0600 obligatoires (lecture/écriture root uniquement) pour protéger les informations sensibles. Le format est un clé=valeur à plat ; les en-têtes de section comme [network] sont ignorés.
# --- Pare-feu ---
ssh_ports=22 # Port de gestion SSH (conservé même lors d'une isolation d'urgence)
allowed_ports=80,443 # Ports de service publics
whitelist_ips=203.0.113.10/32 # IP/CIDR source de maintenance (vide = tout autorisé, anciennement admin_source_ips)
protect_docker_ports=true # Protection DOCKER-USER (empêche les conteneurs de contourner le pare-feu)
preserve_ssh_on_isolation=true # Préserve la voie de gestion SSH même lors d'une isolation d'urgence (false = coupure totale)
# --- Garde d'exécution eBPF ---
action_on_critical=isolate # isolate | freeze (SIGSTOP+coupure réseau) | alert_only
ebpf_socket_path=/run/roamswitch/events.sock
# --- Blocage Egress/C2 et sinkhole DNS ---
egress_ip_blocklist_enabled=true # Par défaut true. Le seed fourni avec le paquet ne contient que les trois serveurs d'attaque publiés par JPCERT/CC ; rien d'autre n'est bloqué tant qu'aucun flux n'est installé
metadata_watch_enabled=true # Par défaut true. Notifie lorsqu'un programme non root/conteneur contacte les métadonnées cloud (journal seulement, sans blocage ; détecte la SSRF)
metadata_watch_allow_users= # Comptes qui utilisent légitimement le service de métadonnées (noms ou identifiants numériques, séparés par des virgules ; root est toujours exempté)
dns_sinkhole_enabled=false # Par défaut false (pour ne pas casser le DNS interne/les configurations split-horizon)
dns_sinkhole_provider=quad9 # quad9 | cloudflare | adguard | cleanbrowsing
# --- Données CVE d'isolation des conteneurs (activées par défaut) ---
cve_kernel_map_updates_enabled=true # Par défaut true. La seule communication externe activée par défaut (données CVE du noyau signées, règles web et, sur les serveurs Ubuntu, données CVE des paquets Ubuntu ; manifeste chaque jour, données CVE environ tous les 30 jours ; anonyme, réception seule, signature vérifiée). false l'arrête
# --- Notifications ---
telegram_enabled=false
telegram_bot_token=
telegram_chat_id=
line_enabled=false
webhook_enabled=false
webhook_url=
webhook_block_private_addresses=false # opt-in SSRF guard
webhook_allow_addresses=
# --- Système ---
language=ja
fim_check_interval_secs=300 # Anciennement nommé scan_interval
isolation_hard_cap_secs=3600 # Secondes avant qu’une isolation à haute confiance passe en mode DEGRADED (0 = maintenir jusqu’à la levée)
Après une modification directe du fichier, redémarrez le service pour appliquer les changements (roamswitch-server ne prend pas en charge le rechargement) :
sudo roamswitch server restart
4.1 Politique par niveau de gravité (guard.yaml, optionnel)
Si action_on_critical seul n'offre pas assez de granularité, créez /etc/roamswitch/guard.yaml (un modèle est fourni dans /etc/roamswitch/guard.yaml.example). En son absence, une politique équivalente est automatiquement synthétisée à partir de action_on_critical dans server.conf, sans impact sur les déploiements existants.
policies:
on_warning:
action: log_and_notify
on_critical:
server_action: isolate_process
kill_process: true
fallback_to_host_isolation_after_retries: 3 # Bascule automatiquement vers l'isolation de l'hôte si le même processus se reproduit
on_emergency:
action: isolate_host_all
kill_process: true
server_safeguards:
maintenance_ssh_ports: [22]
safety_timer_secs: 300 # Secondes avant la restauration automatique d’une isolation à faible confiance (0 la désactive). Non appliqué aux isolations à haute confiance (voir ci-dessous)
Levée automatique d’une isolation (selon la confiance) : une levée sur simple minuterie fixe permet à un attaquant patient d’attendre tout simplement, c’est pourquoi le déclencheur de chaque isolation est classé selon son niveau de confiance. (1) Faible confiance (eBPF Error / Warning et inférieur, anomalies de ports génériques) : restauration complète après une courte minuterie (safety_timer_secs, 300 s par défaut). (2) Haute confiance (falsification d’un canary, réécriture massive de type ransomware, eBPF Critical / Emergency / Alert, escalade répétée de la même règle) : jamais restaurée silencieusement. Après la courte minuterie, la cause continue d’être revérifiée, et l’isolation n’est levée, avec une notification, que lorsque la disparition de la cause est vérifiée. Si cela ne peut être confirmé, que personne n’a accusé réception et que le plafond absolu est atteint (isolation_hard_cap_secs dans server.conf, 3600 s par défaut, 0 = aucun plafond), elle passe en mode DEGRADED. (3) Le mode DEGRADED continue de bloquer les nouveaux flux autres que les chemins d’administration (les ports SSH de maintenance et les IP de la liste blanche) et ne s’ouvre jamais sur minuterie. Il n’est levé que par une revérification confirmant la disparition de la cause, un accusé de réception explicite (un accusé de réception en mode DEGRADED signifie levée) ou sudo roamswitch emergency-restore. Dans toute isolation, les connexions établies autres que les chemins d’administration (un canal C2 ou un reverse shell que l’attaquant a déjà ouvert) sont coupées. Chaque transition est consignée dans la chronologie des incidents et notifiée en 10 langues.
sudo roamswitch server ack
roamswitch server ack accuse réception d’une isolation FULL tout en la maintenant stricte (l’opérateur en a pris la responsabilité : pas de passage en DEGRADED ni de levée automatique) et lève une isolation DEGRADED.
4.2 Blocage Egress / C2 et sinkhole DNS
Avec egress_ip_blocklist_enabled=true (par défaut), les connexions sortantes vers des IP malveillantes connues sont bloquées via nftables. Le flux est /var/lib/roamswitch/threatfeed/malicious_ips.txt (géré par le mécanisme de mise à jour) s'il existe, sinon le seed fourni avec le paquet (/usr/share/roamswitch/threatfeed/) ; l'un est utilisé à la place de l'autre, ils ne sont pas fusionnés. Le seed ne contient que les trois adresses de serveurs d'attaque publiées par JPCERT/CC dans son rapport du 15/10/2026 sur les attaques contre les services web et les API (210.149.87.120, 118.26.36.16, 69.10.51.162). Les adresses de serveurs loués peuvent être réattribuées à d'autres ; si une destination légitime cesse de fonctionner, vérifiez la ligne correspondante de ce fichier.
Activer dns_sinkhole_enabled=true force la résolution via un résolveur DNS filtrant (Quad9 / Cloudflare / AdGuard / CleanBrowsing), bloquant la résolution de domaines connus comme malveillants. La valeur par défaut est false, car cela peut casser le DNS interne ou les configurations split-horizon.
Si metadata_watch_enabled est activé (par défaut), la table nftables inet roamswitch_metadata_watch n'écrit une ligne dans le journal du noyau que lorsqu'un programme non root ou un conteneur ouvre une nouvelle connexion vers une adresse de métadonnées cloud (169.254.169.254, 169.254.170.2, 100.100.100.200, fd00:ec2::254) ; le démon serveur notifie une fois par jour et par compte (par adresse source pour un conteneur). Il se contente de journaliser et de notifier, sans jamais bloquer. Lorsqu'un attaquant transmet à l'application l'URL de son propre serveur, qui redirige (302) vers une adresse interne, le journal d'accès ne montre que l'URL externe ; seul ce trafic sortant révèle le second saut. Une application qui utilise légitimement son rôle cloud est aussi signalée : ajoutez son compte à metadata_watch_allow_users pour l'exclure (un conteneur ne peut pas l'être).
4.3 Garde de détection de scan de ports entrants
Détecte les IP source qui se sont connectées à de nombreux ports distincts en peu de temps, en corrélant les règles de journalisation nftables avec journald (activé par défaut). Les sources de scan à haute confiance peuvent être automatiquement bloquées pendant une durée définie. Utilisé avec RoamSwitch Sensor (une fonction différente du §10.1 — les sondes d'audit complet des ports d'un Sensor appairé sont exclues pour atténuer les faux positifs), l'IP du Sensor lui-même est automatiquement exclue.
# --- Détection de scan de ports entrants (activée par défaut) ---
port_scan_detect_enabled=true # false pour désactiver
port_scan_detect_min_distinct_ports=15 # Jugé comme un scan lorsque les connexions atteignent ce nombre de ports distincts
port_scan_detect_window_secs=300 # Fenêtre d'agrégation pour la détection (secondes)
port_scan_block_enabled=true # Bloque automatiquement l'IP source du scan détecté
port_scan_block_duration_secs=600 # Durée du blocage automatique (secondes)
Vous pouvez consulter l'historique de détection avec la commande roamswitch port-scan.
4.4 Garde de détection de tunneling DNS
N'inspecte que le trafic DNS sortant propre à cet hôte (port UDP/TCP 53) via un consommateur NFQUEUE dédié. Une requête est considérée comme de forme suspecte si la longueur de son label dépasse 40 octets ET si son entropie de Shannon dépasse 3,8, ou si son qtype est TXT/NULL ; une alerte est déclenchée dès que 10 requêtes de ce type ou plus surviennent au cours des 60 dernières secondes (un délai de récupération de 300 secondes évite les alertes répétées pour la même condition). L'objectif est de détecter les motifs de requêtes caractéristiques des outils de tunneling/exfiltration DNS tels qu'iodine et dnscat2. La règle nftables sous-jacente porte le même indicateur bypass que les autres gardes DNS de ce démon, de sorte que la résolution de noms DNS n'est jamais perturbée, même si cette garde est arrêtée ou ne répond pas. Il s'agit d'une fonctionnalité de notification uniquement — elle ne bloque jamais automatiquement. Comme pour tout autre paramètre, une modification de dns_tunnel_detect_enabled ne prend effet qu'après un redémarrage du service.
# --- Détection de tunneling DNS (activée par défaut) ---
dns_tunnel_detect_enabled=true # false pour désactiver
4.5 Garde contre la force brute SSH
La garde lit les échecs de connexion de sshd à l'instant où ils sont écrits dans le journal et les compte par adresse source (activée par défaut). Pour une source qui atteint le nombre d'échecs configuré (par défaut 6 en 600 secondes), la table nftables inet roamswitch_sshguard rejette uniquement les nouvelles connexions vers les ports SSH. Le premier bannissement dure 1 heure, est multiplié par 4 à chaque récidive de la même source et plafonne à 7 jours. Au moment du bannissement, les connexions que cette source avait déjà ouvertes vers SSH sont aussi coupées (les entrées conntrack sont supprimées et une règle rejette les paquets du sens réponse). Seule une source sans session authentifiée, sans connexion par clé publique enregistrée et sans exemption est bannie, et cela est revérifié juste avant la coupure : une session authentifiée et une source exemptée ne sont donc jamais coupées. Rien n'est envoyé vers l'extérieur ; seules des commandes comme journalctl, nft et loginctl sont exécutées localement.
Le journal est suivi avec journalctl -f. journald enregistre quel processus a écrit chaque ligne ; les lignes écrites par autre chose que sshd sont donc ignorées. Sans journald, la garde suit /var/log/auth.log ou /var/log/secure, mais tout utilisateur local autorisé à utiliser syslog peut y falsifier des lignes et faire bannir un tiers ; lorsque journald est disponible, laissez ssh_guard_log_source à sa valeur par défaut auto. Les échecs comptés sont : mot de passe incorrect, utilisateur inconnu, déconnexion avant authentification après avoir indiqué un nom d'utilisateur, dépassement du nombre de tentatives et échec d'authentification PAM. Un échec de clé publique (Failed publickey) n'est pas compté, car un client légitime qui possède plusieurs clés en produit à chaque connexion. L'adresse source est lue à la fin de la ligne, dans from <IP> port <N>. Un attaquant peut mettre n'importe quel texte dans le nom d'utilisateur, mais une fausse adresse source écrite là ne fait pas bannir un tiers. L'IPv6 est comptée par /64 et le bannissement porte aussi sur le /64 (sur l'adresse source seule si ce /64 contient une adresse qui doit rester joignable, comme la passerelle).
Ne sont jamais bannis : la passerelle, les résolveurs DNS, ce serveur lui-même, la boucle locale, whitelist_ips, ssh_guard_allow, la source d'une session SSH ouverte et déjà authentifiée, toute adresse qui s'est connectée par clé publique au cours des 30 derniers jours (ssh_guard_trust_key_days ; une connexion réussie par mot de passe ne compte pas) et un Sensor appairé. Si une de ces sources accumule des échecs, la garde se contente de l'enregistrer. Les adresses privées ne sont pas exemptées, car une machine compromise à l'intérieur du réseau peut aussi être à l'origine d'une attaque par force brute. Une source qui garde seulement une connexion ouverte avant l'authentification n'est pas exemptée non plus.
Lorsque fail2ban (avec une jail sshd activée) ou CrowdSec (avec un firewall bouncer en marche) protège déjà sshd, la garde lui laisse le bannissement afin de ne pas bannir deux fois la même adresse, et se contente de détecter et de notifier (ssh_guard_yield_to_fail2ban, true par défaut). Avec ssh_guard_block_enabled=false, elle ne fait aussi que détecter et notifier. Elle notifie lors d'un bannissement (en mode détection seule, lorsque le seuil est atteint) et lorsqu'une connexion réussit depuis une source qui avait accumulé des échecs (critique : une attaque par force brute a peut-être abouti ; la session n'est pas coupée). Elle ne notifie pas chaque échec, et les sources au-delà de 10 par heure sont regroupées en une seule notification.
La liste des bannissements s'affiche avec roamswitch server bans (option --json ; la liste n'est lisible que par root, donc avec sudo) et se lève avec sudo roamswitch server unban <IP | /64 IPv6 | --all> ; lever un bannissement efface aussi le compteur d'échecs de cette source. Les bannissements sont restaurés avec leur durée restante après un redémarrage du serveur. roamswitch emergency-restore ne lève pas les bannissements SSH (rétablir le réseau n'est pas une raison de laisser revenir celui qui devinait des mots de passe) ; le menu de récupération (roamswitch recover) et la désinstallation suppriment toute la table. L'outil MCP get_ssh_guard_incidents est en lecture seule et il n'existe aucun outil pour lever un bannissement. Dans la TUI Server, la section « Force brute SSH » de l'écran des incidents liste les bannissements et permet de les lever (lancée en root ; §17).
roamswitch server bans
sudo roamswitch server unban 203.0.113.9
sudo roamswitch server unban --all
Il y a 10 réglages, tous préfixés par ssh_guard_ (§18.1). On en modifie un par exemple avec sudo roamswitch server config set ssh_guard_max_failures 10 et on l'applique avec sudo roamswitch server restart. Mettez ssh_guard_enabled=false pour arrêter complètement la garde, ou ssh_guard_block_enabled=false pour qu'elle se contente de détecter et de notifier. L'élément « Protection SSH contre la force brute » du diagnostic en 34 points est lui aussi réussi tant que cette garde fonctionne et bannit.
Limites : les tentatives qui ne font échouer que l'authentification par clé publique ne sont pas comptées. Une attaque par force brute répartie sur de nombreuses adresses sources est comptée source par source ; elle n'est donc pas arrêtée tant qu'une source n'a pas atteint le seuil. Le remède de fond est de désactiver l'authentification par mot de passe et de n'autoriser que les clés publiques.
5. Sécurité intégrée de prévention du verrouillage SSH
Un verrouillage accidentel dû à une mauvaise configuration du pare-feu est un désastre opérationnel intolérable. RoamSwitch Server Edition intègre des protections à plusieurs niveaux :
- ESTABLISHED / RELATED Inconditional Pass : les sessions actives ne sont jamais abandonnées lors du rechargement des règles.
- SSH maintenu pendant l’isolation Air-Gap : même lorsqu’une anomalie déclenche une isolation d’urgence,
preserve_ssh_on_isolation = truene conserve, pour le trafic nouveau comme établi, que les chemins d’administration — les ports SSH de maintenance et les IP sources d’administration (whitelist_ips) — afin que vous puissiez enquêter et rétablir la situation sans vous déplacer sur site. Toutes les autres connexions établies (C2, exfiltration de données ou reverse shell que l’attaquant a déjà ouvert) sont coupées. Si aucune source d'administration n'est indiquée (whitelist_ipset les adresses autorisées de guard.yaml sont vides), les ports SSH de maintenance continuent d'accepter de nouvelles connexions de toute source pendant l'isolement, et le serveur émet un avertissement au démarrage. Avecpreserve_ssh_on_isolation=false, l'isolement coupe aussi le SSH. L'édition serveur jusqu'à la 1.10.4 présentait un défaut. Les règles d'isolement abandonnaient les réponses SSH, de sorte que le SSH de l'opérateur ne fonctionnait pas pendant l'isolement. Il est corrigé dans la 1.10.5. - Atomic nftables Chargement avec Rollback : les erreurs de syntaxe des règles déclenchent instantanément une restauration sans temps d'arrêt vers l'ensemble de règles vérifié précédent.
6. Protection des conteneurs (Docker / Podman)
Le comportement par défaut de Docker crée des règles iptables personnalisées qui contournent les pare-feu hôtes standard, exposant les ports de conteneur (par exemple -p 8080:8080) directement à Internet.
Avec protect_docker_ports=true (par défaut), RoamSwitch s’adapte au backend de pare-feu de Docker afin que le trafic vers les conteneurs soit lui aussi inaccessible de l’extérieur, sauf s’il vise un port listé dans ssh_ports ou allowed_ports. Avec le backend iptables / iptables-nft, il insère une règle d’inspection en tête de la chaîne DOCKER-USER (pour IPv4, et aussi via ip6tables lorsque l’IPv6 de Docker est activé). Avec le backend nftables natif de Docker (Docker 29 et ultérieur, où DOCKER-USER n’existe pas), il crée sa propre table inet roamswitch_docker_guard sur le hook forward, avant les chaînes de Docker (une table inet couvre à la fois IPv4 et IPv6). La décision se fonde sur le port de destination d’origine avant DNAT (ctorigdstport) et ne s’applique qu’au trafic arrivant sur l’interface externe : le trafic sortant des conteneurs et celui entre conteneurs ne sont donc pas touchés. Cela évite l’exposition accidentelle, par exemple, d’un conteneur de base de données de développement.
La protection est idempotente et se répare d’elle-même chaque minute : si dockerd démarre après RoamSwitch, si un redémarrage ou un rechargement de Docker réécrit les règles, ou après un nft flush manuel ou la perte de la table nftables, elle est réappliquée, tandis qu’une protection déjà à jour n’est pas modifiée.
Une protection en temps réel qui surveille docker events détecte aussi les conteneurs démarrés avec --privileged ou avec /var/run/docker.sock monté (risque d’évasion de conteneur) juste après leur démarrage et vous en informe. En outre, la protection d’exécution dans les conteneurs (container_exec_guard_enabled, activée par défaut) inspecte avec YARA les binaires exécutés dans les conteneurs (une évasion qui supprime le fichier après son exécution est tout de même inspectée, car le contenu est lu depuis le descripteur de fichier déjà ouvert). Elle marque aussi, au démarrage, les conteneurs déjà en cours d’exécution et suit automatiquement les nouveaux conteneurs. Les deux fonctionnent en notification seule et ne bloquent jamais automatiquement. Elles fonctionnent aussi avec Docker 29 (depuis la 1.11.1). Quand l’abonnement aux événements continue d’échouer, l’intervalle de reconnexion passe de 5 secondes à 5 minutes au plus.
7. Surveillance de l'intégrité des fichiers du chemin critique (FIM)
Plus de 150 fichiers critiques — binaires critiques comme /bin/login, /usr/bin/sudo et /usr/sbin/sshd, configuration d’authentification comme /etc/shadow et /etc/sudoers, et unités systemd — sont surveillés par SHA-256.
Le périmètre ne se limite pas à des fichiers individuels. Dans les répertoires critiques (/etc/pam.d, /etc/sudoers.d, /etc/ssh/sshd_config.d, /etc/cron.*, /etc/systemd/system, /etc/ld.so.conf.d, /etc/profile.d et /root/.ssh (sauf known_hosts)), l’apparition d’un nouveau fichier est également détectée, et les authorized_keys de chaque compte pouvant se connecter, /etc/ld.so.preload (il n’existe normalement pas ; son apparition est un signe de rootkit local) et les binaires propres de RoamSwitch sont aussi couverts. Les unités temporaires que génère snapd (snap-*.mount, etc.) sont exclues. La détection de nouveaux fichiers ne fonctionne que par rapport à une base de référence incluant ce périmètre : exécutez donc sudo roamswitch fim update une fois après la mise à niveau. Les fichiers que fim verify ne peut pas lire lorsqu’il est exécuté sans root sont signalés comme « ignorés, illisibles » et non comme une falsification.
7.1 Vérification manuelle du hachage
sudo roamswitch fim verify
7.2 Détection événementielle (instantanée)
Les fichiers surveillés sont individuellement observés via fanotify (FAN_CLASS_NOTIF, événements de fin d'écriture), de sorte qu'une altération est re-hachée et détectée à l'instant même où elle se produit, sans attendre le prochain scan périodique. Le scan périodique (par défaut fim_check_interval_secs=300 secondes) reste en place comme filet de sécurité pour les événements manqués. Les modifications qui placent un nouveau fichier sous le même nom (install, sed -i et similaires) sont aussi détectées, et la notification indique le processus à l'origine du changement et sa connexion SSH (§7.5).
7.3 Synchronisation de base automatique sur les mises à jour du système d'exploitation
Sur Debian/Ubuntu, l'installation d'un paquet configure automatiquement le hook DPkg::Post-Invoke dans /etc/apt/apt.conf.d/99roamswitch-fim. Sur Fedora/RHEL/Rocky/AlmaLinux/openSUSE, une unité systemd.path (roamswitch-fim-update.path) surveillant /var/lib/rpm joue le même rôle.
Sur Debian/Ubuntu, /etc/apt/apt.conf.d/99roamswitch-fim attache un hook DPkg::Post-Invoke. Les mises à jour légitimes des packages via sudo apt upgrade actualisent automatiquement la base de référence FIM, éliminant ainsi les fausses alertes positives.
sudo roamswitch fim update
Lorsque le démon démarre pour la première fois et construit la baseline, si un gestionnaire de paquets (apt/dpkg, dnf/rpm, zypper ou pacman) est en cours de travail, il attend jusqu'à 120 secondes qu'il termine avant de la construire. Même si vous l'installez dans le même apt install qu'Apache ou autre, les fichiers temporaires sur lesquels dpkg travaille (comme *.dpkg-new) n'entrent plus dans la baseline et ne ressemblent plus à une falsification lors de la vérification suivante (à partir de la 1.11.18). Si le gestionnaire est toujours occupé après 120 secondes, un avertissement est consigné et la baseline est construite quand même.
7.4 Honeytokens (leurres d'identifiants)
Au démarrage, en tirant parti de son exécution en tant que root, le démon dépose de façon idempotente trois fichiers d'identifiants leurres sous /root : .aws/credentials, .ssh/id_rsa et .docker/config.json (collectivement, des honeytokens). Il n'écrase jamais un fichier réel déjà présent à l'un de ces emplacements. Un processus de surveillance en arrière-plan utilise inotify pour détecter tout accès en lecture à ces fichiers et le considère comme une reconnaissance d'identifiants post-compromission (MITRE ATT&CK T1552 : Unsecured Credentials), envoyant immédiatement une notification de sévérité Critical et l'enregistrant dans la chronologie des incidents. La fonction est activée par défaut et se règle avec les clés honeytokens_enabled (false arrête le placement et la surveillance ; les leurres déjà posés restent) et honeytokens_home (emplacement des leurres ; par défaut /root). Les paquets jusqu'à la 1.10.4 ne contenaient pas roamswitch-honeytokens, nécessaire à cette fonction, qui ne s'exécutait donc pas sur les installations depuis les paquets. Il est inclus depuis la 1.10.5, et le problème du bac à sable systemd qui bloquait les écritures dans /root sur l'édition serveur a été corrigé dans la 1.10.10. Depuis la 1.11.1, chaque commande docker que RoamSwitch exécute lui-même est lancée avec un répertoire privé vide (/run/roamswitch/docker-config en root) comme DOCKER_CONFIG ; elle ne déclenche donc pas le leurre .docker/config.json (auparavant, la surveillance du démon et roamswitch status --server pouvaient lire le leurre et lever une fausse détection). Une lecture par tout autre programme est toujours détectée comme avant.
En cas d'accès réel à l'un des honeytokens, anticipant que l'attaquant continuera à fouiller, RoamSwitch déploie jusqu'à deux leurres supplémentaires thématiquement liés par déclencheur (par exemple, atteindre .aws/credentials dépose aussi .aws/config ; atteindre .ssh/id_rsa dépose .ssh/config ; atteindre .docker/config.json dépose .kube/config), avec un maximum de six au total tous déclencheurs confondus. Si vous constatez une accumulation de ces fichiers inconnus sous /root lors d'une enquête sur un incident, il s'agit d'un comportement attendu.
7.5 Chemin d'intrusion (qui a fait la modification, et par quelle connexion SSH)
Les notifications d'une modification de fichier (FIM des chemins critiques et FIM des fichiers de verrouillage) indiquent désormais le processus à l'origine de la modification (compte, exécutable, commande) et la connexion SSH à laquelle il appartient (IP et port source, heure de connexion, méthode d'authentification et empreinte de la clé publique). C'est activé par défaut (fim_intrusion_context_enabled). Dès qu'un événement est lu, le démon prend un instantané de /proc/<pid> du processus écrivain (exécutable, utilisateur, loginuid, sessionid, cgroup, chaîne des parents), car un processus comme tee ou sed a disparu une milliseconde plus tard. Un processus déjà terminé est complété par l'enregistreur d'exécutions (s'il est activé). Le rattachement à une connexion utilise d'abord la table de sessions de la garde SSH, sinon les lignes Accepted de logind et de journald. Cela fonctionne même si la garde SSH est désactivée. Rien n'est envoyé vers l'extérieur.
Seules les valeurs rapportées par le noyau sont crues : l'exécutable vient de /proc/<pid>/exe (et non d'argv[0]), la connexion de loginuid (fixé une seule fois à la connexion et hérité à travers sudo et su) et du session-N.scope du cgroup, le reste de la chaîne des parents. Les valeurs qu'un processus peut modifier lui-même, comme comm, la ligne de commande et l'environnement, sont affichées mais ne servent jamais à décider ; un processus qui se contente de s'appeler sshd n'est pas pris pour une connexion SSH. Une notification distingue trois réponses : trouvée (source, heure, méthode, clé) ; « Aucune connexion SSH n'a été trouvée » (la vérification a montré un service systemd, un conteneur, une session de connexion locale ou un processus sans session de connexion) ; et « Le chemin de connexion n'a pas pu être déterminé » (le processus avait déjà disparu et n'est pas dans l'enregistreur d'exécutions, logind n'a pas répondu, la modification a été trouvée par l'analyse périodique et le processus est donc inconnu, etc.). Ce qui n'a pas pu être vérifié n'est jamais présenté comme « pas une connexion ». La notification part même si la recherche échoue.
/etc/ssh/sshd_config: modified
Processus : root (connecté en tant que admin) / /usr/bin/tee / commande : tee /etc/ssh/sshd_config (pid 4121)
Connexion SSH : la session ouverte par admin depuis 203.0.113.25:51544 à 2026-10-17 03:12:08 (authentification : publickey, clé SHA256:AbCdEf0123456789)
/etc/sudoers: modified
Le chemin de connexion n'a pas pu être déterminé (le changement a été trouvé par l'analyse périodique ; le processus responsable est inconnu)
Les modifications qui placent un nouveau fichier sous le même nom sont désormais détectées elles aussi : install, sed -i, et cp suivi de mv dans le même répertoire. Un marquage par fichier est posé sur l'inode, de sorte que ce genre de modification ne produisait auparavant aucun événement. Le démon marque maintenant aussi les répertoires qui contiennent des fichiers surveillés, et lorsqu'un fichier d'un autre nom est fermé dans le même répertoire, il recherche à nouveau le nom quelques millisecondes plus tard. Limite : un fichier écrit dans un autre répertoire puis déplacé avec mv n'est trouvé que par l'analyse périodique (fim_check_interval_secs). Le processus écrivain est alors inconnu, et la notification le dit.
Outre la notification, le constat est conservé dans la chronologie des incidents (type fim) et dans /var/lib/roamswitch/fim_intrusions.json (root uniquement, les 100 derniers). L'outil MCP verify_fim le renvoie dans un champ ajouté, recentIntrusionContext (seulement s'il est lancé en root). Le verdict sur l'altération ou non d'un fichier ne change pas. Limites : avec l'enregistreur d'exécutions désactivé et un processus écrivain qui ne vit qu'un instant, l'exécutable est inconnu ; on affiche alors l'exécutable et la ligne de commande du processus parent. Les notifications de la surveillance de persistance (persistence_watch) ne portent aucune information de processus et n'ont donc pas de chemin d'intrusion. Le chemin montre le processus à l'origine de la modification et sa connexion, pas davantage : la porte d'entrée elle-même (la vulnérabilité exploitée, ou la façon dont une clé a été volée) n'est pas montrée. Pour le désactiver, mettez fim_intrusion_context_enabled=false.
8. Intégration eBPF Runtime Guard et Falco
S'accroche aux événements eBPF de l'espace noyau (Falco / Tetragon) pour détecter l'élévation des privilèges du noyau Frag Gap, les échappements de conteneurs et les shells inversés non autorisés.
8.1 Architecture anti-ballonnement
Pour éviter l’« explosion de syslog » et la pression sur le disque dont souffrent les outils de sécurité classiques, RoamSwitch se connecte à Falco directement via la socket de domaine UNIX /run/roamswitch/events.sock. La socket est créée accessible à root uniquement (0600) : seul Falco, exécuté en root, peut y écrire (aucune configuration de permissions supplémentaire n’est nécessaire).
- L'ensemble
/etc/falco/config.d/99-roamswitch-optimized.yamldiffuse les événements directement dans le démon sans aucune E/S disque. La sortie de Falco est transmise au socket avecsocatdans cette configuration ; les paquets deb / rpm de l'édition Server installent doncsocatcomme paquet recommandé (Recommends) ; il est inutile si vous n'utilisez pas Falco. /etc/logrotate.d/roamswitch-falcogarantit une rotation quotidienne propre pour toutes les sorties de fichiers de secours.
8.2 Confinement autonome
Lors de la détection d'une attaque critique, RoamSwitch émet immédiatement SIGSTOP pour geler le PID du processus incriminé et applique l'isolation Air-Gap nftables.
8.3 Préservation automatique des preuves (Forensic Evidence Capture)
Un lot de preuves est créé automatiquement chaque fois que la garde d'exécution eBPF applique une action de confinement par processus (gel via SIGSTOP et coupure réseau). Selon la politique par défaut du §4.1, les événements de sévérité Critical suivent cette voie ; les événements de sévérité Emergency, qui isolent l'hôte entier, ne produisent actuellement pas de lot. Un lot contient une capture de paquets limitée, au mieux, d'environ 30 secondes sur l'interface de routage par défaut (ignorée silencieusement, avec mention de l'omission, si tshark n'est pas installé), ainsi que, lorsque le PID en cause est connu, un instantané /proc/<pid> : status, cmdline, maps, environ (les valeurs dont le nom contient KEY/TOKEN/SECRET/PASSWORD sont remplacées par [REDACTED]), une liste des cibles des descripteurs de fichiers ouverts, et la chaîne des processus ancêtres jusqu'au PID 1. Un fichier manifest.json enregistrant le hachage SHA-256 de chaque fichier capturé est inclus pour une vérification ultérieure d'altération.
Les lots sont stockés sous /var/lib/roamswitch/incident-evidence/<horodatage>-<ID>/. Ils ne sont jamais purgés automatiquement. Pour libérer de l'espace disque, supprimez explicitement les lots plus anciens que la période de rétention (30 jours par défaut) avec :
sudo roamswitch-incident-capture prune [--keep-days N]
Vous pouvez également capturer un instantané manuel à tout moment, sans attendre une action de confinement, avec :
sudo roamswitch-incident-capture snapshot [--pid PID] [--reason TEXT] [--json]
8.4 Mesure de la rapidité d'isolement et heartbeat du chemin d'alerte
La précision et la rapidité de l'isolement eBPF dépendent des règles du capteur (Falco ou Tetragon). De fait, les règles standard de Falco 0.45.0 (29 au total) n'en comptent aucune qui détecte un reverse shell sur l'hôte : les règles de reverse shell ne valent que pour les conteneurs, et certaines sont écartées par la condition priority: warning de RoamSwitch. RoamSwitch ne présume pas de la qualité des règles ; il compense de trois façons : il mesure la durée de l'isolement, il vérifie régulièrement que le chemin d'alerte est vivant, et il détecte lui-même les reverse shells.
Mesure de la latence d'isolement : pour chaque incident eBPF, le démon enregistre le temps écoulé entre la détection par Falco et la lecture de l'alerte (detect_to_receive_ms), entre la lecture et la fin de la réponse (receive_to_action_ms, mesuré une fois l'appel d'isolement revenu ; pour l'Air-Gap de l'hôte, jusqu'au chargement du jeu de règles), ainsi que leur somme (detect_to_action_ms). Les valeurs apparaissent comme champs ajoutés dans ebpf_incidents.json et dans l'outil MCP get_ebpf_incidents. La notification d'un processus isolé porte une ligne « de la détection à la réponse : N ms ». Mesures sur une VM Ubuntu 24.04 (Falco 0.45.0, modern eBPF) : 1 à 2 ms de la détection à la réception, 41 à 62 ms de la réception à l'isolement du processus plus SIGKILL (42 à 64 ms au total), et 109 ms au total pour l'Air-Gap de l'hôte (dans l'objectif de 150 ms). Ces chiffres sont ceux de cette VM. Tetragon horodate à la réception et n'a donc pas de detect_to_receive_ms.
Heartbeat (ebpf_heartbeat_interval_secs ; 600 secondes par défaut, 0 le désactive, sinon 60 à 86400) : le paquet fournit une règle Falco propre à RoamSwitch, 96-roamswitch-heartbeat.yaml. À chaque intervalle, le démon ouvre un chemin jetable que seul root peut utiliser (un nom aléatoire sous /run/roamswitch/heartbeat/) et mesure le temps que met l'alerte de cette règle à revenir par la sortie de Falco. Un aller-retour montre à la fois que la règle est chargée, que Falco tourne et que le chemin de sortie est vivant. Ce n'est que lorsque deux vérifications de suite ne reviennent pas (la seconde une minute après la première) qu'il avertit : « les règles ne sont pas chargées ou la sortie n'arrive pas », au plus une fois par 24 heures. Une ligne de heartbeat est écartée sans atteindre l'isolement, la notification, la liste d'autorisation ni le journal des incidents. Rien n'est envoyé vers l'extérieur. Les allers-retours mesurés étaient de 2 à 6 ms ; avec la règle retirée, l'avertissement est venu après environ 164 secondes, et une fois la règle rétablie l'état est redevenu normal en environ 75 secondes.
L'état est conservé dans /var/lib/roamswitch/ebpf_heartbeat.json et lu par le champ heartbeat de l'outil MCP get_ebpf_incidents et par le diagnostic K-04 (agent d'exécution eBPF ; le nombre de points de diagnostic reste 34). Même si Falco tourne, K-04 échoue lorsque le heartbeat ne revient pas. Limites : on vérifie un aller-retour d'une seule règle (les appels système de la famille open) ; cela ne permet pas de savoir si une autre règle est cassée pour son compte. Ce qui casse entre deux vérifications (10 minutes par défaut) n'est vu qu'à la suivante. Cela n'est pas fait pour Tetragon. Sur un hôte où Falco ne tourne pas ou dont le fichier de règle est absent, rien n'est vérifié et rien n'est signalé (la notification existante « garde arrêtée » s'en charge). Falco écrit une ligne d'avertissement dans syslog à chaque vérification (144 lignes par jour par défaut).
8.5 Détection de reverse shell (propre à RoamSwitch)
Sans s'appuyer sur les règles de Falco, RoamSwitch lit lui-même /proc toutes les 2 secondes et cherche un shell ou un interpréteur (sh, bash, python, perl, ruby, php, node et similaires) dont l'entrée et la sortie standard sont une même connexion TCP que cet hôte a ouverte vers une adresse extérieure. Sont couverts bash -i >& /dev/tcp/…, python, perl, nc -e et socat exec:. Seul ce qui est vu deux fois de suite est signalé, une fois par processus. Par défaut, seules les adresses extérieures publiques comptent ; les adresses privées (RFC 1918, CGNAT, lien local) ne comptent qu'avec reverse_shell_watch_include_private=true, car le ProxyCommand de ssh, les conteneurs et le développement local les rendent courantes et légitimes. Le loopback n'est jamais surveillé. Les connexions acceptées par l'hôte (par inetd ou socat TCP-LISTEN) ne sont pas couvertes non plus. Mesuré sur une VM Ubuntu 24.04, bash /dev/tcp, python, perl, nc -e et socat exec: ont chacun été détectés environ 2,4 secondes après la connexion. ssh, ssh avec un ProxyCommand, git over ssh et un client nc ne sont pas détectés.
Une détection emprunte le même chemin qu'une alerte Falco (liste d'autorisation, délai de répit des notifications, actions par gravité de guard.yaml, journal des incidents) sous la forme d'un événement eBPF Critical nommé RoamSwitch Reverse Shell. Par défaut, le processus est isolé puis tué (kill). Un reverse shell appartenant à root ne peut pas être isolé par processus ; comme pour tout événement Critical, on passe donc à l'Air-Gap de tout l'hôte. Il y a deux issues si l'on craint qu'un programme légitime soit détecté à tort : reverse_shell_watch_notify_only=true (un Warning avec notification seulement ; rien n'est isolé ni tué ; false par défaut) et une entrée dans la liste d'autorisation, sudo roamswitch server allowlist add "RoamSwitch Reverse Shell" <nom du processus>. Les trois clés de réglage sont reverse_shell_watch_enabled (true par défaut), reverse_shell_watch_include_private (false) et reverse_shell_watch_notify_only (false) .
Limites : le filtrage se fait par nom (nom du processus et de l'exécutable) ; un binaire maison portant un autre nom que celui d'un shell ou d'un interpréteur et reliant son entrée et sa sortie standard à un socket n'est donc pas trouvé. Les connexions par loopback (comme le retour de ssh -R) et celles de moins de 2 secondes ne sont pas vues, pas plus que les processus invisibles depuis l'espace de processus de l'hôte. Cette détection n'existe que dans la Server Edition ; le Mac et le client Linux ne l'ont pas.
9. Alertes d'urgence (Telegram / LINE / Webhook)
Envoie des alertes immédiates aux canaux de notification externes lorsque des anomalies de port, une falsification FIM ou des événements de confinement eBPF se produisent :
[notifications]
language = ja
# Telegram : jeton de bot et ID de chat
telegram_bot_token = "123456789:ABCdefGHIjklMNOpqrSTUvwxYZ"
telegram_chat_id = "-1001234567890"
# LINE : jeton d'accès au canal Messaging API et ID utilisateur
line_channel_access_token = "YOUR_LINE_ACCESS_TOKEN"
line_user_id = "U1234567890abcdef1234567890abcdef"
# Webhook générique (Slack, Discord, Teams, votre propre plateforme de supervision)
webhook_url = "https://hooks.slack.com/services/T00/B00/XXXXX"
Même sans configurer ces canaux externes, chaque alerte envoyée est également conservée localement pendant les 7 derniers jours. Consultez-la avec roamswitch notifications.
Refuser les destinations de webhook internes (opt-in) : avec webhook_block_private_addresses=true (défaut false = inchangé), un webhook de notification est refusé si sa destination — pour un nom d'hôte, une seule adresse résolue suffit — est en loopback, privée (10/8, 172.16/12, 192.168/16), lien-local (169.254/16, dont le point de métadonnées cloud 169.254.169.254), ULA (fc00::/7) ou CGNAT (100.64/10). La raison apparaît dans le journal et dans l'erreur de roamswitch notify-test. Les écritures alternatives comme 2130706433 ou 0x7f.1 et l'IPv6 IPv4-mapped sont aussi classées, et les adresses vérifiées sont figées dans curl, ce qui empêche le DNS rebinding de changer la cible. Les destinations internes légitimes, comme un SIEM interne, sont autorisées par webhook_allow_addresses=10.20.0.0/16,fd00::/8 (CIDR séparés par des virgules). Les webhooks de transfert d'événements ont la même paire : forward_webhook_block_private_addresses et forward_webhook_allow_addresses. Même avec l'option à false, une destination qui est une adresse de métadonnées cloud journalise un avertissement (l'envoi n'est pas bloqué). Si une variable d'environnement de proxy HTTP est définie, la résolution et la connexion se font au niveau du proxy et échappent à cette vérification.
10. Intégration de l'agent AI / MCP (Protocole de contexte de modèle)
RoamSwitch Server Edition inclut roamswitch-mcp, permettant aux agents d'IA (Claude, Gemini, Cursor) de surveiller l'état et la posture de l'infrastructure.
Exemple de configuration (`claude_desktop_config.json`)
{
"mcpServers": {
"roamswitch": {
"command": "/usr/bin/roamswitch-mcp",
"args": []
}
}
}
10.1 Délégation à un agent d'investigation (investigation — délégation de l'investigation automatisée initiale à un agent IA)
Alors que le roamswitch-mcp du §10 répond aux requêtes d'un client IA humain, la délégation investigation est un mécanisme distinct où le démon lui-même lance de manière autonome une CLI d'agent IA externe, déclenchée par un événement de détection. Elle cible les événements eBPF critiques jugés notification uniquement (n'ayant pas déclenché d'isolation automatique ni de gel de processus), ainsi que les détections d'altération de FIM Critical-Path et de fichiers de verrouillage de dépendances. Une fois activé, le démon génère d'abord un rapport de triage initial heuristique local (probabilité de faux positif, raisonnement, prochaines étapes suggérées), puis lance la CLI d'agent IA configurée en tant que sous-processus avec ce rapport joint, déléguant l'investigation et le résumé supplémentaires. Désactivé par défaut.
# À ajouter à /etc/roamswitch/guard.yaml (un fichier distinct de server.conf)
investigation:
enabled: true
command: "claude" # "claude" | "agy" | "codex" | "opencode" | toute commande personnalisée
args: ["-p"] # Le prompt est automatiquement ajouté en tant que dernier argument
timeout_secs: 180
Les mêmes paramètres peuvent également être configurés depuis l'assistant interactif de sudo roamswitch server setup (§3.2, dernière étape). Choisissez parmi les préréglages pour Claude Code (claude -p), agy (agy -p --dangerously-skip-permissions), Codex CLI (codex exec), OpenCode (opencode run), ou une commande personnalisée. Lors d'une nouvelle exécution, le préréglage correspondant est sélectionné automatiquement à partir de la configuration enregistrée.
run_as n'est pas enregistrée par l'assistant (CLI et TUI) et le démon ne la démarre pas. Lancer l'outil dans un mode qui ignore les demandes d'autorisation, comme --dangerously-skip-permissions, augmente le risque qu'une entrée malveillante pousse l'agent à des actions non prévues. L'assistant affiche cet avertissement lorsque agy est choisi. Là où existent des chemins de journaux non fiables, une configuration d'outil qui n'ignore pas les demandes d'autorisation est recommandée.La délégation investigation n'est jamais invoquée lorsque le réseau est coupé (par exemple lors d'un Air-Gap actif, ou de tout état équivalent à isolate_host_all).
11. Aide-mémoire des commandes CLI
| Commande | Privilèges | Descriptif |
|---|---|---|
sudo roamswitch status --server |
root | Affiche le score de sécurité du serveur sur 34 éléments et son état (--json affiche le même rapport en JSON) |
sudo roamswitch ports |
root | Auditer les ports d'écoute ouverts et les processus liés |
sudo roamswitch fim verify |
root | Vérifier l'intégrité SHA-256 des fichiers système du chemin critique |
roamswitch notifications |
Utilisateur | Affiche l’historique des notifications de la semaine écoulée (toutes les alertes envoyées) ; --json et --export FILE sont pris en charge |
sudo roamswitch server setup |
root | Lancer l'assistant de configuration initiale interactif |
sudo roamswitch fim update |
root | Actualiser la base de données de base FIM SHA-256 |
sudo roamswitch server config set <key> <value> |
root | Modifie et enregistre une seule clé de configuration (liste au §18) |
sudo roamswitch emergency-restore |
Racine | Désarme toute isolation eBPF/pare-feu et restaure la base de référence initiale |
roamswitch port-scan |
Utilisateur | Affiche l'historique de détection de la garde de détection de scan de ports entrants (§4.3) (IP source, blocage automatique ou non, durée du blocage) |
roamswitch sensor [key|list|pair|unpair|request-audit|results] |
Utilisateur/root | Confiance mutuelle avec un RoamSwitch Sensor par codes d’appairage. pair --addr <IP> --code <code> --fingerprint <SHA-256> effectue l’appairage (l’empreinte est la valeur affichée sur l’écran de Sensor), repin met à jour l’épinglage après que Sensor a régénéré son certificat, et request-audit demande un audit actif de vulnérabilités (récupérez le résultat avec results). Nécessite sensor_pairing_enabled: true (désactivé par défaut). Pour plus de détails, consultez le Manuel d’exploitation de Sensor |
roamswitch server tui |
Utilisateur/root | Lance la TUI qui couvre toutes les fonctions (lecture seule pour les utilisateurs ordinaires, contrôle total en root ; §17) |
sudo roamswitch server ack |
root | Accuse réception de l’isolation d’urgence en cours (maintient stricte une isolation FULL, lève une isolation DEGRADED ; §4.1) |
roamswitch server ebpf |
Utilisateur | Affiche l’état de confinement actuel de la protection d’exécution eBPF et l’historique des incidents détectés |
roamswitch server bans [--json] |
Utilisateur/root | Affiche la garde contre la force brute SSH (§4.5) : son état et les sources actuellement bannies avec la durée restante. --json est disponible. La liste des bannissements n'est lisible que par root |
sudo roamswitch server unban <IP | IPv6 /64 | --all> |
root | Lève un bannissement de la garde SSH et efface le compteur d'échecs de cette source (indiquez une source IPv6 par son /64 ; --all lève tous les bannissements) |
sudo roamswitch server allowlist [list|add <rule> <process> [--exe <path>]|remove <rule> <process>] |
root | Gère la liste d’autorisation permanente des faux positifs. Avec --exe, l’entrée est liée au chemin réel de l’exécutable, de sorte qu’un processus renommé ne peut pas en bénéficier (une entrée par nom seul peut être usurpée, et un avertissement est affiché) |
roamswitch frozen [list|resume <PID>|resume all] |
Utilisateur/root | Liste les processus que les protections maintiennent en SIGSTOP et libère celui qui était un faux positif (SIGCONT) ; resume all les libère tous |
sudo roamswitch events search|tree|export|verify|status |
root | Recherche dans l’enregistreur d’exécutions (--since 2h --pid --exe --user --parent --text --json), affiche un arbre de processus, exporte, vérifie la chaîne de hachage et affiche l’état (§15) |
sudo roamswitch forward status|test|queue |
root | Affiche l’état du transfert d’événements, envoie un événement de test et liste la file de nouvelles tentatives (§16) |
roamswitch timeline / notifications [--json] [--export FILE] |
Utilisateur | Affiche la chronologie unifiée des incidents (expérimental) ou l’historique des notifications ; --json affiche un tableau JSON et --export FILE écrit du JSON Lines |
roamswitch audit-agent-setup [--json] |
Utilisateur | Vérification en lecture seule des fichiers d'instructions, des skills et des réglages OpenClaw donnés aux agents IA à la recherche de contenu risqué (dossier personnel seulement, sans réseau ; --json affiche du JSON). Disponible aussi dans « Outils » du Server TUI |
12. Dépannage et FAQ
T1. RoamSwitch déconnectera-t-il inopinément ma session SSH ?
Non. En fonctionnement normal, RoamSwitch autorise inconditionnellement les états de connexion established/related et ssh_ports (22 par défaut). Même lorsqu’une attaque grave déclenche une isolation d’urgence Air-Gap, preserve_ssh_on_isolation=true (par défaut) maintient les sessions d’administration sur les ports SSH de maintenance et depuis les IP d’administration (toutes les autres connexions établies sont coupées). L'édition serveur jusqu'à la 1.10.4 présentait un défaut. Les règles d'isolement abandonnaient les réponses SSH, de sorte que le SSH de l'opérateur ne fonctionnait pas pendant l'isolement. Il est corrigé dans la 1.10.5.
Q2. Comment puis-je récupérer l’accès en cas de verrouillage accidentel ?
Connectez-vous via la console web de votre fournisseur cloud (VNC / console série), puis exécutez sudo roamswitch emergency-restore pour lever l'isolation, ou sudo systemctl stop roamswitch-server pour arrêter le service.
Q3. Comment puis-je exposer les ports pour les services Web nouvellement ajoutés (par exemple Nginx) ?
Exécutez sudo roamswitch server config set allowed_ports 80,443,3000 (ou modifiez directement /etc/roamswitch/server.conf), puis sudo roamswitch server restart.
13. File Scan Guard (protection des relais de messagerie, dossiers partagés et points de dépôt de fichiers)
Fonctionnalité optionnelle pertinente uniquement si cet hôte possède un répertoire stockant des fichiers destinés à des tiers — un relais de messagerie, un partage Samba/NFS, un point de dépôt d'upload. Le moteur YARA intégré analyse en permanence clamav_scan_dirs sans dépendance externe ; activer clamav_enabled=true ajoute ClamAV comme second avis. Les menaces confirmées sont automatiquement mises en quarantaine dans /var/lib/roamswitch/quarantine et l'opérateur est averti.
# --- File Scan Guard (ClamAV, opt-in) ---
# Le moteur YARA intégré analyse toujours clamav_scan_dirs sans condition.
clamav_enabled=false # true active une inspection supplémentaire via clamdscan
clamav_scan_dirs= # Chemins absolus à analyser (séparés par des virgules)
clamav_scan_interval_secs=86400 # Intervalle d'analyse (secondes, minimum 3600)
clamav_freshclam_interval_secs=7200 # Intervalle de mise à jour automatique de la base de signatures (secondes, minimum 1800)
Également configurable via l'assistant interactif sudo roamswitch server setup ; vérifiez sa configuration et l'état de la quarantaine via l'outil MCP get_file_scan_guard_status.
14. Log Audit (détection et notification des anomalies de motifs de journaux)
Une analyse périodique de journalctl transforme les messages de journal en modèles afin de détecter de nouveaux motifs (des formes de journal jamais vues auparavant) et des anomalies de fréquence (un pic statistique, Z-score > 3,0). Ce mécanisme léger ne nécessite aucun démon supplémentaire ni dépendance externe, il est donc activé par défaut. Les détections sont envoyées via les mêmes canaux de notification que File Scan Guard et FIM (Telegram / LINE / Webhook). Toute clé API ou tout jeton susceptible d'apparaître dans une ligne de journal est automatiquement masqué avant d'être inclus dans la notification.
# --- Log Audit (activé par défaut) ---
log_audit_enabled=true # false pour désactiver
log_audit_interval_secs=1800 # Intervalle d'analyse en secondes (minimum 300)
Peut également être configuré depuis l'assistant interactif sudo roamswitch server setup, et les derniers résultats de détection peuvent être consultés via la commande CLI roamswitch audit-logs ou l'outil MCP audit_security_logs.
AccessScope, un outil de diagnostic des journaux d'accès (outil distinct) : le deb / rpm de la Server Edition inclut la commande accessscope d'un outil distinct qui diagnostique les journaux d'accès des serveurs web et de SSH (l'application à fenêtre n'est pas incluse). Il est en lecture seule, et son analyse n'utilise ni LLM ni réseau. L'analyse par un LLM est facultative et désactivée par défaut (lorsqu'elle est activée, elle peut aussi s'exécuter en tant que root, mais le LLM s'exécute alors avec les droits root ; un utilisateur sans privilèges est recommandé). accessscope scan --auto diagnostique les journaux de cet hôte, et accessscope discover liste l'emplacement des journaux. Pour plus de détails, consultez la page AccessScope. Les deb / rpm de la Server Edition incluent aussi les commandes personalsoc et pathscope de deux autres outils distincts, PersonalSOC (vérifie les journaux et l'état des défenses de cet hôte) et PathScope (analyse les chemins d'élévation de privilèges) ; les applications à fenêtre ne sont pas incluses. Les commandes elles-mêmes n'effectuent aucune communication réseau. L'analyse par LLM de PersonalSOC ne s'exécute que si vous passez --llm.
15. Enregistreur d’exécutions et règles de corrélation (local, notification seule)
Les exécutions de processus (exec) sont enregistrées via le proc connector netlink : exécutable, arguments, filiation parentale, UID, cwd, ID de conteneur et SHA-256. La fonction est activée par défaut, et les enregistrements sont stockés sur cet hôte, dans le répertoire accessible à root uniquement /var/lib/roamswitch/exec_log, sous forme de JSON Lines segmentés et chaînés par hachage (0600, 200 Mo / 14 jours par défaut) et ne sont jamais envoyés ailleurs. Le journal est inviolable de façon détectable (events verify), pas infalsifiable. Si le proc connector ne peut pas être ouvert, la fonction se dégrade en un balayage de /proc à faible cadence. L’enregistrement s’exécute dans ses propres threads, distincts de la boucle d’événements de permission fanotify, et maintient sa propre consommation CPU dans un budget (3 % par défaut).
Recherchez et exportez localement (le journal étant accessible à root uniquement, sudo est normalement requis).
sudo roamswitch events status
sudo roamswitch events search --since 2h --exe curl
sudo roamswitch events tree 4242
sudo roamswitch events export --since 1d > exec-events.jsonl
sudo roamswitch events verify
Règles de corrélation EXR-001 à EXR-007 (notification seule, chacune avec un ID de technique MITRE ATT&CK) : EXR-001 un shell lancé par un service web / EXR-002 exécution depuis /tmp, un fichier supprimé ou memfd / EXR-003 exécution juste après un téléchargement / EXR-004 une commande d’interpréteur en une ligne utilisant base64 ou eval / EXR-005 obtention de l’uid 0 sans setuid / EXR-006 exécution d’un binaire tout juste déposé par cron ou systemd / EXR-007 exécution après modification de ld.so.preload. Chaque règle a une valeur par défaut volontairement silencieuse et n’isole jamais d’elle-même. Rendez silencieuses des règles individuelles avec exec_rules_disabled (par exemple EXR-003,EXR-004) et ajustez les utilisateurs surveillés par EXR-001 avec exec_rule_service_users.
Ce n’est que si vous réglez explicitement exec_rules_isolation_optin (false par défaut) sur true que les règles de gravité élevée sont traitées comme un déclencheur d’isolation à haute confiance (§4.1). Par défaut, les règles se contentent de notifier. Les enregistrements peuvent aussi être lus via les outils MCP en lecture seule search_exec_events et get_process_tree.
16. Transfert d’événements (SIEM / syslog / webhook, sur option)
Les événements de détection peuvent être transférés vers des destinations que vous indiquez au sein de votre propre organisation. La fonction est désactivée par défaut : rien n’est envoyé tant que vous n’avez pas défini forward_enabled=true et configuré au moins une destination, et aucune destination de l’éditeur n’est intégrée. Sont transférés la chronologie des incidents, l’historique des notifications, la protection eBPF, les transitions d’état d’isolation, ainsi que les alertes FIM, canary et de règles d’exécution ; le journal d’exécutions brut lui-même n’est pas transféré. Il existe trois types de destination.
- syslog (
forward_syslog_url:udp://host:514/tcp://host:port/tls://host:port) : RFC 5424 ou CEF (forward_syslog_format). Le cadrage TCP / TLS estoctet(RFC 6587, par défaut) oulf. Vous pouvez indiquer une CA pour la vérification TLS avecforward_tls_ca_file, et la connexion est déléguée àopenssl s_clientdu système. - Fichier JSON Lines (
forward_file_path) : un événement par ligne, rotation selonforward_file_max_mb(50 par défaut) etforward_file_keep(5 par défaut). - Webhook structuré (
forward_webhook_url) : un POST JSON signé en HMAC-SHA256 avec un secret partagé (forward_webhook_secret, ouforward_webhook_secret_filepointant vers un fichier0600), transporté dans l’en-têteX-RoamSwitch-Signature. L’envoi est effectué par un sous-processuscurl, et le secret n’est jamais placé sur la ligne de commande.
Les événements qui n’ont pas pu être livrés (TCP / TLS / webhook) sont placés dans une file de nouvelles tentatives sur disque (0600, plafonnée par forward_queue_max_mb, 20 par défaut, et forward_queue_max_age_hours, 72 par défaut) et réessayés avec un backoff exponentiel, y compris après un redémarrage. forward_min_severity (low par défaut) fixe la gravité minimale envoyée. L’envoi s’exécute dans un thread dédié, de sorte qu’aucun chemin critique n’est bloqué, et lorsque la file déborde, les éléments les plus anciens sont supprimés en premier.
Vérifiez l’état, testez la connectivité et inspectez la file de nouvelles tentatives avec les commandes suivantes (redémarrez le service après avoir modifié les réglages).
# /etc/roamswitch/server.conf
forward_enabled=true
forward_syslog_url=tls://siem.example.org:6514
forward_syslog_format=rfc5424
forward_tls_ca_file=/etc/ssl/certs/corp-ca.pem
forward_min_severity=medium
sudo roamswitch server restart
sudo roamswitch forward status
sudo roamswitch forward test
sudo roamswitch forward queue
17. TUI du serveur (une interface terminal pour chaque fonction)
roamswitch-server-tui (également lancé par roamswitch server tui) est une TUI qui donne accès à toutes les fonctions de Server Edition — réparties entre les verbes de la CLI et les deux fichiers de configuration (server.conf et guard.yaml) — uniquement au clavier, via SSH (elle fonctionne en 80x24, en 10 langues). Les tests de développement échouent dès qu’un verbe de la CLI ou une clé de configuration n’a pas d’équivalent dans la TUI.
- Mode de permissions : lancée en tant qu’utilisateur ordinaire, elle est en lecture seule (les modifications et les actions privilégiées sont désactivées, et la commande
sudo roamswitch …dont vous auriez besoin est affichée à la place). Lancée en root, elle peut agir ; les opérations à fort impact indiquent d’abord ce qu’elles vont faire, et les plus dangereuses exigent de saisiryes. Elle ne démarre jamais le démon et n’ouvre aucune socket réseau qui lui soit propre. - Écrans (changement avec les touches numériques) :
1Tableau de bord (santé, état d’isolation) /2Protection (isolation eBPF, canary, FIM, Docker, egress et DNS, enregistreur d’exécutions, règles et recherche d’événements, flux, XDP gate) /3Incidents (tous les types d’incidents, dont la liste des bannissements SSH et leur levée, chronologie, historique des notifications, processus gelés, coffre de quarantaine, liste d’autorisation) /4Notifications et transfert /5Sensor /6Configuration /7Service /8Outils /9Audit des journaux /0À propos et aide.?affiche les touches de l’écran courant,Lfait défiler les 10 langues,rrecharge etqquitte (en demandant d’abord confirmation si des modifications de configuration ne sont pas enregistrées). - Éditeur de configuration : généré à partir d’un schéma, il modifie les 146 clés de
server.confetguard.yaml(§18) avec validation du type, de la plage et des valeurs autorisées. Vous examinez un diff (avec les secrets masqués) avant d’enregistrer, et l’enregistrement crée une sauvegarde horodatée et écrit de façon atomique. Les clés qui nécessitent un redémarrage, et celles dont une mauvaise valeur peut vous couper l’accès ou affaiblir la protection, sont signalées. La configuration de l’agent d’investigation (§10.1) peut aussi être écrite, après avoir choisi un préréglage et en avoir prévisualisé le résultat.
Lancez-la avec :
sudo roamswitch-server-tui # full control
roamswitch-server-tui # read-only
roamswitch server tui # same as roamswitch-server-tui
18. Référence des clés de configuration (server.conf / guard.yaml)
roamswitch-server ne prend pas en charge le rechargement de sa configuration : chaque clé exige un redémarrage du service pour prendre effet (sudo roamswitch server restart). Modifiez les clés de server.conf avec roamswitch server config set <key> <value> ou avec l’éditeur du §17 ; modifiez guard.yaml avec l’éditeur ou à la main.
18.1 server.conf (109 clés)
| Clé | Type / valeurs | Par défaut | Redémarrage |
|---|---|---|---|
language | system | ja | en | zh-hans | zh-hant | ko | de | fr | es | it | pt | ja | Oui |
ssh_ports | port list | 22 | Oui |
allowed_ports | port list | 80,443 | Oui |
whitelist_ips | list | — | Oui |
preserve_ssh_on_isolation | bool | true | Oui |
telegram_enabled | bool | false | Oui |
telegram_bot_token | string | — | Oui |
telegram_chat_id | string | — | Oui |
line_enabled | bool | false | Oui |
line_channel_access_token | string | — | Oui |
line_user_id | string | — | Oui |
webhook_enabled | bool | false | Oui |
webhook_url | URL | — | Oui |
webhook_block_private_addresses | bool | false | Oui |
webhook_allow_addresses | CIDR list | — | Oui |
action_on_critical | isolate | freeze | alert_only | isolate | Oui |
ebpf_socket_path | abs path | /run/roamswitch/events.sock | Oui |
ebpf_heartbeat_interval_secs | 0 (off) | int 60–86400 | 600 | Oui |
isolation_hard_cap_secs | int ≥ 0 | 3600 | Oui |
fim_check_interval_secs | int ≥ 10 | 300 | Oui |
fim_intrusion_context_enabled | bool | true | Oui |
protect_docker_ports | bool | true | Oui |
dns_sinkhole_enabled | bool | false | Oui |
dns_sinkhole_provider | quad9 | cloudflare | adguard | cleanbrowsing | quad9 | Oui |
egress_ip_blocklist_enabled | bool | true | Oui |
metadata_watch_enabled | bool | true | Oui |
metadata_watch_allow_users | list | — | Oui |
cve_kernel_map_updates_enabled | bool | true | Oui |
clamav_enabled | bool | false | Oui |
clamav_scan_dirs | abs path list | — | Oui |
clamav_scan_interval_secs | int ≥ 3600 | 86400 | Oui |
clamav_freshclam_interval_secs | int ≥ 1800 | 7200 | Oui |
lockfile_watch_dirs | abs path list | — | Oui |
npm_audit_signatures_enabled | bool | false | Oui |
log_audit_enabled | bool | true | Oui |
log_audit_interval_secs | int ≥ 300 | 1800 | Oui |
resource_guard_enabled | bool | true | Oui |
resource_guard_rss_sample_interval_secs | int ≥ 10 | 60 | Oui |
resource_guard_rss_window_secs | int ≥ 300 | 1800 | Oui |
resource_guard_rss_min_samples | int ≥ 3 | 10 | Oui |
resource_guard_rss_min_growth_pct | int ≥ 10 | 50 | Oui |
resource_guard_rss_recovery_drop_pct | int ≥ 1 | 10 | Oui |
resource_guard_rss_min_kb | int ≥ 0 | 20000 | Oui |
resource_guard_crash_loop_window_secs | int ≥ 60 | 300 | Oui |
resource_guard_crash_loop_min_restarts | int ≥ 2 | 3 | Oui |
resource_guard_correlation_window_secs | int ≥ 60 | 600 | Oui |
resource_guard_zombie_min_count | int ≥ 0 | 20 | Oui |
resource_guard_load_min_normalized | float ≥ 0.0 | 0.5 | Oui |
resource_guard_load_enabled | bool | true | Oui |
resource_guard_cpu_enabled | bool | true | Oui |
resource_guard_cpu_sample_interval_secs | int ≥ 0 | 60 | Oui |
resource_guard_cpu_window_secs | int ≥ 0 | 600 | Oui |
resource_guard_cpu_min_samples | int ≥ 0 | 8 | Oui |
resource_guard_cpu_pct_threshold | float 0.0–1000.0 | 80.0 | Oui |
container_exec_guard_enabled | bool | true | Oui |
port_scan_detect_enabled | bool | true | Oui |
port_scan_detect_min_distinct_ports | int ≥ 0 | 15 | Oui |
port_scan_detect_window_secs | int ≥ 0 | 300 | Oui |
port_scan_block_enabled | bool | true | Oui |
port_scan_block_duration_secs | int ≥ 0 | 600 | Oui |
ssh_guard_enabled | bool | true | Oui |
ssh_guard_block_enabled | bool | true | Oui |
ssh_guard_max_failures | int 2–1000 | 6 | Oui |
ssh_guard_window_secs | int 10–86400 | 600 | Oui |
ssh_guard_ban_secs | int 60–2592000 | 3600 | Oui |
ssh_guard_ban_max_secs | int 60–31536000 | 604800 | Oui |
ssh_guard_allow | IP/CIDR list | — | Oui |
ssh_guard_log_source | auto | journal | abs path | auto | Oui |
ssh_guard_yield_to_fail2ban | bool | true | Oui |
ssh_guard_trust_key_days | int 0–3650 | 30 | Oui |
dns_tunnel_detect_enabled | bool | true | Oui |
reverse_shell_watch_enabled | bool | true | Oui |
reverse_shell_watch_include_private | bool | false | Oui |
reverse_shell_watch_notify_only | bool | false | Oui |
sensor_pairing_enabled | bool | false | Oui |
sensor_colocated | bool | false | Oui |
forward_enabled | bool | false | Oui |
forward_syslog_url | URL | — | Oui |
forward_syslog_format | rfc5424 | cef | rfc5424 | Oui |
forward_syslog_framing | octet | lf | octet | Oui |
forward_tls_ca_file | abs path | — | Oui |
forward_file_path | abs path | — | Oui |
forward_file_max_mb | int 1–10000 | 50 | Oui |
forward_file_keep | int 1–100 | 5 | Oui |
forward_webhook_url | URL | — | Oui |
forward_webhook_secret | string | — | Oui |
forward_webhook_secret_file | abs path | — | Oui |
forward_webhook_block_private_addresses | bool | false | Oui |
forward_webhook_allow_addresses | CIDR list | — | Oui |
forward_min_severity | info | low | medium | high | critical | low | Oui |
forward_queue_max_mb | int 1–10000 | 20 | Oui |
forward_queue_max_age_hours | int 1–8760 | 72 | Oui |
exec_recorder_enabled | bool | true | Oui |
exec_recorder_retention_mb | int 1–100000 | 200 | Oui |
exec_recorder_retention_days | int 1–3650 | 14 | Oui |
exec_recorder_hash_chain | bool | true | Oui |
exec_recorder_hash_exe | bool | true | Oui |
exec_recorder_cpu_budget_pct | int 1–50 | 3 | Oui |
exec_rules_enabled | bool | true | Oui |
exec_rules_disabled | string | — | Oui |
exec_rule_service_users | string | — | Oui |
exec_rule_window_secs | int 5–3600 | 120 | Oui |
exec_rules_isolation_optin | bool | false | Oui |
honeytokens_enabled | bool | true | Oui |
honeytokens_home | abs path | /root | Oui |
harden_userns_enabled | bool | true | Oui |
dns_tunnel_entropy_allowlist | list | — | Oui |
fleet_forwarding_allowed_hosts | list | — | Oui |
fleet_forwarding_allow_plaintext | bool | false | Oui |
18.2 guard.yaml (37 clés)
| Clé | Type / valeurs | Par défaut | Redémarrage |
|---|---|---|---|
sensor.type | falco | tetragon | falco | Oui |
sensor.transport | string | unix_socket | Oui |
sensor.socket_path | abs path | /run/roamswitch/events.sock | Oui |
sensor.reconnect_interval_ms | int 100–3600000 | 1000 | Oui |
policies.on_warning.action | log_and_notify | isolate_process | isolate_host_all | log_and_notify | Oui |
policies.on_warning.server_action | log_and_notify | isolate_process | isolate_host_all | — | Oui |
policies.on_warning.kill_process | bool | false | Oui |
policies.on_warning.freeze_process | bool | false | Oui |
policies.on_warning.fallback_to_host_isolation_after_retries | int 0–1000 | — | Oui |
policies.on_error.action | log_and_notify | isolate_process | isolate_host_all | isolate_process | Oui |
policies.on_error.server_action | log_and_notify | isolate_process | isolate_host_all | — | Oui |
policies.on_error.kill_process | bool | false | Oui |
policies.on_error.freeze_process | bool | false | Oui |
policies.on_error.fallback_to_host_isolation_after_retries | int 0–1000 | — | Oui |
policies.on_critical.action | log_and_notify | isolate_process | isolate_host_all | isolate_process | Oui |
policies.on_critical.server_action | log_and_notify | isolate_process | isolate_host_all | — | Oui |
policies.on_critical.kill_process | bool | true | Oui |
policies.on_critical.freeze_process | bool | false | Oui |
policies.on_critical.fallback_to_host_isolation_after_retries | int 0–1000 | 3 | Oui |
policies.on_emergency.action | log_and_notify | isolate_process | isolate_host_all | isolate_host_all | Oui |
policies.on_emergency.server_action | log_and_notify | isolate_process | isolate_host_all | — | Oui |
policies.on_emergency.kill_process | bool | true | Oui |
policies.on_emergency.freeze_process | bool | false | Oui |
policies.on_emergency.fallback_to_host_isolation_after_retries | int 0–1000 | — | Oui |
server_safeguards.allow_established_connections | bool | true | Oui |
server_safeguards.maintenance_ssh_ports | port list | 22 | Oui |
server_safeguards.whitelist_cidrs | list | — | Oui |
server_safeguards.whitelist_dns_servers | list | — | Oui |
server_safeguards.safety_timer_secs | int ≥ 0 | 300 | Oui |
adaptive_security.enabled | bool | true | Oui |
adaptive_security.untrusted_network_actions.elevate_falco_profile | string | — | Oui |
adaptive_security.untrusted_network_actions.auto_enable_userns_restriction | bool | false | Oui |
investigation.enabled | bool | false | Oui |
investigation.command | abs path | — | Oui |
investigation.args | list | — | Oui |
investigation.run_as | string | — | Oui |
investigation.timeout_secs | int 1–86400 | 180 | Oui |
19. Détection des web shells et du code injecté (Web Rules)
Cette fonction détecte les web shells PHP, JavaScript, JSP et ASP et le code injecté qui tournent sur votre serveur web, le PHP caché dans des images et les abus de .htaccess (à partir de Linux 1.11.23). Aucune configuration n'est nécessaire : elle trouve les racines web dans la configuration d'Apache, nginx et Caddy et vérifie un fichier juste après son écriture et sa fermeture (avec fanotify en notification seule, qui ne peut jamais bloquer un autre processus). Une analyse périodique toutes les 6 heures couvre les événements perdus et les fichiers présents avant le démarrage. ClamAV n'est pas nécessaire.
Le comportement se règle dans /etc/roamswitch/web_rules.conf (propriétaire root, mode 0644 ; un fichier modifiable par d'autres est ignoré). Appliquez un changement avec sudo roamswitch server restart. Un modèle s'obtient avec roamswitch web-rules example conf.
| Clé | Signification (par défaut) |
|---|---|
quarantine | Niveau de quarantaine automatique. off n'isole jamais, critical seulement critical, high critical et high (par défaut : critical). Un résultat high au niveau critical ne fait que notifier et déclencher le hook ; le fichier n'est pas touché. |
account_action | Indique s'il faut révoquer le shell de connexion du propriétaire d'un fichier détecté. off / revoke_shell (par défaut : off). Seuls comptent les résultats critical ou high mis en quarantaine. root, les UID inférieurs à account_min_uid, les utilisateurs connectés et l'utilisateur du démon ne sont jamais touchés. L'ancien shell est enregistré et sudo roamswitch web-rules unlock-account <utilisateur> le rétablit. |
account_min_uid | account_min_uid : l'UID le plus bas sur lequel la réponse sur les comptes peut agir (1000 par défaut ; non réglable sous 100). |
scan_dirs, auto_docroots, watch, scan_interval_secs | scan_dirs (chemins absolus séparés par des virgules), auto_docroots (par défaut true ; false arrête la découverte automatique depuis la configuration du serveur web), watch (par défaut true ; false désactive la surveillance des écritures et ne garde que l'analyse périodique) et scan_interval_secs (par défaut 21600, minimum 3600). |
# /etc/roamswitch/web_rules.conf
quarantine=critical
account_action=off
account_min_uid=1000
#scan_dirs=/srv/sites/a,/srv/sites/b
auto_docroots=true
watch=true
scan_interval_secs=21600
Une détection envoie une notification (Telegram, LINE, webhook) qui nomme la règle et indique si le fichier a été mis en quarantaine ou laissé. Pour regarder sans rien déplacer, utilisez sudo roamswitch web-scan <dossier> (lecture seule ; --quarantine pour mettre en quarantaine) ou l'écran Outils de la TUI serveur. Vos règles vont dans /etc/roamswitch/rules.d/*.json. Pour appeler votre script après une détection, placez-le dans /etc/roamswitch/hooks/post-detection (le résultat arrive en JSON sur l'entrée standard ; seul un fichier appartenant à root, non modifiable par d'autres et placé dans un répertoire sûr est exécuté ; pas de shell, arrêt après 30 secondes). Les mises à jour des règles passent par la mise à jour quotidienne en réception seule. Avec cve_kernel_map_updates_enabled désactivé, il n'y a aucun contact réseau et les règles intégrées sont utilisées.