Tracer et contrôler l'intégrité : auditd et AIDE
Pourquoi
Un mardi matin, la mairie signale que l'export CSV de la nuit contient des colonnes inattendues. En cherchant, vous découvrez que /etc/signalements/export.toml sur sig-outils a été modifié il y a trois semaines. Par qui ? Camille, avant son départ ? Un collègue qui a dépanné un soir d'astreinte ? Quelqu'un qui n'aurait jamais dû avoir accès à la machine ? La date de modification du fichier dit quand, pas qui, et elle se falsifie avec un simple touch. Le journal de sudo dit qu'un compte a lancé sudoedit, mais pas forcément sur quel fichier, et rien si la personne a ouvert un shell root avec sudo -i puis travaillé dedans pendant une heure.
Cette leçon répond à trois questions que l'on se pose toujours trop tard :
- Qui a fait quoi ? Une trace des actions sensibles, rattachée à une personne et non à
root. - Qu'est-ce qui a changé ? Une liste fiable des fichiers modifiés depuis un état de référence connu, y compris par quelqu'un qui aurait pris soin de ne rien laisser dans les journaux.
- Peut-on le prouver ? Une trace qui survit à la machine et à son administrateur indélicat, utilisable après un incident, devant un auditeur ou, dans le pire des cas, devant un juge.
Ce n'est pas une curiosité de spécialiste. Le guide BP-028 de l'ANSSI demande d'assurer « l'imputabilité des actions d'administration » dès le niveau intermédiaire (R33), de journaliser l'activité du système avec auditd au niveau renforcé (R73), et de sceller les fichiers en protégeant la base de scellement au niveau élevé (R76, R77). NIS2, qui concerne désormais de nombreuses collectivités et leurs prestataires, impose détection et gestion des incidents ; ISO 27001 et PCI DSS exigent journalisation et détection des changements. Le jour d'un incident, la première question de l'ANSSI, de la CNIL ou de l'assureur sera « que s'est-il passé, et depuis quand ? ».
Sans ces outils, la réponse honnête est « nous ne savons pas », et la seule option sûre devient de tout reconstruire en supposant le pire.
Les concepts
Trois mécanismes complémentaires
Les trois questions appellent trois outils différents, qu'il ne faut pas confondre :
| Outil | Ce qu'il observe | Quand | Ce qu'il ne voit pas |
|---|---|---|---|
| auditd (sous-système d'audit du noyau) | les appels système et accès aux fichiers que vous avez choisi de surveiller, avec l'identité de l'auteur | en temps réel, au moment de l'action | ce qui n'est pas couvert par une règle ; ce qui se passe avant son démarrage |
| AIDE (scellement) | l'état des fichiers (contenu, droits, propriétaire, attributs) comparé à une base de référence | périodiquement, par exemple chaque nuit | qui a fait le changement, ni quand exactement |
| Enregistrement des sessions sudo | ce qui s'affiche dans le terminal d'une commande lancée par sudo | en temps réel | ce qui ne passe pas par sudo (connexion directe, tâche automatisée) |
auditd dit qui et quand, AIDE dit quoi sans dépendre de ce que l'attaquant a laissé dans les journaux, et l'enregistrement de session redonne le contexte : ce que la personne voyait quand elle a tapé ses commandes. Aucun ne suffit seul.
Le sous-système d'audit du noyau
Le noyau Linux contient, depuis la version 2.6, un sous-système d'audit : des points de contrôle placés à l'entrée et à la sortie des appels système, dans les fonctions de vérification des droits sur les fichiers, et dans quelques chemins sensibles (chargement de module, changement d'identité, modification de la configuration d'audit elle-même). Quand une action correspond à une règle, le noyau fabrique un enregistrement (record) et le place dans une file d'attente.
Un programme de l'espace utilisateur, auditd, le démon d'audit, lit cette file par une socket netlink (un canal de communication entre le noyau et un processus), écrit les enregistrements dans /var/log/audit/audit.log, et les transmet à des greffons (plugins) : l'un les envoie à syslog, un autre à une machine distante. Autour de lui gravitent les outils :
auditctl: parle au noyau, pour charger des règles, lire l'état, régler les paramètres ;augenrules: assemble les fichiers de règles de/etc/audit/rules.d/en un seul fichier et le charge ;ausearchetaureport: cherchent dans le journal et en tirent des rapports.
flowchart LR
P[Processus<br/>appel système] --> K[Noyau<br/>filtres d'audit]
K -->|enregistrements| Q[File kauditd<br/>backlog]
Q -->|netlink| D[auditd]
D --> F[/var/log/audit/audit.log/]
D --> G[Greffons :<br/>syslog, remote]
G --> R[sig-outils]
Q -.->|multicast| J[systemd-journald]
Le journal d'audit (journal d'audit) n'est pas un journal applicatif de plus : il est produit par le noyau, que le processus surveillé ne peut ni contourner ni falsifier, puisqu'il ne fait qu'exécuter des appels système.
Les règles : contrôle, fichiers, appels système
Une règle d'audit s'écrit exactement comme les arguments d'auditctl. Il en existe trois sortes :
- Les règles de contrôle règlent le sous-système :
-D(supprimer toutes les règles),-b 8192(taille de la file d'attente du noyau),-f 1(que faire en cas d'échec),-e 2(verrouiller la configuration). - Les règles de surveillance de fichiers déclenchent un enregistrement quand un fichier ou un répertoire est lu, écrit, exécuté ou voit ses attributs changer. La forme historique est
-w /etc/sudoers -p wa -k sudoers: surveiller (watch)/etc/sudoers, pour les accès en écriture (w) et les changements d'attributs (a), et marquer les événements de la clé (key)sudoers. - Les règles d'appels système déclenchent un enregistrement quand un appel donné se termine et que des conditions (
-F) sont vraies :-a always,exit -F arch=b64 -S execve -F euid=0 -k root-cmdse lit « toujours (always), à la sortie de l'appel (exit), pour les appels 64 bits, quand l'appel estexecveet que l'identité effective est root, produire un événement de cléroot-cmd».
La clé est une étiquette libre de 31 octets au plus. Elle ne change rien au filtrage, mais c'est elle qui permettra de retrouver les événements : ausearch -k sudoers. Une règle sans clé produit des événements que personne ne saura chercher.
Important
La forme -w est notée « deprecated due to poor system performance » dans la page auditctl(8) de la version 4 d'audit (Debian 13). Celle de la version 3.1.2 (Ubuntu 24.04) la présente encore comme une forme de compatibilité, moins expressive. Les deux versions acceptent la forme moderne, équivalente : -a always,exit -F arch=b64 -F path=/etc/sudoers -F perm=wa -F key=sudoers (et -F dir= pour un répertoire). C'est celle que cette leçon utilise, pour que les mêmes fichiers de règles servent sur sig-app-1 et sur sig-outils.
auid : l'identité qui survit à sudo
C'est la notion qui donne tout son intérêt à l'audit. Quand Alex se connecte en SSH sur sig-app-1 puis tape sudo -i, son shell tourne avec l'UID 0. Pour le noyau, ce shell est root ; les UID réel, effectif et sauvegardé valent tous 0. Si l'audit ne connaissait que ces identités, toutes les actions d'administration seraient signées « root », c'est-à-dire par personne.
Le noyau conserve donc une identité de plus, attachée à chaque processus : le loginuid, que les outils d'audit appellent auid (audit user ID). Il est fixé une fois, au moment de la connexion, par le module PAM pam_loginuid (présent dans les configurations PAM de sshd, login et cron sur Debian et Ubuntu), qui écrit l'UID de la personne authentifiée dans /proc/self/loginuid. Ensuite, il est hérité par tous les descendants et n'est pas modifié par sudo, su, ni par un programme setuid. La page pam_loginuid(8) insiste : il ne faut pas l'utiliser pour sudo ou su, « as that defeats the purpose ». Un shell obtenu par sudo -i a donc uid=0 mais auid=1001 (Alex), et chacune de ses commandes porte la signature d'Alex.
Les processus lancés au démarrage par systemd n'ont jamais traversé de connexion : leur auid est non défini, représenté par 4294967295 (soit -1 sur 32 bits), ou par le mot unset dans les règles. C'est ce qui permet de distinguer les humains des services : -F auid>=1000 -F auid!=unset sélectionne « les actions qui remontent à une connexion humaine », en écartant Gunicorn, cron sans session, et le démon d'audit lui-même. Le numéro de session (ses=), fixé en même temps, regroupe toutes les actions d'une même connexion.
Un processus root peut-il réécrire son loginuid ? Par défaut, un processus doté de la capability CAP_AUDIT_CONTROL le peut. La règle de contrôle --loginuid-immutable rend le loginuid non modifiable une fois fixé : c'est l'une des premières règles des fichiers d'exemple d'audit.
Le verrouillage : -e 2
auditctl -e 2 met la configuration d'audit en mode immuable : plus aucune règle ne peut être ajoutée ni retirée, l'audit ne peut plus être désactivé, et toute tentative est elle-même journalisée puis refusée. Il faut redémarrer la machine pour changer les règles. Sans ce verrou, un attaquant devenu root commence par auditctl -D et devient invisible ; avec, il doit redémarrer le serveur, ce qui se remarque.
Le scellement des fichiers
Le scellement consiste à calculer, sur un système dans un état connu et sain, une empreinte de chaque fichier important (contenu haché, droits, propriétaire, taille, inode, attributs étendus), à ranger ces empreintes dans une base de référence, puis à recalculer régulièrement et comparer. Toute différence est signalée : fichier ajouté, supprimé, modifié. AIDE (Advanced Intrusion Detection Environment) est l'outil libre le plus répandu pour cela, avec Tripwire et Samhain, que l'ANSSI cite aussi.
Le point faible est évident : un attaquant root peut modifier un binaire puis régénérer la base. La recommandation R77 de l'ANSSI en tire la conséquence : la base doit être signée avec une clé qui n'est pas stockée en clair sur la machine, ou conservée sur une autre machine.
En pratique
Les commandes ci-dessous visent sig-app-1 (Ubuntu 24.04) ; les différences avec sig-outils (Debian 13) sont signalées. Elles n'ont pas été exécutées pour produire cette leçon : les sorties sont reconstituées d'après la documentation et le code source, et introduites comme telles.
Installer auditd et lire l'état du noyau
$ sudo apt install auditd
$ systemctl status auditd
$ sudo auditctl -s
Le paquet auditd installe le démon, auditctl, augenrules, ausearch, aureport et le greffon syslog ; le greffon d'envoi distant est dans audispd-plugins. Le service est activé et démarré à l'installation. auditctl -s interroge le noyau. Sortie typique :
enabled 1
failure 1
pid 812
rate_limit 0
backlog_limit 8192
lost 0
backlog 0
backlog_wait_time 60000
backlog_wait_time_actual 0
loginuid_immutable 0 unlockedLigne par ligne :
enabled 1: l'audit est actif ;2signifierait verrouillé.failure 1: en cas de problème grave (file pleine, mémoire), le noyau écrit un message (printk) ;0serait le silence,2la panique du noyau.pid: le PID d'auditd ;0indique que le démon ne tourne pas, et les événements partent alors dans le tampon du noyau.backlog_limit: la taille de la file ; la valeur par défaut du noyau est 64, beaucoup trop faible, d'où le-b 8192des règles livrées.lost: le nombre d'enregistrements perdus depuis le démarrage. Toute valeur non nulle est un trou dans votre traçabilité.backlog: le nombre d'enregistrements en attente à cet instant.
sudo auditctl -l liste les règles chargées. Juste après l'installation, la réponse est No rules : auditd tourne, mais ne surveille presque rien. Seuls quelques événements câblés dans le noyau (connexions, changements d'identité, modifications de la configuration d'audit) sont produits sans règle.
Écrire les règles de Signalements
Les règles persistantes vivent dans /etc/audit/rules.d/, un fichier par thème. augenrules concatène les fichiers en .rules dans l'ordre de tri naturel de leur nom, retire commentaires et lignes vides, et produit /etc/audit/audit.rules, qu'on ne modifie jamais à la main. Il place de lui-même -D en première ligne, -b en deuxième, -f en troisième et -e en dernière, quel que soit le fichier d'où elles viennent.
Le paquet fournit /etc/audit/rules.d/audit.rules, qui contient seulement des règles de contrôle. Remplacez-le par une organisation lisible, inspirée des fichiers d'exemple livrés dans /usr/share/doc/auditd/examples/ (sous-répertoire rules/ sur Ubuntu 24.04, audit-rules/ sur Debian 13) :
/etc/audit/rules.d/10-base.rules :
## Repartir de zéro, puis dimensionner la file du noyau
-D
-b 8192
--backlog_wait_time 60000
## En cas d'échec : message noyau, pas de panique
-f 1
## L'identité de connexion ne peut plus être modifiée une fois fixée
--loginuid-immutable/etc/audit/rules.d/20-exclusions.rules :
## chrony ajuste l'horloge en permanence : ne pas noyer les vraies modifications
-a never,exit -F arch=b64 -S adjtimex -F auid=unset -F uid=_chrony/etc/audit/rules.d/30-signalements.rules :
## Comptes et groupes
-a always,exit -F arch=b64 -F path=/etc/passwd -F perm=wa -F key=identite
-a always,exit -F arch=b64 -F path=/etc/shadow -F perm=wa -F key=identite
-a always,exit -F arch=b64 -F path=/etc/group -F perm=wa -F key=identite
-a always,exit -F arch=b64 -F path=/etc/gshadow -F perm=wa -F key=identite
## Droits d'administration
-a always,exit -F arch=b64 -F path=/etc/sudoers -F perm=wa -F key=sudoers
-a always,exit -F arch=b64 -F dir=/etc/sudoers.d -F perm=wa -F key=sudoers
## Accès distant
-a always,exit -F arch=b64 -F path=/etc/ssh/sshd_config -F perm=wa -F key=sshd
-a always,exit -F arch=b64 -F dir=/etc/ssh/sshd_config.d -F perm=wa -F key=sshd
## Application : configuration, secrets, unité systemd
-a always,exit -F arch=b64 -F dir=/etc/signalements -F perm=wa -F key=signalements-conf
-a always,exit -F arch=b64 -F dir=/etc/systemd/system -F perm=wa -F key=unites
## La configuration d'audit elle-même
-a always,exit -F arch=b64 -F dir=/etc/audit -F perm=wa -F key=audit-conf
## Modules du noyau
-a always,exit -F arch=b64 -S init_module,finit_module -F key=module-load
-a always,exit -F arch=b64 -S delete_module -F key=module-unload
## Heure système
-a always,exit -F arch=b64 -S adjtimex,settimeofday,clock_settime -F key=heure
## Toute commande exécutée en root par un humain
-a always,exit -F arch=b64 -S execve,execveat -F euid=0 -F auid>=1000 -F auid!=unset -F key=root-cmd
## Appels système 32 bits : anormaux sur ce serveur
-a always,exit -F arch=b32 -S all -F key=32bit-abi/etc/audit/rules.d/99-finalize.rules :
## Verrouiller : plus aucune modification avant le prochain redémarrage
-e 2Quelques explications, ligne par ligne :
-F arch=b64avant-S. Les numéros d'appels système diffèrent entre les jeux 32 et 64 bits ;auditctldoit savoir quelle table utiliser pour traduireexecveen numéro, d'où la consigne de la pageaudit.rules(7)de placerarchavant-S. Sur une instance Arm de Scaleway,b64désigne le jeu natif aarch64 etb32le mode de compatibilité 32 bits ; les règles restent valables.- La dernière règle est une parade : un programme peut, sur x86_64, faire des appels système par l'interface 32 bits, et échapper ainsi à toutes les règles
b64. Plutôt que de dupliquer chaque règle enb32, comme le font les exemples officiels, on journalise toute utilisation de cette interface, qu'aucun logiciel desig-app-1n'utilise normalement. perm=wa: écriture et changement d'attributs (droits, propriétaire). Une lecture de/etc/shadown'est pas tracée ici ; on pourrait ajouterr, au prix d'un événement à chaque authentification.-F dir=couvre le répertoire et tout ce qu'il contient, récursivement.- La règle
root-cmdreprend l'esprit de la recommandation R33 de l'ANSSI, qui propose de journaliser tous lesexecve: on se limite ici aux exécutions en root qui remontent à une connexion humaine, ce qui écarte l'immense majorité du bruit produit par les services. - L'exclusion de chrony : le jeu d'exemples officiel en contient une (
22-ignore-chrony.rules), mais elle filtre aussi sur un contexte SELinux (subj_type=chronyd_t) qui n'existe pas sur Debian et Ubuntu. Le nom du compte de chrony (_chronysur Debian et Ubuntu) se vérifie avecps -o user= -C chronyd. Elle est dans un fichier numéroté avant celui des règles de surveillance pour une raison expliquée dans « Sous le capot ».
Vérifiez puis chargez :
$ sudo augenrules --check
$ sudo augenrules --load
$ sudo auditctl -l
--check dit si /etc/audit/audit.rules doit être régénéré, sans rien changer. --load le régénère si nécessaire et charge les règles dans le noyau. auditctl -l affiche les règles telles que le noyau les a comprises : la règle root-cmd y apparaît par exemple avec -F auid>=1000 -F auid!=-1, ce qui est la même chose.
Au démarrage, les règles sont chargées automatiquement. Sur Ubuntu 24.04 (audit 3.1.2), c'est une ligne ExecStartPost=-/sbin/augenrules --load de auditd.service qui s'en charge ; sur Debian 13 (audit 4.0.2), une unité distincte, audit-rules.service, dont auditd.service dépend.
Warning
Ne posez -e 2 qu'une fois les règles validées. Après le chargement, toute correction exige un redémarrage du serveur. Pendant la mise au point, commentez la ligne de 99-finalize.rules.
Provoquer et lire un événement
Sur sig-app-1, Alex (UID 1001) redémarre le service :
$ sudo systemctl restart signalements
Le journal brut contient alors un événement composé de plusieurs enregistrements qui partagent le même horodatage et le même numéro de série. Sortie typique, dans /var/log/audit/audit.log (champs abrégés) :
type=SYSCALL msg=audit(1791386592.418:5821): arch=c000003e syscall=59 success=yes exit=0 a0=55d0c3b2e8a8 a1=55d0c3b2e1f0 a2=55d0c3b2e208 a3=0 items=2 ppid=48211 pid=48212 auid=1001 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts0 ses=7 comm="systemctl" exe="/usr/bin/systemctl" key="root-cmd"
type=EXECVE msg=audit(1791386592.418:5821): argc=3 a0="systemctl" a1="restart" a2="signalements"
type=CWD msg=audit(1791386592.418:5821): cwd="/home/alex"
type=PATH msg=audit(1791386592.418:5821): item=0 name="/usr/bin/systemctl" inode=1574 dev=fc:01 mode=0100755 ouid=0 ogid=0 rdev=00:00 nametype=NORMAL
type=PATH msg=audit(1791386592.418:5821): item=1 name="/lib64/ld-linux-x86-64.so.2" inode=2219 dev=fc:01 mode=0100755 ouid=0 ogid=0 rdev=00:00 nametype=NORMAL
type=PROCTITLE msg=audit(1791386592.418:5821): proctitle=73797374656D63746C0072657374617274007369676E616C656D656E7473Comment le lire :
msg=audit(1791386592.418:5821): horodatage en secondes depuis le 1er janvier 1970 (ici le 7 octobre 2026 à 15:23:12 UTC), millisecondes, puis numéro de série de l'événement. Tous les enregistrements portant le même couple forment un événement.SYSCALL: l'appel lui-même.arch=c000003ecode l'architecture x86_64,syscall=59estexecvesur cette architecture,success=yes exit=0dit qu'il a réussi,a0àa3sont les quatre premiers arguments, en hexadécimal (des adresses mémoire, inutiles ici).items=2annonce deux enregistrementsPATH. Puis les identités :auid=1001(Alex, qui s'est connecté),uid=0 euid=0(root, qui exécute),ses=7(la session SSH d'Alex),tty=pts0. Enfincomm, le nom court du processus,exe, le chemin du binaire, etkey, la clé de la règle qui a déclenché l'événement.EXECVE: les arguments de la commande. Un argument contenant des espaces, des guillemets ou des caractères non imprimables est écrit en hexadécimal, sans guillemets.CWD: le répertoire courant.PATH: chaque fichier touché par l'appel. Pour unexecve, le binaire et l'éditeur de liens dynamique. On y lit l'inode, le périphérique, les droits et le propriétaire au moment de l'appel.PROCTITLE: la ligne de commande complète, toujours en hexadécimal parce qu'elle contient des octets nuls entre les arguments. Ici,systemctl restart signalements.
Vous trouverez aussi, juste avant, un événement presque identique pour /usr/bin/sudo, avec uid=1001 euid=0 : sudo est setuid root, donc son propre execve se termine avec une identité effective nulle et correspond à la règle. Les deux événements racontent l'histoire complète : Alex a lancé sudo, qui a lancé systemctl en root.
Sur Debian et Ubuntu, le format par défaut est log_format = ENRICHED : chaque ligne se termine par un caractère de séparation (0x1D, invisible dans la plupart des terminaux) suivi de champs en majuscules déjà traduits, comme AUID="alex" UID="root" SYSCALL=execve. Ils sont calculés au moment de l'écriture, ce qui fige le nom correspondant à l'UID ce jour-là, même si le compte est supprimé ensuite.
Chercher avec ausearch
Personne ne lit audit.log à la main. ausearch assemble les enregistrements en événements et sait les traduire :
$ sudo ausearch -k root-cmd -i --start today
$ sudo ausearch -k sudoers -i --start recent
$ sudo ausearch -ul alex -i --start 14:00:00 --end 16:00:00
$ sudo ausearch -f /etc/signalements -i
$ sudo ausearch -m USER_LOGIN -sv no -i --start this-week
-kfiltre par clé,-ulpar identité de connexion (auid),-uapar n'importe laquelle des identités,-fpar nom de fichier,-mpar type d'enregistrement,-sv nosur les échecs ;-i(interpret) traduit les nombres : UID en noms, architecture et appel système en clair,PROCTITLEdécodé ;--startet--end(ou-ts,-te) acceptent une date et une heure dans le format de la locale, ou des mots-clés :recent(les dix dernières minutes),today,boot,this-week,week-ago,this-month.
Plusieurs critères se combinent par un ET logique. Sortie typique de la première commande, réduite à l'événement précédent :
----
type=PROCTITLE msg=audit(10/07/26 15:23:12.418:5821) : proctitle=systemctl restart signalements
type=PATH msg=audit(10/07/26 15:23:12.418:5821) : item=1 name=/lib64/ld-linux-x86-64.so.2 inode=2219 dev=fc:01 mode=file,755 ouid=root ogid=root rdev=00:00 nametype=NORMAL
type=PATH msg=audit(10/07/26 15:23:12.418:5821) : item=0 name=/usr/bin/systemctl inode=1574 dev=fc:01 mode=file,755 ouid=root ogid=root rdev=00:00 nametype=NORMAL
type=CWD msg=audit(10/07/26 15:23:12.418:5821) : cwd=/home/alex
type=EXECVE msg=audit(10/07/26 15:23:12.418:5821) : argc=3 a0=systemctl a1=restart a2=signalements
type=SYSCALL msg=audit(10/07/26 15:23:12.418:5821) : arch=x86_64 syscall=execve success=yes exit=0 items=2 ppid=48211 pid=48212 auid=alex uid=root gid=root euid=root tty=pts0 ses=7 comm=systemctl exe=/usr/bin/systemctl key=root-cmdLa date suit la locale (%x) : 10/07/26 est le format de la locale C, mois en premier. Avec --format csv ou --format text, ausearch produit des sorties plus faciles à exploiter dans un tableur ou un rapport d'incident.
Tip
Pour reconstituer tout ce qu'une personne a fait pendant une connexion, cherchez d'abord sa session : sudo ausearch -m USER_LOGIN -ul alex -i donne le numéro ses=, puis sudo ausearch --session 7 -i affiche toute la session, connexion, commandes et déconnexion.
Résumer avec aureport
aureport produit des tableaux de synthèse, utiles pour une revue hebdomadaire :
$ sudo aureport --summary -i
$ sudo aureport -k --summary
$ sudo aureport -au --failed -i
$ sudo aureport -l -i --start week-ago
$ sudo aureport -m -i
-k résume par clé, -au liste les tentatives d'authentification, -l les connexions, -m les modifications de comptes, --failed et --success filtrent sur le résultat. Sortie typique de aureport -k --summary :
Key Summary Report
===========================
total key
===========================
412 root-cmd
37 unites
6 signalements-conf
2 sudoersUne clé sudoers ou identite qui apparaît dans le résumé de la semaine alors qu'aucun changement n'était prévu mérite d'être expliquée. C'est exactement ce que fait la revue des accès (revue des accès) côté traces.
Régler auditd.conf : traçabilité contre disponibilité
/etc/audit/auditd.conf règle le démon. Les valeurs livrées par Debian et Ubuntu sont celles du projet amont, à une exception près : un correctif Debian remplace log_group = root par log_group = adm, de sorte que les membres du groupe adm lisent le journal d'audit.
log_file = /var/log/audit/audit.log
log_format = ENRICHED
log_group = adm
flush = INCREMENTAL_ASYNC
freq = 50
max_log_file = 8
num_logs = 5
max_log_file_action = ROTATE
space_left = 75
space_left_action = SYSLOG
admin_space_left = 50
admin_space_left_action = SUSPEND
disk_full_action = SUSPEND
disk_error_action = SUSPENDmax_log_file(en Mio) etnum_logs: le journal tourne à 8 Mio, et cinq fichiers sont conservés. Sur un serveur où la règleroot-cmdest active, 40 Mio peuvent ne couvrir que quelques jours.max_log_file_action = keep_logstourne sans jamais supprimer, ce qui reporte le problème sur l'espace disque.space_leftpuisadmin_space_left(en Mio, ou en pourcentage avec%) : deux seuils d'alerte sur l'espace libre de la partition du journal, avec leurs actions.disk_full_actionetdisk_error_action: ce que fait auditd quand il ne peut plus écrire.
Les actions possibles posent le vrai choix de cette section. suspend arrête l'écriture mais garde le démon en vie : le service continue, la traçabilité s'arrête. single bascule la machine en mode mono-utilisateur, halt l'arrête : la traçabilité est garantie, au prix du service. Pour Signalements, une API publique dont l'indisponibilité gêne les agents de la voirie, SUSPEND assorti d'une alerte est le choix raisonnable. Pour un bastion d'administration ou un système qui traite des données classifiées, un arrêt plutôt qu'une action non tracée peut être exigé. C'est une décision de sécurité, à écrire dans la fiche du serveur, pas un réglage technique anodin.
Deux précautions découlent de ce choix : placer /var/log/audit sur un système de fichiers dédié, pour qu'un journal applicatif emballé ne le prive pas d'espace (leçon 6), et surveiller les messages d'auditd, comme Audit daemon is low on disk space for logging ou Audit daemon is suspending logging due to no space left on logging partition., qui doivent déclencher une alerte.
Après une modification d'auditd.conf, demandez au démon de relire sa configuration :
$ sudo auditctl --signal reload
--signal envoie au démon le signal correspondant : reload (HUP), rotate (USR1, rotation immédiate), resume (USR2, reprendre l'écriture après une suspension, une fois l'espace libéré).
Auditer dès le démarrage
Un processus créé avant l'activation de l'audit n'est jamais complètement audité. Par défaut, le noyau initialise l'audit sans l'activer et attend auditd. Le paramètre audit=1 sur la ligne de commande du noyau l'active dès le début, et audit_backlog_limit=8192 évite de perdre les enregistrements produits avant le démarrage du démon. Sur Ubuntu et Debian, ajoutez-les dans un fragment de configuration de GRUB plutôt que dans /etc/default/grub (leçon 2) :
$ echo 'GRUB_CMDLINE_LINUX="$GRUB_CMDLINE_LINUX audit=1 audit_backlog_limit=8192"' | sudo tee /etc/default/grub.d/90-audit.cfg
$ sudo update-grub
Après le redémarrage, cat /proc/cmdline doit contenir les deux paramètres. À l'inverse, audit=0 désactive l'audit jusqu'au redémarrage suivant, et les unités d'auditd refusent alors de démarrer (ConditionKernelCommandLine=!audit=0) : vérifiez que personne ne l'a ajouté.
Faire sortir les événements de la machine
Un journal d'audit resté sur sig-app-1 n'a aucune valeur face à un attaquant root : il peut l'effacer, et -e 2 ne protège que les règles, pas le fichier. Les événements doivent partir au moment où ils sont produits vers sig-outils, qui reçoit déjà les journaux depuis la leçon 12. Deux voies existent.
Par syslog, la voie recommandée ici. Le greffon audisp-syslog remet chaque événement à syslog, et rsyslog, déjà configuré à la leçon 12 pour émettre vers sig-outils en TCP chiffré avec TLS et file d'attente sur disque, fait le reste. Modifiez /etc/audit/plugins.d/syslog.conf :
active = yes
direction = out
path = /sbin/audisp-syslog
type = always
args = LOG_INFO LOG_LOCAL6
format = stringactive = yes active le greffon, args donne la priorité et la catégorie (facility) syslog. La catégorie local6 permet à sig-outils de ranger ces messages dans un fichier à part et de leur appliquer une rétention propre. /sbin est un lien vers /usr/sbin sur les deux distributions. Évitez l'argument interpret : la page audisp-syslog(8) prévient qu'un analyseur naïf peut alors être trompé par un attaquant qui choisit les noms de ses fichiers ou de ses processus. Rechargez auditd (auditctl --signal reload).
Par audisp-remote, la voie native. Le paquet audispd-plugins fournit audisp-remote, qui envoie les événements à un auditd distant configuré pour écouter (tcp_listen_port = 60 dans l'auditd.conf de sig-outils). Ses réglages, dans /etc/audit/audisp-remote.conf, sont soignés : mode = forward avec une file sur disque (/var/spool/audit/remote.log par défaut), network_failure_action, heartbeat_timeout. Mais son seul transport chiffré est Kerberos (transport = KRB5) ; il n'y a pas de TLS. Sans infrastructure Kerberos, les événements traversent le réseau privé pn-signalements en clair. C'est acceptable sur un réseau privé maîtrisé, moins si l'on vise la défense en profondeur. Si vous choisissez cette voie, l'unité d'auditd doit en outre démarrer après le réseau : un commentaire de l'unité amont décrit la surcharge à écrire (After=network-online.target).
Sur sig-outils, une règle rsyslog range les messages de la catégorie local6 par hôte d'origine, avec les droits restreints au groupe des personnes chargées de la sécurité. Le format de ces fichiers est celui d'audit.log précédé de l'en-tête syslog : ausearch -if <fichier> sait encore les lire si l'on retire cet en-tête, et les outils de centralisation savent les analyser.
Note
systemd-journald reçoit aussi une copie des enregistrements d'audit par une socket dédiée, systemd-journald-audit.socket, quand celle-ci est active. journalctl _TRANSPORT=audit -n 5 dit si c'est le cas. Cette copie double le volume du journal et n'est pas une solution de conservation : la source de vérité reste auditd.
Sceller les fichiers avec AIDE
Sur sig-app-1 :
$ sudo apt install aide
Le paquet (aide et aide-common) crée un compte système _aide, installe la configuration dans /etc/aide/aide.conf et ses fragments dans /etc/aide/aide.conf.d/, et un minuteur systemd, dailyaidecheck.timer, qui lance une vérification chaque nuit (vers 1 h 50, avec un délai aléatoire de deux heures au plus, sur Debian 13). Les réglages du travail quotidien sont dans /etc/default/aide.
Important
Le binaire aide de Debian et d'Ubuntu est compilé sans fichier de configuration par défaut. Appelez-le toujours avec --config /etc/aide/aide.conf, ou passez par les scripts du paquet (aideinit, dailyaidecheck). Sans cette option, aide --check échoue avec missing 'database_in', config option is required.
La configuration fournie par Debian est volontairement « paranoïaque », selon son propre README : elle surveille tout le système de fichiers, avec des règles adaptées aux fichiers qui changent légitimement (journaux, bases, caches). Ajoutez les fichiers de Signalements dans un fragment, par exemple /etc/aide/aide.conf.d/90_aide_signalements (sans point dans le nom : le paquet ne lit que les noms acceptés par run-parts) :
# Code et configuration : tout changement doit être signalé
/opt/signalements/venv f Full
/opt/signalements f Full
/etc/signalements f Full
# Les pièces jointes changent sans cesse : hors scellement
!/var/lib/signalements/pieces-jointesUne ligne de sélection associe un chemin (qui commence toujours par /, et qui est une expression régulière), un type de fichier facultatif (f pour les fichiers ordinaires, d pour les répertoires) et un groupe d'attributs. Full est défini dans aide.conf : propriétaire, droits, type, nombre de liens, inode, taille, attributs étendus, dates de modification et de changement, et toutes les empreintes disponibles. ! exclut un chemin et tout ce qu'il contient. Vérifiez la syntaxe, puis créez la base de référence :
$ sudo aide --config /etc/aide/aide.conf --config-check
$ sudo aideinit -y -f
--config-check lit la configuration et s'arrête, en signalant les erreurs. aideinit parcourt le système, écrit la nouvelle base dans /var/lib/aide/aide.db.new, puis, avec -f, la copie en /var/lib/aide/aide.db, la base de référence ; -y accepte d'écraser une base existante. Le parcours prend plusieurs minutes et sollicite fortement le disque : faites-le hors des heures de pointe.
Vérifiez à la demande :
$ sudo aide --config /etc/aide/aide.conf --check
Après une modification de /etc/signalements/export.toml, la sortie ressemble à ceci (extrait) :
Start timestamp: 2026-10-07 16:02:41 +0000 (AIDE 0.18.6)
AIDE found differences between database and filesystem!!
Summary:
Total number of entries: 152370
Added entries: 0
Removed entries: 0
Changed entries: 1
---------------------------------------------------
Changed entries:
---------------------------------------------------
f ... .C...: /etc/signalements/export.toml
---------------------------------------------------
Detailed information about changes:
---------------------------------------------------
File: /etc/signalements/export.toml
Size : 1214 | 1263
Mtime : 2026-09-12 08:14:03 +0000 | 2026-10-07 15:41:22 +0000
Ctime : 2026-09-12 08:14:03 +0000 | 2026-10-07 15:41:22 +0000
SHA256 : 3d1N2lX0... | qP8sY7c2...Le résumé compte les entrées ajoutées, supprimées et modifiées. La ligne codée de la section « Changed entries » indique, colonne par colonne, quels attributs ont changé ; sa légende exacte dépend des options de compilation et figure dans aide.conf(5), à la rubrique report_summarize_changes. La section détaillée, plus lisible, donne l'ancienne valeur à gauche et la nouvelle à droite. Le code de sortie se lit comme un masque : 1 pour des entrées ajoutées, 2 pour des supprimées, 4 pour des modifiées, additionnés (7 pour les trois) ; 14 et au-delà signalent une erreur d'AIDE lui-même (17 : erreur de configuration, 18 : erreur d'entrée-sortie). Un script de surveillance doit distinguer les deux.
Après un changement légitime, une mise à jour de paquets ou une livraison de Signalements, il faut accepter le nouvel état. La bonne méthode passe par --update, qui vérifie et écrit une nouvelle base dans aide.db.new :
$ sudo aide --config /etc/aide/aide.conf --update
$ sudo cp /var/lib/aide/aide.db.new /var/lib/aide/aide.db
Lisez le rapport avant de copier : c'est la dernière occasion de remarquer qu'à côté des 214 fichiers modifiés par apt upgrade, un 215e n'appartient à aucun paquet. Le README Debian recommande cette méthode plutôt qu'une réinitialisation, précisément pour cette raison. Le travail quotidien du paquet fait déjà un --update (réglage COMMAND=update), mais ne copie jamais la nouvelle base de lui-même (COPYNEWDB=no) : chaque changement reste signalé chaque nuit tant que personne ne l'a accepté. Les rapports sont écrits dans /var/log/aide/aide.log.
Protéger la base, enfin. Une copie dans /var/lib/aide est à la merci de root. Organisez le stockage hors de la machine selon un modèle « tiré » : c'est sig-outils qui vient chercher la base après chaque acceptation, la range avec son empreinte SHA-256, et la refournit avant chaque vérification, de sorte qu'un sig-app-1 compromis ne puisse pas écraser la référence conservée ailleurs. Les rapports nocturnes, eux, partent avec les autres journaux.
Sur sig-outils (Debian 13, AIDE 0.19.1), tout ce qui précède s'applique à l'identique, avec un service supplémentaire, dailyaidecheck-buildcache.service, lancé avant la vérification.
Vérifier les fichiers des paquets : dpkg --verify et debsums
Pour un contrôle rapide, sans base préalable, dpkg compare les fichiers installés aux empreintes MD5 enregistrées à l'installation de chaque paquet :
$ sudo dpkg --verify
$ sudo dpkg --verify openssh-server
La commande n'affiche que les fichiers qui diffèrent. Sortie typique :
??5?????? c /etc/ssh/sshd_config
??5?????? /usr/sbin/sshdLes neuf premiers caractères suivent le format de rpm -V : ? signifie « contrôle non effectué », et un 5 en troisième position signale que l'empreinte du contenu ne correspond plus ; la page dpkg(1) précise que c'est actuellement le seul contrôle réellement effectué. Le c marque un fichier de configuration (conffile), qu'il est normal d'avoir modifié. Un binaire comme /usr/sbin/sshd modifié hors de toute mise à jour, en revanche, est un signal d'alerte grave. Le paquet debsums offre le même service avec d'autres options (debsums -s pour n'afficher que les erreurs, -a pour inclure les fichiers de configuration, -l pour lister les paquets sans empreintes).
Ces deux outils ont la même limite, que la page debsums(1) énonce elle-même : les empreintes sont stockées sur la machine, dans /var/lib/dpkg/info/, donc modifiables par root, et MD5 n'est plus résistant aux collisions. Ils servent à repérer une modification maladroite ou une corruption, pas à résister à un attaquant ; ils renvoient d'ailleurs vers AIDE pour cela.
Enregistrer les sessions sudo
Le journal de sudo (leçon 8 de Linux : premiers pas) note la commande lancée. Quand la commande est un shell, il ne dit rien de ce qui s'est passé dedans ; l'audit dit quelles commandes ont été exécutées, mais pas ce qu'elles ont affiché. L'option log_output de sudo enregistre la sortie du terminal :
$ sudo visudo -f /etc/sudoers.d/90-journal-sessions
Defaults log_output
Defaults!/usr/bin/sudoreplay !log_outputLa première ligne enregistre la sortie de toutes les commandes lancées par sudo ; la seconde exclut sudoreplay lui-même, pour ne pas enregistrer la relecture d'un enregistrement. sudo exécute alors la commande dans un pseudo-terminal et écrit, par défaut, sous /var/log/sudo-io/, un répertoire par session nommé d'après un numéro de séquence en base 36 (00/00/01, 00/00/02...), en droits 0600. Pour retrouver et relire :
$ sudo sudoreplay -l user alex fromdate "last week"
$ sudo sudoreplay 00/00/2A
-l liste les sessions correspondant à l'expression (user, command, runas, cwd, fromdate, todate). Chaque ligne ressemble à ceci :
Oct 7 15:20:41 2026 : alex : TTY=/dev/pts/0 ; CWD=/home/alex ; USER=root ; TSID=00/00/2A ; COMMAND=/bin/bashSans option, sudoreplay rejoue la session à la vitesse réelle ; -s 4 l'accélère, -m 1 plafonne les pauses à une seconde.
log_input existe aussi, pour enregistrer les frappes. La page sudoers(5) met en garde : un mot de passe tapé dans la session, même sans écho à l'écran, se retrouve alors en clair dans l'enregistrement. Ne l'activez qu'en connaissance de cause. Pour centraliser ces enregistrements, sudo sait les envoyer directement à un serveur sudo_logsrvd (option log_servers, port 30344 en TLS) ; à défaut, ils doivent être collectés avec les autres journaux. Sur la famille Red Hat, tlog enregistre les sessions de terminal entières, avec ou sans sudo, et les envoie au journal ; il n'est pas empaqueté pour Debian et Ubuntu.
Sous le capot
Le contexte d'audit. À la création de chaque processus, le noyau évalue la liste de règles task. Une règle -a never,task (que certains fichiers d'exemple installent, comme 10-no-audit.rules) indique que ce processus et ses descendants n'auront pas de contexte d'audit : aucune règle d'appel système ne pourra jamais s'appliquer à eux. Pour les autres, le noyau alloue une structure (le contexte d'audit) qu'il remplit à l'entrée de chaque appel système : numéro, arguments, identités. Pendant l'appel, les fonctions de résolution de chemins y accrochent les fichiers rencontrés (les futurs PATH). À la sortie, le noyau parcourt la liste exit : si une règle correspond, il construit les enregistrements à partir du contexte et les met en file.
La première règle qui correspond gagne. Dans la liste exit, le noyau s'arrête à la première règle dont toutes les conditions sont vraies, et applique son action, always ou never. C'est pourquoi les exclusions (never) se placent avant les règles qu'elles tempèrent, et pourquoi 20-exclusions.rules précède 30-signalements.rules : si l'ordre était inversé, la règle heure capterait les ajustements de chrony avant que l'exclusion ne soit examinée. -a ajoute une règle en fin de liste, -A en tête.
Pourquoi les règles coûtent cher. Une règle d'appel système est évaluée à la sortie de chaque appel de chaque processus audité, qu'il s'agisse de Gunicorn qui lit une socket ou de PostgreSQL qui écrit une page. Le noyau précalcule, pour chaque règle, l'ensemble des appels concernés, ce qui écarte vite les règles sans rapport ; d'où les conseils des pages de manuel : toujours préciser arch, regrouper plusieurs appels dans une même règle (-S execve,execveat), et réserver les règles d'appels système aux cas où elles sont nécessaires. Les règles path= et dir= sont traitées autrement : le noyau les rattache à l'inode surveillé, par le mécanisme de notification de fichiers, et ne les examine que pour les appels qui touchent cet inode. La surveillance d'un répertoire très actif peut néanmoins produire un volume énorme.
La file d'attente et les pertes. Les enregistrements attendent dans une file du noyau, lue par le fil noyau kauditd, qui les envoie à auditd par netlink en unicast, et en multicast aux autres lecteurs comme journald. Si auditd ne suit pas (disque lent, rafale d'événements), la file grossit jusqu'à backlog_limit. Au-delà, les processus qui produisent des événements sont mis en attente pendant au plus backlog_wait_time, ce qui ralentit la machine, puis les enregistrements sont perdus. Le noyau l'écrit dans son tampon, sous la forme audit: audit_backlog=8193 > audit_backlog_limit=8192, suivi de audit: audit_lost=12 audit_rate_limit=0 audit_backlog_limit=8192 et audit: backlog limit exceeded. Avec -f 2, une perte provoquerait une panique du noyau : c'est le réglage des systèmes où une action non tracée est pire qu'un arrêt.
L'immuabilité du loginuid. Sans --loginuid-immutable, l'écriture dans /proc/<pid>/loginuid est autorisée à un processus doté de CAP_AUDIT_CONTROL, ce qui permettrait à root de se faire passer pour un autre auid. Avec cette option, le noyau refuse toute modification d'un loginuid déjà fixé. Un effet de bord : les conteneurs qui lancent leur propre sshd avec pam_loginuid ne peuvent plus le faire, raison pour laquelle l'option n'est pas activée par défaut.
L'arrêt d'auditd et l'auid. En amont, auditd.service porte RefuseManualStop=yes : systemctl stop auditd est refusé, et la documentation de Red Hat demande de passer par la commande service, pour que l'auid de la personne qui arrête le démon soit enregistré plutôt que celui de systemd. Debian (et donc Ubuntu) retire cette ligne par un correctif, pour que le démon puisse être redémarré lors des mises à jour du paquet ; le correctif reconnaît d'ailleurs que l'arrêt est alors attribué au PID de systemd. Sur vos serveurs, systemctl restart auditd fonctionne donc, mais l'arrêt d'auditd devient moins bien attribué : une raison de plus pour alerter sur tout événement DAEMON_END reçu par sig-outils.
Comment AIDE compare. La base est un fichier texte compressé (gzip_dbout=yes), une ligne par fichier. À la vérification, AIDE parcourt le système selon le même arbre de règles, recalcule et compare. Entre deux passages, un fichier peut être modifié puis restauré sans laisser de trace dans AIDE : c'est l'audit, en temps réel, qui couvre cet intervalle. Sur Debian et Ubuntu, la vérification quotidienne tourne sous le compte _aide, avec la seule capability CAP_DAC_READ_SEARCH, qui l'autorise à lire tous les fichiers sans être root.
Pièges courants
The audit system is in immutable mode, no rule changes allowed. Vous avez posé -e 2, puis voulu corriger une règle avec augenrules --load. C'est le comportement voulu : modifiez les fichiers de /etc/audit/rules.d/, vérifiez avec augenrules --check, puis planifiez un redémarrage (leçon 4). Pendant la mise au point, laissez -e 2 commenté.
Les règles ne sont pas chargées après un redémarrage. Une seule ligne invalide fait échouer le chargement : auditctl s'arrête avec un message comme Option -x on line 12 is invalid, ou une erreur sur un appel système inconnu pour l'architecture. Sur Debian 13, audit-rules.service est alors en échec, et auditd.service aussi, puisqu'il en dépend (Requires=), un choix délibéré de l'unité amont « to be sure to get your attention ». Sur Ubuntu 24.04, le chargement se fait par une ligne ExecStartPost=- dont le tiret fait ignorer l'échec : auditd tourne, sans vos règles. Dans les deux cas, sudo auditctl -l après chaque redémarrage, et une vérification automatique du nombre de règles chargées.
Un nom d'appel système inconnu. -S stime existe en 32 bits mais pas sur x86_64, et plusieurs appels anciens n'existent pas sur aarch64 (open, creat, rename, remplacés par openat, renameat). Une règle copiée d'un guide écrit pour x86_64 échoue sur une instance Arm. ausyscall --dump liste les appels de l'architecture courante.
Oublier le filtre auid!=unset. -F auid>=1000 seul inclut 4294967295, puisque ce nombre est supérieur à 1000 : tous les services démarrés par systemd entrent dans la règle, et le volume explose. Les deux conditions vont ensemble.
Le journal d'audit qui sature. Une règle trop large (-S openat sans filtre, surveillance de /var/lib/signalements) produit des milliers d'événements par seconde. Symptômes : lost qui grimpe dans auditctl -s, des messages backlog limit exceeded dans dmesg, une latence de l'API en hausse, et des journaux qui tournent si vite que les cinq fichiers ne couvrent que quelques heures. Identifiez la règle bavarde avec aureport -k --summary, puis resserrez-la par des filtres (auid, exe=, success=0) ou des exclusions never placées avant elle.
missing 'database_in', config option is required. AIDE lancé sans --config sur Debian ou Ubuntu : le binaire n'a pas de configuration par défaut. Ajoutez --config /etc/aide/aide.conf.
Des rapports AIDE de milliers de lignes chaque matin. La base n'a jamais été mise à jour après les mises à jour automatiques de la nuit (unattended-upgrades), donc chaque rapport répète tous les changements depuis l'initialisation. Personne ne les lit plus, et le jour où un vrai binaire est remplacé, il passe inaperçu dans le bruit. Il faut un processus : après chaque mise à jour ou livraison, revue du rapport puis acceptation (--update et copie). Réglez aussi les exclusions des répertoires qui changent légitimement.
Croire que dpkg --verify est un contrôle d'intégrité de sécurité. Il lit des empreintes MD5 stockées sur la machine même. Un attaquant qui remplace /usr/sbin/sshd peut mettre à jour /var/lib/dpkg/info/openssh-server.md5sums dans la foulée.
Des enregistrements sudo qui contiennent des secrets. Avec log_output, un cat du fichier d'environnement de Signalements affiche la DATABASE_URL et son mot de passe, qui se retrouvent dans /var/log/sudo-io/, puis dans la centralisation. Avec log_input, ce sont les mots de passe tapés. Protégez ces enregistrements comme des secrets, et préférez sudoedit à cat sous sudo.
Sécurité
- Les traces locales ne prouvent rien face à root. Un attaquant root peut effacer
audit.log, arrêter auditd (s'il n'a pas posé-e 2), réécrire la base AIDE et les enregistrements sudo. Seule la copie partie en temps réel vers une autre machine, à laquelle les comptes desig-app-1n'ont pas accès en écriture, a valeur de preuve. Sursig-outils, les comptes qui administrent les serveurs d'application ne doivent pas pouvoir modifier les traces reçues : c'est le principe de séparation des rôles. - Le journal d'audit est une donnée personnelle. Il associe des actions horodatées à des personnes nommées : c'est un traitement au sens du RGPD, soumis à une finalité (sécurité du système), une durée de conservation définie (voir la politique de rétention et la leçon 12 pour les recommandations de la CNIL sur la journalisation), une information des personnes concernées (charte d'administration) et un accès restreint. La surveillance des administrateurs est légitime ; elle doit être annoncée et proportionnée.
- Qui lit le journal d'audit. Sur Debian et Ubuntu,
log_group = admdonne la lecture d'audit.logà tout le groupeadm, qui peut contenir plus de monde que prévu (le premier compte créé sur Ubuntu en fait partie). Le journal d'audit contient les arguments de commandes, donc parfois des secrets passés en ligne de commande. Vérifiezgetent group adm, ou repassezlog_groupàroot. - Surveillez la surveillance. Les événements qui doivent déclencher une alerte immédiate sur
sig-outils:DAEMON_ENDouDAEMON_ABORT(auditd arrêté),CONFIG_CHANGE(règles modifiées), les clésaudit-conf,sudoers,identite,module-load,32bit-abi, et l'absence de messages d'un serveur pendant plus de quelques minutes. Un attaquant compétent ne déclenche pas d'alerte : il coupe le flux. - Le scellement suppose un état initial sain. Une base AIDE construite sur une machine déjà compromise scelle la compromission. Initialisez la base juste après l'installation ou la reconstruction, avant toute exposition.
En production
- Partez d'un référentiel, puis taillez. Les fichiers d'exemple (OSPP, PCI DSS, STIG) et le guide de l'ANSSI, appliqués en entier, produisent un volume que personne n'analysera. Commencez par les clés qui répondent à une question précise, mesurez une semaine avec
aureport -k --summary, puis ajoutez. Et désignez qui lit les rapports et les alertes : un dispositif que personne n'exploite ne vaut rien. - Les règles sont du code. Les fichiers de
/etc/audit/rules.d/,auditd.conf, les fragments AIDE et les réglages sudo se déploient par l'outil d'automatisation (cours Ansible : les fondamentaux), identiques sursig-app-1etsig-app-2, versionnés, revus. Un écart entre deux machines censées être identiques est en soi un signal. - Dimensionnez le transport et le stockage. La règle
root-cmdsur un serveur administré à la main produit peu ; la même sur un nœud où un outil de configuration lance des centaines de commandes en root toutes les trente minutes produit beaucoup. Prévoyez la place sursig-outils, et une rétention conforme à ce que vous avez déclaré. - AIDE et l'infrastructure immuable s'accordent bien. Sur des serveurs reconstruits à chaque livraison (infrastructure immuable), la base AIDE peut être produite au moment de la fabrication de l'image et conservée hors de la machine : tout écart en production est alors suspect, sans « changement légitime » à trier.
- Dans les conteneurs et sur Kubernetes. Le sous-système d'audit est global au noyau : sur un nœud Kapsule, auditd voit les appels système des conteneurs, mais leur auid est non défini, et les identités sont celles des espaces de noms. Pour les charges conteneurisées, on se tourne plutôt vers le journal d'audit de l'API Kubernetes et vers des outils fondés sur eBPF (Falco, Tetragon), qui rattachent les événements aux pods.
- Testez la chaîne de bout en bout. Une fois par trimestre : modifiez un fichier surveillé sur
sig-app-2, vérifiez que l'événement arrive sursig-outils, que l'alerte part, que le rapport AIDE du lendemain le signale, et que vous savez retrouver l'auteur. C'est l'équivalent, pour la traçabilité, d'un test de restauration de sauvegarde (leçon 16).
Exercices
1. Lire un événement (niveau 100). Voici un enregistrement SYSCALL (abrégé) trouvé sur sig-app-2 : type=SYSCALL msg=audit(1791320400.112:9921): arch=c000003e syscall=257 success=yes exit=3 items=2 ppid=7710 pid=7744 auid=1004 uid=0 euid=0 tty=pts1 ses=12 comm="vim" exe="/usr/bin/vim.basic" key="sudoers". Que s'est-il passé, et qui en est responsable ?
Solution
Un processus vim a ouvert avec succès (success=yes, exit=3 est le descripteur de fichier obtenu) un fichier surveillé par une règle de clé sudoers ; l'appel 257 est openat sur x86_64 (ausyscall 257 le confirme). Il tournait en root (uid=0 euid=0), mais l'auid vaut 1004 : la personne qui s'est connectée avec l'UID 1004 a obtenu les droits root, probablement par sudo, puis a édité un fichier de sudoers. getent passwd 1004 donne son nom, et sudo ausearch --session 12 -i reconstitue toute sa session, connexion comprise, ainsi que les enregistrements PATH du même événement qui donnent le nom exact du fichier. L'auteur est la personne de l'UID 1004, pas « root ».
2. Une règle et son test (niveau 200). Écrivez une règle persistante qui trace toute modification du fichier d'unité et des surcharges de Signalements (/etc/systemd/system/signalements.service et /etc/systemd/system/signalements.service.d/) avec la clé unite-signalements, chargez-la, provoquez un événement et retrouvez-le.
Solution
Dans /etc/audit/rules.d/30-signalements.rules, avant la règle plus large sur /etc/systemd/system (sinon, la première règle qui correspond étant retenue, l'événement porterait la clé unites) :
-a always,exit -F arch=b64 -F path=/etc/systemd/system/signalements.service -F perm=wa -F key=unite-signalements
-a always,exit -F arch=b64 -F dir=/etc/systemd/system/signalements.service.d -F perm=wa -F key=unite-signalementsPuis sudo augenrules --check, sudo augenrules --load (impossible si -e 2 est déjà actif : il faudra redémarrer), et sudo auditctl -l -k unite-signalements pour voir les règles chargées. Test : sudo systemctl edit signalements, ajouter une ligne, enregistrer. Recherche : sudo ausearch -k unite-signalements -i --start recent. L'événement montre un PATH sur le fichier override.conf, comm=systemctl et l'auid de la personne. Notez que systemctl edit écrit dans un fichier temporaire puis le renomme : plusieurs événements apparaissent, dont un rename.
3. Le disque plein (niveau 300). Un vendredi soir, le système de fichiers de /var/log/audit sur sig-app-1 atteint 100 %. Avec la configuration par défaut, que se passe-t-il pour l'API et pour la traçabilité ? Le RSSI de la collectivité demande que plus aucune action d'administration ne puisse avoir lieu sans trace. Que proposez-vous, et à quel prix ?
Solution
Avec disk_full_action = SUSPEND, auditd cesse d'écrire et journalise Audit daemon is suspending logging due to no space left on logging partition. ; l'API continue de répondre, mais plus aucune action n'est tracée localement jusqu'à ce que de l'espace soit libéré et que l'on envoie sudo auditctl --signal resume. Si les greffons continuent d'émettre vers sig-outils, une partie de la trace survit, mais rien ne le garantit.
Pour satisfaire l'exigence du RSSI, on peut régler admin_space_left_action = single et disk_full_action = halt (ou single) : la machine s'arrête plutôt que de fonctionner sans trace. Le prix : un incident disque devient une indisponibilité de l'API. C'est supportable parce que sig-app-2 prend le relais derrière le répartiteur, à condition que les deux machines ne saturent pas en même temps (rétention, volume et alertes identiques). Il faut aussi réduire le risque à la source : partition dédiée à /var/log/audit, space_left réglé pour alerter des heures avant, rotation adaptée au volume réel, et alerte sur space_left_action = email ou exec. La décision et sa justification vont dans la fiche du serveur.
4. Le binaire suspect (niveau 300). Le rapport AIDE de cette nuit sur sig-outils signale /usr/bin/curl comme modifié (taille, Mtime, SHA256), alors qu'aucune mise à jour n'a eu lieu selon /var/log/apt/history.log. Décrivez votre démarche, de la première vérification à la décision.
Solution
- Ne pas accepter le changement et ne pas mettre à jour la base.
- Croiser les sources.
dpkg --verify curl: un5en troisième position confirme que le contenu ne correspond plus à l'empreinte du paquet (en gardant à l'esprit que ces empreintes sont locales).dpkg -S /usr/bin/curlconfirme le paquet propriétaire. Comparer l'empreinte SHA-256 du fichier avec celle du même paquet téléchargé ailleurs (apt download curlsur une autre machine, puisdpkg-deb -x). - Chercher l'auteur. Sur
sig-outils, dans la copie centralisée plutôt que locale :ausearch -f /usr/bin/curl -iet les événementsroot-cmdautour de la date de modification indiquée par le rapport, puis la session (--session) et les enregistrements sudo correspondants. - Comparer avec la base protégée. Vérifier que la base AIDE utilisée est bien celle conservée hors machine (empreinte SHA-256), pour écarter une base altérée.
- Décider. Si la modification n'est pas expliquée, traiter la machine comme compromise : l'isoler (groupe de sécurité Scaleway), préserver les preuves (instantané du volume), prévenir le RSSI et, selon la gravité, l'ANSSI ou le CERT de rattachement, puis reconstruire à partir d'une image saine plutôt que « réparer » le binaire. Un binaire modifié est rarement la seule modification.
Récapitulatif
- auditd répond à « qui, quand », AIDE à « qu'est-ce qui a changé », l'enregistrement sudo à « qu'a-t-on vu à l'écran ». Les trois se complètent.
- Le sous-système d'audit est dans le noyau ; auditd écrit
/var/log/audit/audit.loget alimente des greffons. Les règles persistantes vont dans/etc/audit/rules.d/*.rules, assemblées et chargées paraugenrules --load. - Règles de fichiers :
-a always,exit -F arch=b64 -F path=... -F perm=wa -F key=...(la forme-west déconseillée en audit 4). Règles d'appels système :archavant-S, appels regroupés, toujours une clé. Dans la listeexit, la première règle qui correspond gagne. - auid (loginuid) est fixé à la connexion par
pam_loginuidet survit àsudo: c'est lui qui désigne la personne.-F auid>=1000 -F auid!=unsetisole les actions humaines ;--loginuid-immutableempêche de le réécrire. -e 2verrouille les règles jusqu'au redémarrage.auditctl -smontre l'état, dont le compteurlost.- Un événement = plusieurs enregistrements de même
msg=audit(horodatage:série):SYSCALL,EXECVE,CWD,PATH,PROCTITLE(en hexadécimal).ausearch -k ... -ietaureportles rendent lisibles. auditd.confimpose un choix explicite entre disponibilité (SUSPEND) et traçabilité (single,halt) quand le disque est plein.- Les traces n'ont de valeur que hors de la machine, envoyées en temps réel (greffon syslog puis rsyslog en TLS, ou
audisp-remote). - AIDE :
aideinitpour la base,aide --config /etc/aide/aide.conf --checkpour vérifier,--updatepuis copie deaide.db.newaprès revue d'un changement légitime, base conservée ailleurs.dpkg --verifyetdebsumsne servent qu'à repérer une modification non malveillante.
Pour aller plus loin
- Les pages
auditctl(8),audit.rules(7),auditd.conf(5)etausearch-expression(5), et les fichiers d'exemple de/usr/share/doc/auditd/examples/, qui sont la meilleure collection de règles commentées. - Le dépôt
linux-audit/audit-documentationsur GitHub, qui décrit chaque type d'enregistrement et chaque champ. - Le guide de l'ANSSI, Recommandations de configuration d'un système GNU/Linux (BP-028), recommandations R33, R73, R76 et R77, et son guide Recommandations de sécurité pour l'architecture d'un système de journalisation.
- La documentation d'AIDE (
aide.conf(5)) et le fichierREADME.Debiandu paquetaide-common, qui détaille le travail quotidien et ses réglages. - Les cours Journaux centralisés avec Loki, pour exploiter les événements reçus par
sig-outils, et SSH, pour les certificats et l'attribution des connexions. - La leçon suivante, Sauvegarder et restaurer un serveur.
Sources
- Linux man-pages, auditctl(8)
- Linux man-pages, audit.rules(7)
- Linux man-pages, auditd.conf(5)
- Linux man-pages, augenrules(8)
- Linux man-pages, ausearch(8)
- Linux man-pages, aureport(8)
- Linux man-pages, pam_loginuid(8)
- Linux man-pages, dpkg(1)
- Ubuntu manpages (noble), auditctl(8), audisp-remote.conf(5), audisp-syslog(8)
- Debian manpages (trixie), auditctl(8) : -w déconseillé
- Debian manpages (trixie), aide(1), aide.conf(5), aideinit(8), debsums(1)
- Debian manpages (trixie), journald.conf(5) : Audit= et systemd-journald-audit.socket
- linux-audit, code source d'audit-userspace (auditctl.c, auditd-event.c, unités systemd, règles d'exemple)
- Debian, paquet audit : correctifs 01-no-refusemanualstop et 03-Set-log_group-adm
- Debian, paquet aide : README.Debian, minuteur dailyaidecheck, /etc/default/aide
- AIDE, code source v0.19.1 (report.c, report_plain.c, attributes.c)
- Noyau Linux v6.8, kernel/audit.c
- Documentation du noyau, paramètres audit= et audit_backlog_limit=
- sudo, pages de manuel sudoers(5) et sudoreplay(8)
- Red Hat Enterprise Linux 9, Security hardening : Auditing the system
- ANSSI, Recommandations de configuration d'un système GNU/Linux (BP-028 v2.0), R33, R73, R76, R77
- packages.ubuntu.com (noble) : auditd, aide, sudo
- packages.debian.org (trixie) : auditd, audispd-plugins, aide-common, sudo