ROAMSWITCH SERVER 1.10.6 · Dernière mise à jour : 2026-09-26

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) .

Principe Zero Telemetry (aucune information sur vous n'est envoyée ; la seule communication externe par défaut est la réception de données signées)
RoamSwitch n’envoie ni les adresses IP de votre serveur, ni les informations de ports, ni les empreintes de fichiers, ni les journaux système, ni les résultats de diagnostic à l’éditeur ou à un quelconque cloud. Le binaire du démon ne contient lui-même aucun client TLS ou HTTP. Hors mises à jour du gestionnaire de paquets, le seul trafic qui quitte l’hôte par défaut est la récupération anonyme de données signées (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

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
Forfait Exclusion Mutuelle (Conflits)
Les éditions Client (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
  1. Ports : saisissez les ports de maintenance SSH (par défaut 22) et les ports de service publics (par défaut 80,443), séparés par des virgules.
  2. 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, saisissez ANYWHERE (le chemin SSH d'administration reste alors ouvert au monde entier, y compris pendant l'isolement).
  3. Canaux de notification : activez le bot Telegram, l'API Messaging LINE et/ou un webhook générique (Slack / Discord / Teams).
  4. Réaction à un événement eBPF critique : choisissez isolate (isoler l'hôte), freeze (geler le processus) ou alert_only (notification uniquement). Après l'enregistrement, il vous est proposé d'envoyer une notification de test et de redémarrer le service.
  5. Mise à jour automatique des données CVE (y par 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 un User-Agent: RoamSwitch-Updater fixe 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épondre n l’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 un server.conf existant, la réponse par défaut reste n.
  6. 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.
  7. 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.
  8. 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).
  9. 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.
Remarque sur l'ID de chat Telegram
L'ID de chat d'un super-groupe est un nombre négatif qui commence par -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 :

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).

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.

Garantie de sécurité en lecture seule
Pour empêcher les attaques par injection rapide de compromettre l'infrastructure, l'interface MCP est strictement en lecture seule. Les agents IA ne peuvent pas ouvrir de ports, supprimer l'isolation ou modifier les configurations de sécurité via MCP. La correction nécessite un accès au shell TTY local authentifié.

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.

Remarque sur l'injection de prompt
L'intégration investigation transmet les détails de l'incident (noms de processus, chemins de fichiers et chaînes semblables qu'un attaquant peut en partie contrôler) dans le prompt de l'agent d'IA, sous forme de chaînes JSON tronquées. Sous forme de chaînes JSON, les sauts de ligne et les guillemets ne permettent pas de simuler une ligne de séparation ni une fausse section d'instructions. Cela n'empêche pas le contenu d'une chaîne d'être lu comme une instruction ; l'agent ne peut donc pas s'exécuter en root : une configuration sans utilisateur non privilégié dans 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.

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.

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
languagesystem | ja | en | zh-hans | zh-hant | ko | de | fr | es | it | ptjaOui
ssh_portsport list22Oui
allowed_portsport list80,443Oui
whitelist_ipslist—Oui
preserve_ssh_on_isolationbooltrueOui
telegram_enabledboolfalseOui
telegram_bot_tokenstring—Oui
telegram_chat_idstring—Oui
line_enabledboolfalseOui
line_channel_access_tokenstring—Oui
line_user_idstring—Oui
webhook_enabledboolfalseOui
webhook_urlURL—Oui
webhook_block_private_addressesboolfalseOui
webhook_allow_addressesCIDR list—Oui
action_on_criticalisolate | freeze | alert_onlyisolateOui
ebpf_socket_pathabs path/run/roamswitch/events.sockOui
ebpf_heartbeat_interval_secs0 (off) | int 60–86400600Oui
isolation_hard_cap_secsint ≥ 03600Oui
fim_check_interval_secsint ≥ 10300Oui
fim_intrusion_context_enabledbooltrueOui
protect_docker_portsbooltrueOui
dns_sinkhole_enabledboolfalseOui
dns_sinkhole_providerquad9 | cloudflare | adguard | cleanbrowsingquad9Oui
egress_ip_blocklist_enabledbooltrueOui
metadata_watch_enabledbooltrueOui
metadata_watch_allow_userslist—Oui
cve_kernel_map_updates_enabledbooltrueOui
clamav_enabledboolfalseOui
clamav_scan_dirsabs path list—Oui
clamav_scan_interval_secsint ≥ 360086400Oui
clamav_freshclam_interval_secsint ≥ 18007200Oui
lockfile_watch_dirsabs path list—Oui
npm_audit_signatures_enabledboolfalseOui
log_audit_enabledbooltrueOui
log_audit_interval_secsint ≥ 3001800Oui
resource_guard_enabledbooltrueOui
resource_guard_rss_sample_interval_secsint ≥ 1060Oui
resource_guard_rss_window_secsint ≥ 3001800Oui
resource_guard_rss_min_samplesint ≥ 310Oui
resource_guard_rss_min_growth_pctint ≥ 1050Oui
resource_guard_rss_recovery_drop_pctint ≥ 110Oui
resource_guard_rss_min_kbint ≥ 020000Oui
resource_guard_crash_loop_window_secsint ≥ 60300Oui
resource_guard_crash_loop_min_restartsint ≥ 23Oui
resource_guard_correlation_window_secsint ≥ 60600Oui
resource_guard_zombie_min_countint ≥ 020Oui
resource_guard_load_min_normalizedfloat ≥ 0.00.5Oui
resource_guard_load_enabledbooltrueOui
resource_guard_cpu_enabledbooltrueOui
resource_guard_cpu_sample_interval_secsint ≥ 060Oui
resource_guard_cpu_window_secsint ≥ 0600Oui
resource_guard_cpu_min_samplesint ≥ 08Oui
resource_guard_cpu_pct_thresholdfloat 0.0–1000.080.0Oui
container_exec_guard_enabledbooltrueOui
port_scan_detect_enabledbooltrueOui
port_scan_detect_min_distinct_portsint ≥ 015Oui
port_scan_detect_window_secsint ≥ 0300Oui
port_scan_block_enabledbooltrueOui
port_scan_block_duration_secsint ≥ 0600Oui
ssh_guard_enabledbooltrueOui
ssh_guard_block_enabledbooltrueOui
ssh_guard_max_failuresint 2–10006Oui
ssh_guard_window_secsint 10–86400600Oui
ssh_guard_ban_secsint 60–25920003600Oui
ssh_guard_ban_max_secsint 60–31536000604800Oui
ssh_guard_allowIP/CIDR list—Oui
ssh_guard_log_sourceauto | journal | abs pathautoOui
ssh_guard_yield_to_fail2banbooltrueOui
ssh_guard_trust_key_daysint 0–365030Oui
dns_tunnel_detect_enabledbooltrueOui
reverse_shell_watch_enabledbooltrueOui
reverse_shell_watch_include_privateboolfalseOui
reverse_shell_watch_notify_onlyboolfalseOui
sensor_pairing_enabledboolfalseOui
sensor_colocatedboolfalseOui
forward_enabledboolfalseOui
forward_syslog_urlURL—Oui
forward_syslog_formatrfc5424 | cefrfc5424Oui
forward_syslog_framingoctet | lfoctetOui
forward_tls_ca_fileabs path—Oui
forward_file_pathabs path—Oui
forward_file_max_mbint 1–1000050Oui
forward_file_keepint 1–1005Oui
forward_webhook_urlURL—Oui
forward_webhook_secretstring—Oui
forward_webhook_secret_fileabs path—Oui
forward_webhook_block_private_addressesboolfalseOui
forward_webhook_allow_addressesCIDR list—Oui
forward_min_severityinfo | low | medium | high | criticallowOui
forward_queue_max_mbint 1–1000020Oui
forward_queue_max_age_hoursint 1–876072Oui
exec_recorder_enabledbooltrueOui
exec_recorder_retention_mbint 1–100000200Oui
exec_recorder_retention_daysint 1–365014Oui
exec_recorder_hash_chainbooltrueOui
exec_recorder_hash_exebooltrueOui
exec_recorder_cpu_budget_pctint 1–503Oui
exec_rules_enabledbooltrueOui
exec_rules_disabledstring—Oui
exec_rule_service_usersstring—Oui
exec_rule_window_secsint 5–3600120Oui
exec_rules_isolation_optinboolfalseOui
honeytokens_enabledbooltrueOui
honeytokens_homeabs path/rootOui
harden_userns_enabledbooltrueOui
dns_tunnel_entropy_allowlistlist—Oui
fleet_forwarding_allowed_hostslist—Oui
fleet_forwarding_allow_plaintextboolfalseOui

18.2 guard.yaml (37 clés)

Clé Type / valeurs Par défaut Redémarrage
sensor.typefalco | tetragonfalcoOui
sensor.transportstringunix_socketOui
sensor.socket_pathabs path/run/roamswitch/events.sockOui
sensor.reconnect_interval_msint 100–36000001000Oui
policies.on_warning.actionlog_and_notify | isolate_process | isolate_host_alllog_and_notifyOui
policies.on_warning.server_actionlog_and_notify | isolate_process | isolate_host_all—Oui
policies.on_warning.kill_processboolfalseOui
policies.on_warning.freeze_processboolfalseOui
policies.on_warning.fallback_to_host_isolation_after_retriesint 0–1000—Oui
policies.on_error.actionlog_and_notify | isolate_process | isolate_host_allisolate_processOui
policies.on_error.server_actionlog_and_notify | isolate_process | isolate_host_all—Oui
policies.on_error.kill_processboolfalseOui
policies.on_error.freeze_processboolfalseOui
policies.on_error.fallback_to_host_isolation_after_retriesint 0–1000—Oui
policies.on_critical.actionlog_and_notify | isolate_process | isolate_host_allisolate_processOui
policies.on_critical.server_actionlog_and_notify | isolate_process | isolate_host_all—Oui
policies.on_critical.kill_processbooltrueOui
policies.on_critical.freeze_processboolfalseOui
policies.on_critical.fallback_to_host_isolation_after_retriesint 0–10003Oui
policies.on_emergency.actionlog_and_notify | isolate_process | isolate_host_allisolate_host_allOui
policies.on_emergency.server_actionlog_and_notify | isolate_process | isolate_host_all—Oui
policies.on_emergency.kill_processbooltrueOui
policies.on_emergency.freeze_processboolfalseOui
policies.on_emergency.fallback_to_host_isolation_after_retriesint 0–1000—Oui
server_safeguards.allow_established_connectionsbooltrueOui
server_safeguards.maintenance_ssh_portsport list22Oui
server_safeguards.whitelist_cidrslist—Oui
server_safeguards.whitelist_dns_serverslist—Oui
server_safeguards.safety_timer_secsint ≥ 0300Oui
adaptive_security.enabledbooltrueOui
adaptive_security.untrusted_network_actions.elevate_falco_profilestring—Oui
adaptive_security.untrusted_network_actions.auto_enable_userns_restrictionboolfalseOui
investigation.enabledboolfalseOui
investigation.commandabs path—Oui
investigation.argslist—Oui
investigation.run_asstring—Oui
investigation.timeout_secsint 1–86400180Oui

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)
quarantineNiveau 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_actionIndique 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_uidaccount_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_secsscan_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.

← Livre blanc Server Edition Vers la page d'installation Linux →