
🌐 Aussi en: English · Deutsch · Español
Un outil de contrôle d’intégrité ne vaut que par les e-mails qu’il envoie. S’il signale des centaines de modifications chaque matin, plus personne ne les lit au bout d’une semaine – et la seule vraie découverte se perd avec elles. C’était mon problème avec AIDE et rkhunter sur trois hôtes K3s : les deux fonctionnaient, mais ils signalaient surtout ce que j’avais moi-même provoqué.
Ce deep dive montre ce que font les deux outils, d’où vient le bruit sur un hôte Kubernetes et comment la base de référence suit chaque modification voulue.
🧾 Ce que fait AIDE
AIDE (Advanced Intrusion Detection Environment) construit une base de données : pour chaque fichier surveillé, il enregistre les sommes de contrôle, les droits, le propriétaire, la taille et les horodatages. Le contrôle quotidien compare le système de fichiers à cette base. Si quelqu’un modifie un programme dans /usr/bin ou une configuration dans /etc, cela se voit – même si l’attaquant a nettoyé les journaux.
Chez moi, il tourne une fois par jour et n’envoie un e-mail que s’il trouve réellement des différences. Deux détails le rendent utilisable au quotidien :
- Plusieurs threads : AIDE 0.19 sait calculer les empreintes en parallèle. Avec un seul thread, une passe prenait de 38 secondes à une minute et demie ; désormais, il utilise un thread par vCPU, avec une priorité basse.
- Le code de sortie est un masque de bits : 1 = fichiers ajoutés, 2 = supprimés, 4 = modifiés. Les valeurs de 1 à 7 signifient donc « différences trouvées » ; seul 14 ou plus indique une erreur d’AIDE lui-même. Le traiter comme un code d’erreur ordinaire, c’est interrompre justement quand AIDE a fait son travail – ce qui est arrivé à ma première version.
À retenir : AIDE ne dit pas « bon » ou « mauvais », mais « différent d’hier ». Qu’il s’agisse d’une découverte dépend de l’actualité de la base.
🐳 D’où vient le bruit sur un hôte K3s
Un hôte Kubernetes change en permanence sans que rien de suspect ne se produise. Trois endroits produisaient régulièrement des fausses alertes chez moi :
/var/log/pods: K3s crée un sous-répertoire à chaque démarrage de pod et à chaque exécution de CronJob. Cela modifie le nombre de liens du répertoire parent – AIDE le signalait pratiquement chaque jour./var/log/containers: un lien symbolique par conteneur vers/var/log/pods. Si un pod de CronJob est nettoyé pendant le contrôle, le lien pointe dans le vide, et l’e-mail commençait par « failed to access … »./boot/efi: un système de fichiers FAT qu’AIDE n’a pas le droit de lire sous SELinux. Il ignorait de toute façon la partition – mais chaque passe produisait une série de refus SELinux, 13 par passe sur un hôte.
Les deux premiers ne sont pas une cible de manipulation : ce sont des captures éphémères de la sortie des conteneurs, ni des programmes ni de la configuration. Ils sont donc exclus, chacun avec sa justification dans le code. Pour /boot/efi, l’exclusion ne suffit pas : AIDE interroge quand même les propriétés du système de fichiers avec statfs(). Un petit module SELinux local autorise exactement cet appel – lire les métadonnées du système de fichiers, pas un seul fichier. Les fichiers EFI viennent de paquets : rpm -V permet de les vérifier au besoin.
À retenir : les exclusions sont acceptables tant que chacune a une justification. « C’est agaçant » n’en est pas une – « c’est éphémère et ce n’est pas une cible d’attaque », si.
🔄 La base doit suivre
La plupart des fausses alertes venaient pourtant de moi. Toute modification voulue – une mise à jour de paquet, une nouvelle règle de pare-feu, un nouveau binaire K3s – est d’abord un écart pour AIDE. Sur mes hôtes, trois chemins modifient des fichiers surveillés, et chacun a besoin de sa propre mise à jour de la base :
- Les exécutions d’Ansible : le dernier rôle de chaque playbook s’appelle
common_aide_refresh. Il lanceaide --update, qui vérifie et écrit la nouvelle base en une seule passe. Auparavant, c’était un contrôle suivi d’une mise à jour, donc deux analyses complètes par exécution. - Les mises à jour de sécurité nocturnes : dnf-automatic installe des mises à jour la nuit, sans Ansible. Après un changement de noyau, AIDE a signalé le lendemain 3 273 fichiers ajoutés, 3 273 supprimés et 364 modifiés – l’ancien noyau en moins, le nouveau en plus. Depuis, une mise à jour séparée de la base tourne à 04:00, après la fenêtre de mise à jour et le redémarrage éventuel de 03:30.
- Les modifications à la main : qui modifie quelque chose en dehors de ces deux chemins doit déclencher la mise à jour lui-même. Ma règle : après chaque exécution de playbook avec
--tags, lancer aussi--tags common_rkhunter,common_aide_refresh– une exécution avec tags saute le dernier rôle.
Le troisième chemin est le plus délicat. Quand j’ai récemment installé un noyau à la main dans l’après-midi, le contrôle de minuit – avant la mise à jour de 04:00 – aurait signalé exactement ce noyau.
À retenir : chaque chemin par lequel un système change a besoin d’une mise à jour adaptée de la base. S’il en manque un, la fausse alerte arrive à coup sûr.
🦠 rkhunter : un deuxième avis avec ses particularités
rkhunter (Rootkit Hunter) fonctionne de manière similaire, avec un autre objectif : il compare les programmes système importants à sa propre base de propriétés et recherche les traces de rootkits connus. Lui aussi a besoin d’une base à jour, créée par rkhunter --propupd.
Trois choses ont été nécessaires pour qu’il se taise :
- Un plugin dnf plutôt qu’un crochet sur le minuteur : après chaque transaction dnf qui a réellement modifié des paquets, un petit plugin lance
rkhunter --propupd. Ma première solution était accrochée au service de dnf-automatic et ne se déclenchait donc que pour les mises à jour nocturnes, pas pour undnf upgrademanuel. - Une seule analyse par nuit : le paquet EPEL apporte son propre script dans
/etc/cron.daily. Avec ma propre entrée cron, chaque hôte faisait deux analyses complètes par nuit – et un avertissement donnait deux e-mails. Le script du paquet a disparu, et un réglage rpm (%_netsharedpath) empêche la prochaine mise à jour de rkhunter de le remettre. - Des tests désactivés, chacun avec sa raison : certains tests ne conviennent pas à AlmaLinux 9 ou à K3s – le test de configuration SSH, avec un bug connu de rkhunter 1.4.6, ou les tests de modules, qui cherchent au mauvais endroit après un changement de noyau. Chaque test désactivé figure avec sa justification dans le rôle.
Un détail pour le principe de dérive : --propupd renouvelle une base dérivée, pas une configuration. La tâche ne signale donc jamais « changed » – sinon chaque exécution du playbook ressemblerait à une dérive.
À retenir : un paquet apporte parfois sa propre idée de l’exploitation. Qui planifie lui-même doit désactiver volontairement la planification fournie – et s’assurer qu’elle ne revient pas.
💓 Qui contrôle le contrôleur ?
Un contrôle d’intégrité silencieux n’est utile que s’il tourne vraiment. « Pas d’e-mail » peut vouloir dire deux choses : tout va bien – ou la tâche ne tourne plus. Chacune de ces tâches écrit donc à la fin un horodatage (un battement de cœur) pour Prometheus, et une règle d’alerte se déclenche quand l’un d’eux devient trop ancien.
La mise en place de ces battements de cœur a fait apparaître deux vieilles erreurs :
- Sur un hôte, un second contrôle AIDE créé à la main tournait à 05:00 – dans aucun rôle ni aucun dépôt, sur un seul thread et en double.
- Les e-mails adressés au simple destinataire
rootn’arrivaient jamais. Le relais les acceptait, mais msmtp ne connaît pas d’alias locaux, et sans domaine l’e-mail n’allait nulle part. Depuis, chaque alerte part vers une adresse complète.
À retenir : le silence n’est pas une preuve. Un outil de contrôle a lui-même besoin d’un contrôle : qu’il tourne et que ses e-mails arrivent.
🎯 Les leçons
- Une alerte doit avoir un sens – sinon personne ne la lit.
- Des exclusions seulement avec une justification – les journaux éphémères des conteneurs oui, « agaçant » non.
- Chaque chemin de modification a besoin de sa mise à jour de la base – Ansible, mises à jour nocturnes et travail manuel.
- Vérifier les planifications fournies – un paquet peut apporter une seconde analyse.
- Surveiller le contrôleur – un battement de cœur par tâche, des e-mails vers de vraies adresses.
Plus de contexte sur SELinux sur ces hôtes dans le deep dive SELinux, la surveillance des tâches dans la partie 6 de la visite Ansible.

