Aller au contenu
Tracer et contrôler l'intégrité : auditd et AIDE

Tracer et contrôler l'intégrité : auditd et AIDE

300 Expert ⏱ 1 h 30 linuxubuntudebiansystemd

À la fin, vous saurez

  • Expliquer le chemin d'un événement d'audit, du noyau jusqu'au fichier de journal et aux greffons d'auditd
  • Écrire des règles d'audit persistantes de surveillance de fichiers et d'appels système, filtrées par identité de connexion, et les charger avec augenrules
  • Lire un événement brut (SYSCALL, EXECVE, CWD, PATH, PROCTITLE) et retrouver l'auteur d'une action avec ausearch et aureport
  • Régler auditd.conf en arbitrant entre disponibilité du service et complétude de la traçabilité
  • Faire sortir les événements d'audit de la machine vers sig-outils
  • Sceller les fichiers d'un serveur avec AIDE, mettre la base à jour après un changement légitime et la protéger hors de la machine
  • Contrôler les fichiers installés par les paquets avec dpkg --verify et enregistrer les sessions sudo

Prérequis

Testé avec aide-debian 0.19.1 aide-ubuntu 0.18.6 auditd-debian 4.0.2 auditd-ubuntu 3.1.2 debian 13 debsums 3.0.2.3 sudo-debian 1.9.16p2 sudo-ubuntu 1.9.15p5 ubuntu 24.04 , vérifié le 7 octobre 2026

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 :

  1. Qui a fait quoi ? Une trace des actions sensibles, rattachée à une personne et non à root.
  2. 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.
  3. 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 :

OutilCe qu'il observeQuandCe 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'auteuren temps réel, au moment de l'actionce 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érencepériodiquement, par exemple chaque nuitqui a fait le changement, ni quand exactement
Enregistrement des sessions sudoce qui s'affiche dans le terminal d'une commande lancée par sudoen temps réelce 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 ;
  • ausearch et aureport : 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-cmd se lit « toujours (always), à la sortie de l'appel (exit), pour les appels 64 bits, quand l'appel est execve et 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 unlocked

Ligne par ligne :

  • enabled 1 : l'audit est actif ; 2 signifierait verrouillé.
  • failure 1 : en cas de problème grave (file pleine, mémoire), le noyau écrit un message (printk) ; 0 serait le silence, 2 la panique du noyau.
  • pid : le PID d'auditd ; 0 indique 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 8192 des 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 2

Quelques explications, ligne par ligne :

  • -F arch=b64 avant -S. Les numéros d'appels système diffèrent entre les jeux 32 et 64 bits ; auditctl doit savoir quelle table utiliser pour traduire execve en numéro, d'où la consigne de la page audit.rules(7) de placer arch avant -S. Sur une instance Arm de Scaleway, b64 désigne le jeu natif aarch64 et b32 le 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 en b32, comme le font les exemples officiels, on journalise toute utilisation de cette interface, qu'aucun logiciel de sig-app-1 n'utilise normalement.
  • perm=wa : écriture et changement d'attributs (droits, propriétaire). Une lecture de /etc/shadow n'est pas tracée ici ; on pourrait ajouter r, 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-cmd reprend l'esprit de la recommandation R33 de l'ANSSI, qui propose de journaliser tous les execve : 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 (_chrony sur Debian et Ubuntu) se vérifie avec ps -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=73797374656D63746C0072657374617274007369676E616C656D656E7473

Comment 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=c000003e code l'architecture x86_64, syscall=59 est execve sur cette architecture, success=yes exit=0 dit qu'il a réussi, a0 à a3 sont les quatre premiers arguments, en hexadécimal (des adresses mémoire, inutiles ici). items=2 annonce deux enregistrements PATH. 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. Enfin comm, le nom court du processus, exe, le chemin du binaire, et key, 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 un execve, 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
  • -k filtre par clé, -ul par identité de connexion (auid), -ua par n'importe laquelle des identités, -f par nom de fichier, -m par type d'enregistrement, -sv no sur les échecs ;
  • -i (interpret) traduit les nombres : UID en noms, architecture et appel système en clair, PROCTITLE décodé ;
  • --start et --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-cmd

La 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  sudoers

Une 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 = SUSPEND
  • max_log_file (en Mio) et num_logs : le journal tourne à 8 Mio, et cinq fichiers sont conservés. Sur un serveur où la règle root-cmd est active, 40 Mio peuvent ne couvrir que quelques jours. max_log_file_action = keep_logs tourne sans jamais supprimer, ce qui reporte le problème sur l'espace disque.
  • space_left puis admin_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_action et disk_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 = string

active = 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-jointes

Une 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/sshd

Les 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_output

La 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/bash

Sans 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 de sig-app-1 n'ont pas accès en écriture, a valeur de preuve. Sur sig-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 = adm donne la lecture d'audit.log à tout le groupe adm, 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érifiez getent group adm, ou repassez log_group à root.
  • Surveillez la surveillance. Les événements qui doivent déclencher une alerte immédiate sur sig-outils : DAEMON_END ou DAEMON_ABORT (auditd arrêté), CONFIG_CHANGE (règles modifiées), les clés audit-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 sur sig-app-1 et sig-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-cmd sur 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 sur sig-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 sur sig-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-signalements

Puis 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
  1. Ne pas accepter le changement et ne pas mettre à jour la base.
  2. Croiser les sources. dpkg --verify curl : un 5 en 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/curl confirme le paquet propriétaire. Comparer l'empreinte SHA-256 du fichier avec celle du même paquet téléchargé ailleurs (apt download curl sur une autre machine, puis dpkg-deb -x).
  3. Chercher l'auteur. Sur sig-outils, dans la copie centralisée plutôt que locale : ausearch -f /usr/bin/curl -i et les événements root-cmd autour de la date de modification indiquée par le rapport, puis la session (--session) et les enregistrements sudo correspondants.
  4. 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.
  5. 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.log et alimente des greffons. Les règles persistantes vont dans /etc/audit/rules.d/*.rules, assemblées et chargées par augenrules --load.
  • Règles de fichiers : -a always,exit -F arch=b64 -F path=... -F perm=wa -F key=... (la forme -w est déconseillée en audit 4). Règles d'appels système : arch avant -S, appels regroupés, toujours une clé. Dans la liste exit, la première règle qui correspond gagne.
  • auid (loginuid) est fixé à la connexion par pam_loginuid et survit à sudo : c'est lui qui désigne la personne. -F auid>=1000 -F auid!=unset isole les actions humaines ; --loginuid-immutable empêche de le réécrire.
  • -e 2 verrouille les règles jusqu'au redémarrage. auditctl -s montre l'état, dont le compteur lost.
  • Un événement = plusieurs enregistrements de même msg=audit(horodatage:série) : SYSCALL, EXECVE, CWD, PATH, PROCTITLE (en hexadécimal). ausearch -k ... -i et aureport les rendent lisibles.
  • auditd.conf impose 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 : aideinit pour la base, aide --config /etc/aide/aide.conf --check pour vérifier, --update puis copie de aide.db.new après revue d'un changement légitime, base conservée ailleurs. dpkg --verify et debsums ne servent qu'à repérer une modification non malveillante.

Pour aller plus loin

  • Les pages auditctl(8), audit.rules(7), auditd.conf(5) et ausearch-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-documentation sur 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 fichier README.Debian du paquet aide-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.
+30 XP Carte du ciel →Mon cosmonaute →

Sources