Lynis + Ansible : automatiser l’audit de sécurité de vos serveurs Linux
Auditer un serveur Linux à la main, ça marche – une fois. Mais quand on gère 5, 10 ou 30 machines, il faut automatiser. Je vous montre comment j’utilise Lynis, inxi et un script de collecte maison, le tout orchestré par Ansible, pour produire des rapports de sécurité complets en quelques minutes.
📑 Sommaire
- Pourquoi automatiser l’audit de sécurité Linux
- Lynis : le scanner de sécurité open source de référence
- inxi : l’inventaire système complet en une commande
- Script de collecte complémentaire : ce que Lynis ne couvre pas
- Le playbook Ansible qui orchestre tout
- Lancer l’audit en pratique
- Lire et exploiter les rapports
- Checklist post-audit : les actions à prioriser
- Erreurs courantes à éviter
- FAQ

⚡ En résumé
Lynis est un outil open source qui scanne la sécurité d’un système Linux (SSH, permissions, firewall, kernel). Combiné à inxi pour l’inventaire matériel et à un script de collecte système, le tout orchestré par un playbook Ansible, il permet d’auditer automatiquement un parc de serveurs et de récupérer 3 rapports exploitables en quelques minutes, sans intervention manuelle sur chaque machine.
Pourquoi automatiser l’audit de sécurité Linux
Quand un client me demande un audit de sécurité sur un serveur, la procédure manuelle fonctionne : je me connecte en SSH, je lance Lynis, je note les résultats, je vérifie la configuration SSH, les ports ouverts, les comptes utilisateurs, le firewall, les backups… C’est fastidieux mais faisable.
Le problème arrive quand je dois auditer une infrastructure complète : 5 serveurs de production, 2 serveurs de staging, un bastion, un serveur de monitoring. Refaire la même procédure serveur par serveur, c’est une perte de temps considérable et une source d’erreurs (oublier une vérification, mélanger les résultats).
Ma solution : un playbook Ansible qui se connecte à chaque serveur, lance 3 outils d’audit complémentaires, récupère les rapports en local et nettoie derrière lui. Un ansible-playbook audit.yml et 10 minutes plus tard, j’ai tous mes rapports prêts à analyser.
Cette approche fonctionne aussi bien pour un audit ponctuel (prestation client) que pour un audit régulier de votre propre infrastructure. J’utilise le même playbook pour mes serveurs d’infogérance et pour les audits ponctuels de mes clients.
Lynis : le scanner de sécurité open source de référence
Lynis est un outil d’audit de sécurité développé par CISOfy. Il analyse en profondeur un système Linux (ou macOS/Unix) et produit un score de durcissement (hardening index) avec des recommandations concrètes. C’est le standard de facto pour l’audit de sécurité sur Linux.
Ce que Lynis vérifie
Lynis passe en revue plus de 300 points de contrôle, répartis en catégories :
- Boot et services : GRUB protégé, services inutiles actifs, systemd
- Kernel : paramètres sysctl, modules chargés, protections mémoire
- Authentification : configuration PAM, politique de mots de passe, comptes sans mot de passe
- SSH : PermitRootLogin, PasswordAuthentication, protocoles autorisés
- Réseau et firewall : ports ouverts, règles iptables/nftables/UFW, configuration IPv6
- Système de fichiers : permissions sensibles, SUID/SGID, partitions sans options de montage sécurisées
- Logiciels : paquets obsolètes, gestionnaire de paquets, intégrité des binaires
- Logging : configuration syslog/journald, rotation des logs
Installation et lancement manuel
La méthode la plus propre est de cloner le dépôt officiel directement sur le serveur cible :
git clone https://github.com/CISOfy/lynis.git
cd lynis
sudo ./lynis audit system
L’audit dure entre 2 et 5 minutes selon la complexité du serveur. Le rapport s’affiche dans le terminal et se trouve aussi dans /var/log/lynis-report.dat.
Lynis nécessite les droits root pour un audit complet. Sans sudo, certains tests seront ignorés (vérification du firewall, lecture de /etc/shadow, inspection des fichiers sécurisés). Le rapport sera partiel.
inxi : l’inventaire système complet en une commande
Lynis se concentre sur la sécurité, mais ne collecte pas les informations matérielles et système. Pour compléter l’audit, j’utilise inxi, un outil de diagnostic système qui produit un inventaire complet en une seule commande :
git clone https://github.com/smxi/inxi.git
cd inxi
./inxi -Fazy
Le flag -Fazy donne :
-F: rapport complet (CPU, GPU, réseau, disques, partitions, capteurs)-a: informations avancées (adresses MAC, serial, etc.)-z: anonymise les données sensibles (MAC addresses masquées)-y: largeur de colonne maximale pour une sortie lisible
Le résultat est un snapshot complet du serveur : modèle CPU, quantité de RAM, layout disques, interfaces réseau, version du kernel, état des services. C’est exactement ce qu’il faut pour la partie « inventaire » d’un rapport d’audit.
Script de collecte complémentaire : ce que Lynis ne couvre pas
Même avec Lynis et inxi, certaines informations manquent : l’état des services systemd, les processus gourmands, la configuration SSH détaillée, les comptes sudoers, l’état de fail2ban, l’état d’auditd. J’ai donc écrit un script de collecte en Bash qui complète les lacunes :
#!/usr/bin/env bash
# audit_collect.sh - Collecte d'infos d'audit (lecture seule)
set -uo pipefail
timestamp="$(date -Is)"
echo "# Audit système - $(hostname) - $timestamp"
# 1. Ressources système
echo "## Ressources système"
echo "CPU:"
lscpu | egrep 'Model name|Socket|Thread|Core|CPU\(s\)'
echo "RAM:"
free -h
echo "Disques:"
lsblk -o NAME,SIZE,FSTYPE,MOUNTPOINT,LABEL
df -hT
# 2. Services et processus
echo "## Services et processus"
echo "Services actifs:"
systemctl list-units --type=service --state=running | head -n 200
echo "Services en échec:"
systemctl --failed
echo "Processus CPU élevés:"
ps axo pid,ppid,cmd,%cpu,%mem --sort=-%cpu | head -n 15
echo "Processus RAM élevés:"
ps axo pid,ppid,cmd,%mem,%cpu --sort=-%mem | head -n 15
# 3. Sécurité système
echo "## Sécurité système"
echo "SSH config:"
sshd_cfg="/etc/ssh/sshd_config"
[ -f "$sshd_cfg" ] && egrep -i \
'PermitRootLogin|PasswordAuthentication|PubkeyAuthentication' "$sshd_cfg"
echo "Comptes utilisateurs (UID>=1000):"
getent passwd | awk -F: '$3>=1000 {print $1":"$3":"$6":"$7}'
echo "Sudoers:"
sudo -n cat /etc/sudoers 2>/dev/null | egrep -v '^#' || echo "Accès sudoers non disponible"
echo "Fail2ban:"
systemctl status fail2ban 2>/dev/null | head -n 15 || echo "fail2ban absent"
echo "auditd:"
systemctl status auditd 2>/dev/null | head -n 15 || echo "auditd absent"
Le script est en lecture seule : aucune modification, aucune écriture sur le serveur. Il ne fait que lire des informations système et les afficher sur la sortie standard.
Le playbook Ansible qui orchestre tout
Voici le cœur du dispositif : un playbook Ansible qui se connecte au serveur cible, lance les 3 outils d’audit, rapatrie les rapports en local, puis nettoie le serveur.
---
- name: Audit Lynis + audit système inxi
hosts: "{{ target | default('debian13-test') }}"
become: true
gather_facts: true
vars:
lynis_repo: "https://github.com/CISOfy/lynis.git"
lynis_dir: "{{ ansible_env.HOME }}/lynis"
inxi_repo: "https://github.com/smxi/inxi.git"
inxi_dir: "{{ ansible_env.HOME }}/inxi"
audit_collect_script_local: "./audit_collect.sh"
audit_collect_script_remote: "{{ ansible_env.HOME }}/audit_collect.sh"
local_report_dir: "./rapports_lynis_inxi"
tasks:
# Créer le répertoire local pour les rapports
- name: Créer le répertoire local pour stocker les rapports
delegate_to: localhost
become: false
ansible.builtin.file:
path: "{{ local_report_dir }}"
state: directory
mode: "0755"
# --- Lynis (sécurité) ---
- name: Cloner Lynis dans le home
ansible.builtin.git:
repo: "{{ lynis_repo }}"
dest: "{{ lynis_dir }}"
version: "master"
update: false
- name: Exécuter un audit Lynis
ansible.builtin.command: >
./lynis audit system --cronjob --report-file /dev/null
args:
chdir: "{{ lynis_dir }}"
register: lynis_output
- name: Écrire le rapport Lynis sur le contrôleur
delegate_to: localhost
become: false
ansible.builtin.copy:
dest: "{{ local_report_dir }}/{{ inventory_hostname }}-rapport-lynis.txt"
content: "{{ lynis_output.stdout }}"
mode: "0644"
# --- inxi (inventaire système) ---
- name: Cloner inxi dans le home
ansible.builtin.git:
repo: "{{ inxi_repo }}"
dest: "{{ inxi_dir }}"
version: "master"
update: false
- name: Exécuter inxi (inventaire complet anonymisé)
ansible.builtin.shell: ./inxi -Fazy
args:
chdir: "{{ inxi_dir }}"
register: inxi_output
- name: Écrire le rapport inxi sur le contrôleur
delegate_to: localhost
become: false
ansible.builtin.copy:
dest: "{{ local_report_dir }}/{{ inventory_hostname }}-rapport-systeme-inxi.txt"
content: "{{ inxi_output.stdout }}"
mode: "0644"
# --- Script de collecte complémentaire ---
- name: Copier audit_collect.sh sur la cible
ansible.builtin.copy:
src: "{{ audit_collect_script_local }}"
dest: "{{ audit_collect_script_remote }}"
mode: "0755"
- name: Exécuter audit_collect.sh
ansible.builtin.command: "{{ audit_collect_script_remote }}"
register: audit_collect_output
- name: Écrire le rapport audit_collect sur le contrôleur
delegate_to: localhost
become: false
ansible.builtin.copy:
dest: "{{ local_report_dir }}/{{ inventory_hostname }}-audit-collect.txt"
content: "{{ audit_collect_output.stdout }}"
mode: "0644"
# --- Nettoyage ---
- name: Supprimer les fichiers d'audit sur la cible
ansible.builtin.file:
path: "{{ item }}"
state: absent
loop:
- "{{ inxi_dir }}"
- "{{ lynis_dir }}"
- "{{ audit_collect_script_remote }}"
Points clés de ce playbook
- Idempotence : le playbook vérifie si les rapports existent déjà localement avant de relancer l’audit (dans la version complète du repo). Pas de double travail inutile.
- Nettoyage automatique : tout ce qui est cloné ou copié sur le serveur cible est supprimé à la fin. Le serveur revient à son état initial.
- Délégation locale : les rapports sont écrits sur la machine contrôleur Ansible (
delegate_to: localhost), pas sur le serveur audité. - Variable
target: on peut cibler n’importe quel serveur ou groupe de l’inventaire Ansible sans modifier le playbook.
Lancer l’audit en pratique
Prérequis
- Ansible installé sur votre poste local
- Accès SSH aux serveurs cibles (clé SSH recommandée)
- Droits sudo sur les serveurs cibles
- Git installé sur les serveurs cibles (pour cloner Lynis et inxi)
Auditer un seul serveur
# Auditer un serveur spécifique de votre inventaire
ansible-playbook audit.yml -e target=mon-serveur-prod
# Auditer avec un inventaire ad hoc
ansible-playbook audit.yml -i "192.168.1.50," -e target=all
Auditer toute une infrastructure
# Auditer tous les serveurs d'un groupe
ansible-playbook audit.yml -e target=production
# Auditer avec un parallélisme limité (éviter la surcharge)
ansible-playbook audit.yml -e target=all --forks 3
À la fin de l’exécution, vous retrouvez un répertoire rapports_lynis_inxi/ contenant 3 fichiers par serveur :
rapports_lynis_inxi/
├── srv-prod-01-rapport-lynis.txt
├── srv-prod-01-rapport-systeme-inxi.txt
├── srv-prod-01-audit-collect.txt
├── srv-prod-02-rapport-lynis.txt
├── srv-prod-02-rapport-systeme-inxi.txt
└── srv-prod-02-audit-collect.txt
Lire et exploiter les rapports
Rapport Lynis : le hardening index
La partie la plus utile du rapport Lynis se trouve à la fin : le hardening index. C’est un score sur 100 qui donne une vision immédiate de l’état de sécurité du serveur :
Hardening index : 67 [############# ]
Tests performed : 281
Plugins enabled : 0
Un score en dessous de 70 mérite attention. En dessous de 50, c’est une urgence. Au-dessus de 80, le serveur est bien durci.
Juste avant le score, Lynis liste les suggestions et warnings classés par catégorie. Ce sont les actions concrètes à mettre en place :
Suggestions (42):
* Set a password on GRUB boot loader [BOOT-5122]
* Install libpam-tmpdir to set $TMP and $TMPDIR [CUST-0280]
* Install apt-listchanges [PKGS-7394]
* Configure minimum password age in /etc/login.defs [AUTH-9286]
* Configure maximum password age in /etc/login.defs [AUTH-9286]
* Default umask in /etc/login.defs should be 027 [AUTH-9328]
Warnings (2):
* Found some information disclosure in SMTP banner [MAIL-8818]
* iptables module(s) loaded, but no rules active [FIRE-4512]
Rapport inxi : contexte matériel
Le rapport inxi permet de contextualiser les résultats de Lynis. Un serveur avec 1 Go de RAM et un disque presque plein n’aura pas les mêmes priorités qu’un serveur bien dimensionné. Informations utiles :
- CPU, nombre de cores, architecture
- RAM totale et utilisation
- Layout disques et taux d’occupation
- Interfaces réseau et configuration IP
- Version du kernel et de l’OS
Rapport audit_collect : vue opérationnelle
Ce troisième rapport complète les deux premiers avec les informations opérationnelles que Lynis ne couvre pas :
- Liste des services en échec (
systemctl --failed) - Processus les plus gourmands en CPU et RAM
- Configuration SSH effective (pas seulement les warnings Lynis)
- Liste complète des comptes avec UID, home directory et shell
- État de fail2ban et auditd
- Contenu du fichier sudoers
Pour chaque serveur audité, je commence par lire le rapport inxi (contexte), puis le hardening index de Lynis (score global), puis les warnings Lynis (urgences), et enfin le rapport audit_collect (détails opérationnels). Cette lecture en 4 étapes permet d’identifier rapidement les priorités.
Checklist post-audit : les actions à prioriser
✅ Checklist de remédiation post-audit
- ☐ SSH :
PermitRootLogin noetPasswordAuthentication nodans/etc/ssh/sshd_config - ☐ Firewall : règles iptables/nftables/UFW actives et restrictives (pas de
ACCEPTglobal) - ☐ Mises à jour : paquets à jour,
unattended-upgradesconfiguré pour les correctifs de sécurité - ☐ Comptes : supprimer ou verrouiller les comptes inutilisés, vérifier les sudoers
- ☐ Services : désactiver les services inutiles, corriger les services en échec
- ☐ Fail2ban : installé et actif sur SSH au minimum
- ☐ Permissions : corriger les fichiers SUID/SGID inutiles, vérifier les permissions sur
/etc/shadow - ☐ Logs : rotation configurée, journald persistant activé
- ☐ Backups : vérifier qu’un backup récent existe et qu’il est testé
- ☐ Kernel : paramètres sysctl de sécurité appliqués (
net.ipv4.conf.all.rp_filter,kernel.randomize_va_space) - ☐ Monitoring : un agent de supervision est installé et envoie des données (node_exporter, Netdata, etc.)
Erreurs courantes à éviter
🔴 Lancer Lynis sans sudo
Sans les droits root, Lynis ignore les tests sur le firewall, les permissions sensibles, /etc/shadow et de nombreux points de contrôle système. Le rapport sera incomplet et le score artificiellement bas. Utilisez toujours become: true dans le playbook.
🔴 Ne pas nettoyer après l’audit
Laisser Lynis et inxi clonés sur un serveur de production est une mauvaise pratique. Ces outils révèlent des informations sensibles. Le playbook inclut une étape de nettoyage automatique : les dépôts clonés et le script sont supprimés à la fin de l’exécution.
🔴 Auditer sans inventaire Ansible
Utiliser un inventaire ad hoc (-i "IP,") pour un audit ponctuel fonctionne, mais sur une infrastructure entière, maintenir un inventaire structuré (groupes, variables) est indispensable pour que l’audit soit reproductible et que les rapports soient nommés correctement.
🔴 Ignorer le score Lynis inférieur à 50
Un hardening index en dessous de 50 indique des failles critiques : root SSH autorisé, pas de firewall, paquets obsolètes avec CVE connues. Ce n’est pas un score « moyen », c’est un serveur vulnérable. Traitez les warnings Lynis en priorité avant les suggestions.
Aller plus loin : le guide d’audit terrain
Les 3 rapports automatisés couvrent 80 % du travail. Pour les 20 % restants – la partie qui nécessite du jugement humain – j’ai documenté un guide opérationnel complet avec les commandes à lancer pour chaque section du rapport final :
Réseau et firewall
# Interfaces réseau et configuration IP
ip a
# Routes
ip r
# Ports ouverts (la commande la plus utile)
sudo ss -tulpen
# Firewall : vérifier ce qui est actif
sudo ufw status verbose # si UFW
sudo nft list ruleset # si nftables
sudo iptables -L -n -v # si iptables legacy
Base de données
# Version PostgreSQL
sudo -u postgres psql -c "SELECT version();"
# Nombre de connexions actives
sudo -u postgres psql -c "SELECT count(*) FROM pg_stat_activity;"
# Dernier backup visible
sudo find / -name "*.sql" -o -name "*.dump" 2>/dev/null
Backups
# Backups présents sur le serveur
sudo find / -name "*backup*" 2>/dev/null
# Crontabs (backups automatisés)
crontab -l
sudo ls /etc/cron.d/
# Recherche de scripts de backup S3
sudo grep -R "s3" /etc /usr/local /opt 2>/dev/null
Priorisation des risques
Après avoir collecté toutes les informations, je classe les observations en 3 niveaux de priorité :
- 🔴 P0 – Critique : root SSH autorisé, pas de backup, disque plein à 95 %, firewall absent ou inactif, CVE connues non corrigées
- 🟠 P1 – Important : fail2ban absent, mises à jour de sécurité en retard, comptes inutilisés avec accès sudo, pas de monitoring
- 🟡 P2 – Amélioration : hardening sysctl manquant, pas de rotation de logs sur certains services, mot de passe GRUB non configuré
Un audit n’a de valeur que s’il est suivi d’actions correctives. Produire un rapport Lynis avec un score de 55 et ne rien faire, c’est pire que de ne pas auditer du tout : vous savez que le serveur est vulnérable et vous ne corrigez pas. Chaque audit doit déboucher sur un plan d’action avec des échéances.
FAQ
Besoin d’un audit de sécurité sur votre infrastructure Linux ?
J’accompagne les entreprises dans l’audit, le durcissement et l’infogérance de leurs serveurs Linux. Un audit complet avec rapport détaillé et plan d’action, c’est la première étape pour sécuriser votre infrastructure.