Nous avons étudié plusieurs solutions permettant de journaliser les commandes exécutées sur le système, le but étant de pouvoir remonter à la cause d’un éventuel problème sur l’infrastructure.
auditd
est actuellement la solution la plus adaptée aux besoins de Picasoft :
il est largement supporté, s’intègre bien avec SELinux si besoin, permet de
centraliser les logs et d’effectuer leur rotation, permet de journaliser en
détail de nombreux événements sur le système et est hautement configurable.
selinux
, kerberos
ou
rsyslog
La configuration d’auditd
se fait en deux parties : celle des règles d’audit
et celle du démon en lui-même.
Les règles se trouvent dans /etc/audit/rules.d/audit.rules
, qui ne doit pas
être édité manuellement. Il est automatiquement consitué par aggrégation de
celles contenues dans les fichiers de /etc/audit/rules.d/
. Il contient une
succession d’options qui peuvent être directement passées au démon en appelant
la commande auditctl
. Les options inscrites dans ce fichier sont passés à
auditd
lorsqu’il est lancé. Ces options sont documentées dans auditctl(8)
et
audit.rules(7)
.
Parmi elles, celles commençant par -w
permettent de journaliser les accès aux
fichiers en lecture, écriture, exécution ou modification d’attributs. auditd
se charge de déterminer ces accès en fonction de certains appels système
pertinents. Par exemple, un appel à write(2)
ne suffit pas à déterminer accès
en écriture car ceux-ci sont trop courants. auditd
a (notamment) besoin de
l’associer à un appel à open(2)
pour considérer une écriture de fichier.
Les règles contenant -S
permettent de journaliser les appels système. L’option
-F
, pouvant apparaître plusieurs fois, spécifie un filtre et l’option -a
spécifie au moteur de correspondance du noyau dans quel cas un événement est
pris en compte. Un événement générant généralement plusieurs enregistrement, une
règle peut soit concerner soit tout un événement, soit juste un enregistrement.
Par exemple :
-a never,exit -F exe=/usr/sbin/runc
supprime tous les événements liés à runc
alors que :
-a always,exclude -F msgtype=CWD
élimine les enregistrements CWD
de tous les événements mais journalise encore
les autres enregistrements leur étant associé (sous condition évidente que les
autres règles le permettent).
L’option -k
permet d’associer un label à une règle. Chaque événement
journalisé par celle-ci sera alors portera alors ce label, ce qui est utile pour
l’analyse postérieure des journaux.
Il est à noter que l’ordre des règles dans le fichier importe : elles sont évaluées les unes à la suite des autres. Ainsi, si une règle exclut un événement, il ne sera journalisé, peu importe ce que stipulent d’autres règles situées plus loin dans le fichier de configuration.
Une configuration disponible sur
Github
présente de bonnes pratiques concernant les règles auditd
et permet de
rapidement se familiariser avec des nombreuses options proposées par son système
de règles.
Voici la configuration des règles dans /etc/audit/rules.d/audit.rules
que nous
avons déployée sur tous les hôtes dans le cadre de la TX :
# First rule - delete all -D # Increase the buffers to survive stress events. # Make this bigger for busy systems -b 8192 # This determine how long to wait in burst of events --backlog_wait_time 0 # Set failure mode to syslog -f 1 # don't log verbose container commands events -a never,exit -F exe=/usr/sbin/runc -a never,exit -F exe=/usr/bin/docker-runc -a never,exit -F exe=/usr/bin/containerd # don't log CWD records -a always,exclude -F msgtype=CWD # don't log SELinux AVC records -a always,exclude -F msgtype=AVC # log all 32/54bit execve calls from root, docker and others -a exit,always -F arch=b64 -F euid=root -S execve -k execve_root -a exit,always -F arch=b32 -F euid=root -S execve -k execve_root -a exit,always -F arch=b64 -F egid=docker -S execve -k execve_docker -a exit,always -F arch=b32 -F egid=docker -S execve -k execve_docker -a exit,always -F arch=b64 -S execve -k execve_others -a exit,always -F arch=b32 -S execve -k execve_others # monitor writes and file attribute changes on /etc and /lib -w /etc -p wa -k etc_modification -w /lib -p wa -k lib_modification
Le démon auditd
en lui-même est configuré dans le fichier
/etc/audit/auditd.conf
. Il s’organise en paires clef = valeur
séparées par
des retours à la ligne. On peut y configurer les journaux, de leur localisation
(/var/log/audit/audit.log
par défaut) à leur format et à l’espace qu’ils
peuvent prendre au maximum, la centralisation des journaux avec Kerberos et les
paramètres réseau d’auditd.
La configuration de base proposée par Debian est pertinente. Nous insisterons toutefois sur les options suivantes :
dispatcher = /sbin/audispd
: on souhaite que la centralisation des logs soit
faite par le plugin syslog
d’audispd
action_mail_acct = root
: les mails envoyés par auditd sont par défaut à
destination de root
. On pourra plus tard mettre en place une centralisation
des mails en configurant le service de mail en réseaumax_log_file = 8
et max_log_file_action = ROTATE
: dès qu’un fichier de
log atteint une taille de 8M, on effectue une rotationspace_left = 75
et space_left_action = SYSLOG
: lorsque la partition
contenant les journaux descend en-dessous des 75M de libres, on émet un
avertissement avec syslog
admin_space_left
et admin_space_left_action
: lorsque la partition
contenant les journaux descend en-dessous des 75M de libres, on suspend
l’activité d’auditddisk_full_action = SUSPEND
et disk_error_action = SUSPEND
: lorsque la
partition contenant les journaux est pleine, on suspend l’activité d’auditd
Au-delà de la configuration d’auditd en lui-même, il est conseillé de passer
audit=1
comme paramètre au noyau afin de pouvoir auditer les processus
éventuellent lancés avant auditd
lui-même.
Les informations relative à la centralisation des logs peuvent être retrouvées ici.
Une fois configuré, auditd ne fait que journaliser les événements pertinents
dans /var/log/audit/audit.log
(ou ailleurs selon la configuration). On peut
alors utiliser différentes méthodes pour retrouver ceux nous intéressant. On
peut notamment utiliser ausearch
et aureport
, des outils propres à auditd,
journalctl
venant avec systemd, ou simplement chercher manuellement à travers
les journaux.
aureport(8)
produit des résumés des journaux produits par auditd. Ces résumés
peuvent être basés sur différents critères décrits dans le manuel, comme par
exemple les labels (définis dans les règles de configuration), le groupe de
l’utilisateur ayant généré l’événement ou le pid du processus. Il est aussi
possible d’obtenir certains événements courants comme ceux concernant par
exemple les modifications de configuration ou les actions sur fichiers et/ou
sockets. Dans ces cas, auditd gère lui-même les cas correspondant au besoin
exprimé.
ausearch(8)
est un autre outil fourni par auditd offrant des fonctionnalités
plus bas niveau. Ses arguments sont très similaires à ceux de aureport
mais
plutôt que d’afficher des résumés des événements, il les affiche directement
tels qu’ils sont contenus dans les journaux. Il s’agit donc en un sens d’un
“grep contextuel intelligent” pour auditd.
Il est également possible de directement manipuler les journaux avec les outils
présents sur le système, ce qui peut être plus rapide (selon la familiarité de
l’utilisateur) pour explorer les événements sans savoir exactement ce que l’on
cherche ou pour au contraire trouver quelque chose de particulier qu’on sait
pouvoir facilement trouver avec grep
ou less
.
Finalement, journalctl
permet aussi d’accéder aux journaux d’auditd, bien que
ce ne soit pas une façon recommandée de les traiter.
auditd permet de tracer les utilisateurs responsables des commandes journalisés.
En particulier, on peut savoir qui a exécuté une commande avec sudo
.
Cependant, on perd l’information d’utilisateur lorsque celui-ci devient root
avec su
.
On peut continuer à le traçant en utilisant les identifiants de session que
conserve auditd. Ainsi, les enregistrements SYSCALL
contiennent un champ
ses
. À partir de celui-ci, il suffit de remonter dans les journaux et de
trouver l’appel (par exemple) à su
ayant le même identifiant de session et qui
comportera l’UID original de l’utilisateur.