Vue d’ensemble — à quoi cela sert
Diagnostic de sécurité exécute une analyse des traces de rootkit ainsi qu’une analyse de durcissement du système sur vos serveurs enregistrés, note chaque résultat sous forme d’un score de 0 à 100 assorti d’une note de A à F, et affiche sur un seul écran la posture de sécurité de l’ensemble de votre parc. Chaque contrôle est accompagné d’une explication quoi/pourquoi/comment corriger, et tout constat qui est un échec dont la sévérité est critique (fail + crit) est promu automatiquement en cas de Résolution des problèmes (dédoublonné, et résolu automatiquement dès que le contrôle passe de nouveau).
Composants principaux :
- Sonde
infr_seccheck_probe.cjs— un script Node qui s’exécute localement et en lecture seule sur l’hôte cible (sans identifiants). Il effectue 36 contrôles et produit du JSON. - Catalogue de référence
App\Support\SecurityCheckbook— détient les 9 catégories, les clés de contrôle, les pondérations et les sévérités (indépendant de la langue, compatible avec le cache). Les textes d’explication se trouvent dansresources/lang/{ko,en}/seccheck.php. - Moteur
App\Services\Security\DiagnosticsService— ingestion → notation → promotion/résolution des cas → agrégation du tableau de bord. - Stockage
infr_sec_scan(migration000766) — une ligne = une analyse d’un hôte ;findingsest stocké en ligne au format JSON.
Exécuter la sonde en tant que root active les contrôles privilégiés tels que
/etc/shadow,sudoersetsshd -T. Sans les droits root, les contrôles privilégiés sont rétrogradés enskipet exclus du dénominateur du score (aucune pénalité).
Quand l’utiliser
- Validation du durcissement de référence avant d’admettre un nouveau serveur en production.
- Tri rapide des traces de rootkit / porte dérobée sur un hôte suspect (processus cachés, injection dans
ld.so.preload, carte réseau en mode promiscuité, etc.). - Un rythme de conformité récurrent : une sonde quotidienne par cron qui pousse les scores via le rapporteur d’API afin d’accumuler automatiquement une tendance.
- Préparation aux audits : voir d’un coup d’œil quels hôtes utilisent un système d’exploitation en fin de vie, présentent des mises à jour de sécurité non appliquées ou autorisent la connexion SSH en root.
Disposition
| Zone | Contenu |
|---|---|
| Bandeau de KPI | Score moyen du parc · nombre d’hôtes analysés · cas critiques ouverts · total des contrôles en échec · heure de la dernière analyse |
| Répartition des notes | Histogramme du nombre d’hôtes A/B/C/D/F |
| Scores par catégorie | Consolidation des 9 catégories (moyenne du parc, ordre du catalogue, couleur de tonalité) |
| Tendance du score | Les 60 dernières analyses par ordre chronologique |
| Hôtes par note | Grille de cartes d’hôtes — triées du score le plus bas (le plus risqué) en premier. Chaque carte affiche la note, les compteurs pass/warn/fail/crit, la source d’entrée et l’heure de l’analyse. Clic → fenêtre de rapport |
| Fenêtre de rapport | Score et note globaux + résumé (SE/noyau) + détail par contrôle (quoi/pourquoi/correctif/preuve) + lien vers le cas promu |
Barre d’outils supérieure : [Lancer l’analyse] (exécution distante multi-serveurs) · [Coller le résultat] · Actualiser · Bascule d’actualisation automatique · Plein écran.
Comment l’utiliser
Quatre voies d’entrée
infr_sec_scan.source classe la manière dont une analyse a été reçue :
| source | Point d’entrée | Méthode |
|---|---|---|
emulate |
Fenêtre [Lancer l’analyse] | Sélectionnez les instances → déployez et exécutez la sonde à distance. Un collage ou une application d’émulation distante portant un instance_id est également enregistré comme emulate |
paste |
Fenêtre [Coller le résultat] | Collez le JSON de la sonde produit directement sur la cible, sans liaison à une instance |
api |
POST /api/v1/security/scan |
Le cron de chaque hôte exécute la sonde → envoie via une clé d’API (la voie du rapporteur) |
manual |
Repli | Valeur par défaut lorsque la valeur de source n’est pas valide |
1) Exécution distante multi-serveurs — interrogation asynchrone
Une exécution complète synchrone dépasserait le temps d’exécution de PHP sur de nombreux hôtes ; le flux est donc enregistrer → worker lancé sans attente → interroger.
- [Lancer l’analyse] → cochez les instances cibles (chacune indique joignable / injoignable).
POST /security/diagnostics/run→ crée un enregistrement de progression et renvoie immédiatementrun_id(Cache, TTL 30 min).- Le front end appelle
POST /security/diagnostics/run-worker/{runId}sans attendre → le worker traite tous les hôtes séquentiellement sousset_time_limit(0)etignore_user_abort(l’échec d’un hôte n’arrête pas les autres). - Le front end interroge
GET /security/diagnostics/run-status/{runId}pour mettre à jour la progression (done/total/ok).
Une instance marquée injoignable ne correspond à aucun nœud du collecteur
run_report: elle ne peut donc pas être exécutée à distance. Exécutez la sonde directement sur l’hôte et soumettez-la via [Coller le résultat]. Voir Émulation distante pour le câblage de l’exécution distante.
2) Collage / ingestion de JSON
Exécutez la sonde sur l’hôte cible et collez son JSON.
# Sur l’hôte cible (recommandé : root)
node infr_seccheck_probe.cjs --min
--min produit du JSON sur une seule ligne. Forme de la sortie :
{
"host": "web-01",
"generated_at": "2026-08-13T03:30:00Z",
"os": "Rocky Linux 9.3",
"kernel": "5.14.0-362.el9",
"root": true,
"checks": [
{ "key": "ssh_root_login", "category": "ssh", "status": "fail", "severity": "crit", "detail": "PermitRootLogin yes", "evidence": "/etc/ssh/sshd_config:32" },
{ "key": "svc_firewall", "category": "services", "status": "pass", "severity": "crit", "detail": "firewalld active" }
],
"summary": {}
}
C’est POST /security/diagnostics/ingest qui le reçoit. Lier une instance enregistre source=emulate ; laisser la liaison vide enregistre source=paste.
3) Rapporteur d’API (automatisation)
Le cron de chaque hôte exécute la sonde et pousse le résultat dans InfraGuard. Émettez la clé d’API dans Administration ▸ Clés API ; la clé doit porter la portée scan.write.
30 3 * * * node /opt/infr/infr_seccheck_probe.cjs --min | curl -sS -X POST https://infraguard.example.com/api/v1/security/scan -H "Authorization: Bearer YOUR_API_KEY" -H "Content-Type: application/json" --data @-
Réponse (201) :
{ "ok": true, "scan_id": 812, "host": "web-01", "score": 74, "grade": "C" }
Notation — SecurityCheckbook
Le score est un rapport pondéré de la pondération et du statut de chaque contrôle.
Facteur de statut (STATUS_FACTOR) — seuls ceux-ci comptent ; skip/info sont exclus du dénominateur :
| Statut | Facteur |
|---|---|
pass |
1.0 |
warn |
0.6 |
fail |
0.0 |
skip · info |
exclus |
Multiplicateur de sévérité (SEV_MUL) — plus l’implication d’un échec est lourde, plus il déplace le score :
| fail_severity | Multiplicateur |
|---|---|
crit |
1.6 |
warn |
1.0 |
info |
0.5 |
Pondération par contrôle w = check_weight(1–3) × severity_multiplier ; score global = round(100 × Σ(w × status_factor) / Σw). Les scores par catégorie utilisent la même formule au sein de chaque catégorie.
Note et tonalité :
| Score | Note | Tonalité |
|---|---|---|
| ≥ 90 | A | good |
| ≥ 80 | B | good |
| ≥ 70 | C | warn |
| ≥ 60 | D | warn |
| < 60 | F | crit |
(Les notes sont A/B/C/D/F ; la tonalité est good ≥ 80 · warn ≥ 60 · crit < 60.)
9 catégories · 36 contrôles
Chaque catégorie possède une pondération d’affichage et une icône ; la notation réelle utilise la pondération par contrôle × multiplicateur de sévérité ci-dessus.
| Catégorie | Libellé | Contrôles | Contrôles notables (implication en cas d’échec) |
|---|---|---|---|
rootkit |
Rootkit / logiciel malveillant | 6 | rk_known_files·rk_ld_preload·rk_hidden_proc (crit) |
patch |
Correctifs / mises à jour | 3 | pt_security_updates·pt_eol_os (crit) |
ssh |
Configuration SSH | 5 | ssh_root_login·ssh_empty_pass (crit) |
accounts |
Comptes / privilèges | 5 | acc_uid0·acc_empty_pass (crit) |
network |
Exposition réseau | 3 | net_legacy_services·net_db_exposed (crit) |
filesystem |
Permissions du système de fichiers | 5 | fs_shadow_perm (crit)·fs_world_writable·fs_suid (warn) |
hardening |
Durcissement du système | 5 | hd_selinux·hd_aslr·hd_syncookies (warn) |
services |
Services / pare-feu | 2 | svc_firewall (crit)·svc_unnecessary (info) |
logging |
Audit / journalisation | 2 | log_auditd·log_syslog (warn) |
Les clés inconnues sont absorbées dans la catégorie other. Le texte « quoi / pourquoi / correctif » de chaque contrôle est rendu dans la fenêtre de rapport depuis seccheck.check.*.
Constats critiques → promotion en Résolution des problèmes
À chaque ingestion, reconcileCases() réconcilie les cas de l’hôte.
- Seuls les constats avec
status = failETseverity = critsont promus. Clé de dédoublonnage : unfingerprintinterne. - S’il existe un cas ouvert, il incrémente
occurrence_count++etlast_occurred_at; sinon il crée un nouveau cas :infr_incident(area=security,source=detection,entity_type=seccheck,entity_key=host,severity=crit,status=open) ainsi qu’uninfr_incident_event(kind=created). - Résolution automatique : un cas auparavant ouvert qui n’est plus fail+crit dans cette analyse (corrigé ou plus détecté) passe en
status=resolvedavecresolved_atet une note de résolution automatique.
Les contrôles promus apparaissent dans la fenêtre de rapport avec un badge « promu en résolution » et un lien [Voir le cas]. Les cas se traitent sur le tableau Sécurité ▸ Résolution des problèmes.
Supprimer une analyse (
POST /security/diagnostics/delete) ne supprime pas les cas qu’elle a promus : ils sont indépendants.
Sources de données
| Source | Rôle |
|---|---|
infr_sec_scan (000766) |
Résultats d’analyse (un par hôte). JSON score·grade·pass/warn/fail/crit/total_count·category_scores·summary·findings. Index (host,scanned_at)·(instance_id,scanned_at)·grade·score |
infr_instance |
Instances cibles (résout host → instance_id par alias/hostname) |
infr_incident / infr_incident_event |
Cas critiques promus et leur chronologie |
infr_api_key |
Authentification du rapporteur d’API (portée scan.write) |
| Cache | Agrégat du tableau de bord mis en cache 20 s (infr:sec:diag:build) · enregistrement de progression de l’exécution asynchrone (TTL 1800 s) |
infr_seccheck_probe.cjs |
La sonde source (locale, en lecture seule) |
- Discipline d’agrégation : parmi les 500 analyses les plus récentes, ne conserver que la plus récente par hôte (dédoublonnage) → liste du parc, moyenne, consolidation par catégorie, tendance, nombre de critiques ouverts.
- La catégorie et la sévérité fournies par la sonde ne sont que des indications ; le serveur les renormalise comme valeurs de référence via
SecurityCheckbook.
Accès
- Lecture : nécessite l’accès au domaine de rôle Sécurité (dans le palier actuel, staff = 5 / admin = 10 ; demo = 1 ne voit pas le domaine Sécurité). Permet de consulter le tableau de bord et les rapports.
- Écriture (exécution / ingestion / suppression) : nécessite
infr_user_level >= 2en session (canWrite()). En dessous,run·ingest·deleterenvoient 403 (seccheck.toast.forbidden). - Rapporteur d’API : le middleware
infr.apikeyplus une clé portant la portéescan.write; sinon 403forbidden_scope. - Audit : toute écriture est consignée dans
infr_audit_log—sec.diag_run(nombre de cibles),sec.diag_ingest(scan_id·score·source),sec.diag_delete(id de l’analyse). Consultez le Journal d’audit.
Pour le modèle de niveaux en général (middleware infr.level:N), voir Niveaux RBAC.
Dépannage et FAQ
Q. Une instance apparaît « injoignable » dans [Lancer l’analyse].
Elle ne correspond à aucun nœud du collecteur run_report, il n’y a donc pas de câblage d’exécution distante. Exécutez la sonde directement sur l’hôte et soumettez-la via [Coller le résultat].
Q. Erreur « No checks found ».
Le JSON collé ne contient pas de tableau checks (ni items), ou ses entrées n’ont pas de key. Collez la sortie de infr_seccheck_probe.cjs --min telle quelle.
Q. Le score est faible alors que le nombre d’échecs est réduit.
C’est le multiplicateur de sévérité. Un échec crit pèse 1,6 fois un warn. Utilisez les scores par catégorie et la fenêtre de rapport pour repérer le constat qui tire le score vers le bas.
Q. Tous les contrôles privilégiés sont en skip.
La sonde a été exécutée avec un compte non root. Des contrôles comme /etc/shadow, sudoers ou sshd -T nécessitent root. skip est exclu du dénominateur (aucune pénalité), mais exécutez la sonde en root (ou via la passerelle) pour un diagnostic complet.
Q. Une exécution prend du temps — puis-je fermer le navigateur ?
Oui. Le worker est lancé sans attente et continue sous ignore_user_abort même si la requête est interrompue. Rouvrez et interrogez run-status, ou lisez simplement les notes une fois qu’elles apparaissent sur le tableau de bord. L’enregistrement de progression est conservé 30 minutes.
Q. Un cas a disparu de lui-même. Si une analyse ultérieure ne signale plus ce constat comme fail+crit (corrigé ou non détecté), le moteur résout automatiquement le cas. C’est le comportement attendu.
Voir aussi
- Sécurité ▸ Résolution des problèmes — flux de travail des cas critiques promus
- Émulation distante — déploiement de la sonde et câblage d’exécution multi-serveurs
- Clés API — clés de la voie du rapporteur (portée
scan.write) - Actifs ▸ Instances — le registre des instances de système d’exploitation cibles
- Sécurité ▸ Vue d’ensemble — le récit complet de l’entonnoir de défense
- Journal d’audit — historique des exécutions / ingestions / suppressions
