Mode opératoire — Lire les journaux bruts en direct avec LogAnalyzer, en lecture seule

Document autonome. Partie théorique, puis mise en œuvre telle qu’elle a été réalisée et vérifiée le 06/11/2026 sur srv-supervision (10.0.30.15, Debian 13, zone ADM), phase 17 du suivi (SUIVI-TP.md), étape 67 de la documentation. Prérequis : les journaux de toutes les machines arrivent déjà dans la base syslog du cluster MariaDB/Galera (MO-15-Rsyslog-Galera.md), et srv-supervision atteint le cluster par son HAProxy local 127.0.0.1:3306 (MO-14-HAProxy-local-Galera.md).

Dernière mise à jour : 06/11/2026


Sommaire

§Contenu
1À quoi sert LogAnalyzer, à côté de Grafana
2Les choix : vues en lecture seule, mot de passe Apache, port 8443
3Les vues SQL et le compte en lecture seule
4Apache et PHP sur srv-supervision
5Télécharger, vérifier et installer LogAnalyzer
6S’en servir : vue en direct, recherche, et ajuster une règle
7Le superviser
8Pièges et checklist

1 · À quoi sert LogAnalyzer, à côté de Grafana

Grafana (tableau de production)LogAnalyzer
Question« Est-ce que ça va ? »« Que se passe-t-il, en ce moment, ligne par ligne ? »
Ce qu’il montrece que ses requêtes choisissent (connexions refusées, réussies, volume…)tous les journaux stockés, bruts, du plus récent au plus ancien
Usagesurveiller, être alertéparcourir sans rien chercher, repérer ce qui choque, rechercher simplement (machine, gravité, programme, texte)
Suite logiqueune alerteune règle ajustée : bruit coupé à la source, règle Wazuh, nouvelle alerte Grafana

LogAnalyzer est une application web en PHP, écrite par Adiscon (l’éditeur de rsyslog), faite pour lire des journaux rangés par rsyslog dans MySQL/MariaDB. Depuis 2026 elle est reprise par l’équipe rsyslog sur GitHub (rsyslog/loganalyzer) : version 5.0.2 du 28/09/2026, avec des correctifs de sécurité (injections SQL, XSS, sessions). L’ancien site d’Adiscon s’arrête à la 4.1.13 (2022) : prendre la version GitHub.

Principe à retenir — Grafana fait voir, LogAnalyzer fait comprendre : on ne filtre que le bruit qu’on a d’abord lu et reconnu comme inutile, jamais un échec.

Limite — Ce qui est filtré à la source (avant d’arriver en base) n’est jamais visible, ni dans Grafana ni dans LogAnalyzer.


2 · Les choix

ChoixDécisionPourquoi
Oùsrv-supervision, qui reçoit déjà les journauxpas de nouvelle machine ; accès au cluster déjà en place
Lecture des tablesdeux vues SQL au format attendu par LogAnalyzer (« MonitorWare »)nos tables ont un format maison (étape 48) ; les vues traduisent sans toucher aux tables, à rsyslog, à la purge ni à Grafana
Compte SQLSELECT sur les vues seulementLogAnalyzer ne peut ni écrire ni lire les tables directement
Identificationmot de passe Apache (Basic) devant tout le site ; pas de base d’utilisateurs LogAnalyzerla base d’utilisateurs devrait être écrite dans le cluster et sauvegardée : inutile pour un seul administrateur
PortHTTPS 8443, certificat auto-signé ; port 80 ferméne touche pas à Grafana (3000) ; le mot de passe ne circule jamais en clair
Accès réseauzone d’administration seulementaucune règle ajoutée : le poste d’admin arrive par Tailscale ; les autres zones n’ont aucune règle vers ADM:8443

3 · Les vues SQL et le compte en lecture seule

Contexte : sur un nœud du cluster (srv-mysql-01), en root. Objectif : LogAnalyzer lit les journaux sans rien pouvoir modifier.

3.1 Vérifier le type des colonnes

mariadb -e "SHOW CREATE TABLE syslog.journaux\G"

facilite et gravite sont des nombres (tinyint) : c’est ce qu’attend LogAnalyzer (sinon, convertir dans la vue).

3.2 Créer les deux vues

Les noms de colonnes viennent du code de LogAnalyzer (src/include/constants_logstream.php, correspondance monitorware) : ID, DeviceReportedTime, FromHost, Facility, Priority, SysLogTag, Message, InfoUnitID, ProcessID, EventID, EventLogType, EventSource, EventCategory, EventUser, SystemID, Checksum.

CREATE OR REPLACE SQL SECURITY DEFINER VIEW syslog.la_journaux AS
SELECT id AS ID,
       CONVERT_TZ(recu_le, '+00:00', 'Europe/Paris') AS ReceivedAt,
       CONVERT_TZ(COALESCE(emis_le, recu_le), '+00:00', 'Europe/Paris') AS DeviceReportedTime,
       hote AS FromHost, facilite AS Facility, gravite AS Priority,
       programme AS SysLogTag, message AS Message,
       1 AS InfoUnitID, NULL AS ProcessID, NULL AS EventID, NULL AS EventLogType,
       NULL AS EventSource, NULL AS EventCategory, NULL AS EventUser, NULL AS SystemID,
       CRC32(message) AS Checksum
FROM syslog.journaux;

Puis la même vue syslog.la_journaux_auth sur syslog.journaux_auth (journaux d’authentification).

DétailPourquoi
CONVERT_TZ(…, 'Europe/Paris')les tables sont en UTC ; l’écran s’affiche à l’heure locale (fuseaux horaires chargés dans le cluster)
Checksum calculési cette colonne est vide, LogAnalyzer peut chercher à l’écrire : avec une vue, il n’en a jamais besoin
une vue par table, pas d’UNIONune UNION empêcherait d’utiliser les index sur plus d’un million de lignes

Validation

mariadb -e "EXPLAIN SELECT * FROM syslog.la_journaux ORDER BY ID DESC LIMIT 50;"

key = PRIMARY, rows = 50 : la page lit 50 lignes, pas la table entière.

3.3 Le compte en lecture seule (mot de passe saisi par l’administrateur)

read -rsp "Mot de passe loganalyzer : " P; echo; printf "CREATE USER 'loganalyzer'@'10.0.30.15' IDENTIFIED BY '%s';\n" "$P" | mariadb; unset P
mariadb -e "GRANT SELECT ON syslog.la_journaux TO 'loganalyzer'@'10.0.30.15'; GRANT SELECT ON syslog.la_journaux_auth TO 'loganalyzer'@'10.0.30.15';"

Ne jamais écrire le mot de passe dans la commande elle-même : il resterait dans l’historique. read -rsp le demande sans l’afficher ; printf est une commande interne du shell, il n’apparaît pas dans la liste des processus.

Validation (depuis srv-supervision, mot de passe demandé)

mariadb -h 127.0.0.1 -u loganalyzer -p -e "SELECT ID, DeviceReportedTime, FromHost FROM syslog.la_journaux ORDER BY ID DESC LIMIT 3;"
mariadb -h 127.0.0.1 -u loganalyzer -p -e "SELECT COUNT(*) FROM syslog.journaux;"

La première affiche 3 lignes à l’heure de Paris ; la seconde répond ERROR 1142 … SELECT command denied. 229-loganalyzer-compte-lecture-vues.png


4 · Apache et PHP sur srv-supervision

Contexte : srv-supervision, en root. Objectif : un site HTTPS sur 8443, protégé par mot de passe.

4.1 Paquets

apt-get install -y --no-install-recommends apache2 libapache2-mod-php php-mysql php-gd php-mbstring

4.2 N’écouter que sur 8443

cp -p /etc/apache2/ports.conf /etc/apache2/ports.conf.orig
printf 'Listen 8443\n' > /etc/apache2/ports.conf
a2dissite 000-default && a2enmod ssl headers

Dans /etc/apache2/conf-available/security.conf : ServerTokens Prod et ServerSignature Off (Apache ne dit plus sa version).

4.3 Certificat et site

mkdir -p /etc/ssl/loganalyzer && openssl req -x509 -nodes -days 825 -newkey rsa:2048 -keyout /etc/ssl/loganalyzer/loganalyzer.key -out /etc/ssl/loganalyzer/loganalyzer.crt -subj "/CN=srv-supervision.sio.internal" -addext "subjectAltName=DNS:srv-supervision.sio.internal,IP:10.0.30.15"

/etc/apache2/sites-available/loganalyzer.conf (essentiel) :

<VirtualHost *:8443>
    ServerName srv-supervision.sio.internal
    DocumentRoot /var/www/loganalyzer
    SSLEngine on
    SSLCertificateFile    /etc/ssl/loganalyzer/loganalyzer.crt
    SSLCertificateKeyFile /etc/ssl/loganalyzer/loganalyzer.key
    <Directory /var/www/loganalyzer>
        Options -Indexes
        AllowOverride None
        AuthType Basic
        AuthName "LogAnalyzer - lab"
        AuthUserFile /etc/apache2/loganalyzer.htpasswd
        Require valid-user
    </Directory>
    Header always set X-Content-Type-Options "nosniff"
    Header always set X-Frame-Options "SAMEORIGIN"
</VirtualHost>
a2ensite loganalyzer && apache2ctl configtest && systemctl restart apache2

4.4 Le mot de passe (par l’administrateur)

htpasswd -B /etc/apache2/loganalyzer.htpasswd ipfixe

-B : rangé chiffré en bcrypt. Fichier en 640 root:www-data. Mot de passe dans Bitwarden.

Validation (curl n’est pas installé : wget)

wget -qO- --no-check-certificate --user=ipfixe --ask-password https://127.0.0.1:8443/

Sans mot de passe : 401 ; avec : la page. ss -ltnp : Apache sur *:8443 seulement. 230-loganalyzer-apache-8443.png


5 · Télécharger, vérifier et installer LogAnalyzer

5.1 L’archive, et son empreinte

mkdir -p /root/telechargements/loganalyzer-5.0.2 && cd /root/telechargements/loganalyzer-5.0.2
wget https://github.com/rsyslog/loganalyzer/releases/download/v5.0.2/loganalyzer-5.0.2.tar.gz
echo "77477c075810b358241a05981cf06fe63e0138d4a68bd1d385567e9da555c293  loganalyzer-5.0.2.tar.gz" | sha256sum -c -

Réussi (6 875 678 octets). L’empreinte attendue est celle publiée sur la page de la version GitHub. Si elle diffère : on n’installe pas.

5.2 Copier le site

mkdir extrait && tar -xzf loganalyzer-5.0.2.tar.gz -C extrait --no-same-owner
cp -a extrait/loganalyzer-5.0.2/src/. /var/www/loganalyzer/ && chown -R root:root /var/www/loganalyzer
touch /var/www/loganalyzer/config.php && chown root:www-data /var/www/loganalyzer/config.php && chmod 660 /var/www/loganalyzer/config.php

5.3 L’installeur web

Ouvrir https://10.0.30.15:8443/install.php depuis le poste d’administration ( le lien « here » de la page d’erreur s’affiche en texte brut dans la 5.0.2 : H-88).

ÉtapeChampValeur
3Message character limit for the main view200
3Automatically resolved IP Addresses (inline)No (sinon une requête DNS par adresse lue)
3Enable User DatabaseNo
7Name of the Source / Source TypeJournaux / MYSQL Native
7Table typeMonitorWare
7Database Host127.0.0.1 (pas localhost : ce serait le socket d’un MariaDB local, absent)
7Database Name / Tablenamesyslog / la_journaux
7Database User / Passwordloganalyzer / Bitwarden
7Enable Row CountingNo (compter un million de lignes à chaque page chargerait la base)

5.4 Seconde source, puis verrouiller

Dans config.php, recopier les lignes $CFG['Sources']['Source1'][…] en Source2, avec Name = 'Authentification' et DBTableName = 'la_journaux_auth' (au lab, fait par un petit script, sans afficher le mot de passe). Puis :

php -l /var/www/loganalyzer/config.php
chmod 640 /var/www/loganalyzer/config.php && rm /var/www/loganalyzer/install.php

Validation — la page d’accueil affiche les derniers journaux, la liste « Select Source » propose Journaux et Authentification. 231-loganalyzer-journaux-en-direct.png


6 · S’en servir

BesoinOù
Vue en directSet auto reload : un intervalle (30 s)
Recherchechamp Search : severity:warning, host:srv-mysql-01, syslogtag:sshd, ou un mot du message
Journaux d’authentificationSelect Source → Authentification
Détail d’un messagel’icône à gauche du message

Le cas du lab (06/11) — La première page était remplie par la sonde d’état Galera (Started galera-etat@… / Deactivated successfully) : 77 % des journaux. Lu, reconnu comme du bruit, puis coupé à la source dans [email protected] :

LogLevelMax=notice
SyslogLevel=warning

LogLevelMax=notice coupe les messages « info » de systemd sur ce service ; SyslogLevel=warning garde les erreurs du script. Contrôle : 60 → 0 ligne par minute et par nœud, et une erreur simulée reste visible. Ensuite, la recherche severity:warning a fait ressortir trois vrais échecs de la sonde à 05:50, jusque-là noyés dans le bruit. 232, 233

Les cas suivants (06/11 soir), repérés de la même façon (panneau « Lignes de journaux reçues » puis détail par programme) : la recopie GLPI ouvrait une session SSH toutes les 30 s (→ une seule connexion réutilisée, ControlPersist) ; deux tâches lancées chaque minute (→ LogLevelMax=notice) ; l’interface Wazuh en niveau « info » (→ logging.quiet: true). Résultat : 1 270 → 70, 453 → 70, 645 → 125 lignes par heure. 242

Validation — après chaque réglage, mesurer avant / après et vérifier qu’une erreur passe toujours.


7 · Le superviser

Sur srv-metriques : un module blackbox qui attend un 401 (Apache répond et demande le mot de passe ; la supervision n’a pas besoin du mot de passe), et un job Prometheus sonde_loganalyzer (service="loganalyzer").

  http_401_insecure:
    prober: http
    timeout: 5s
    http:
      preferred_ip_protocol: "ip4"
      valid_status_codes: [401]
      tls_config:
        insecure_skip_verify: true
wget -qO- 'http://127.0.0.1:9115/probe?module=http_401_insecure&target=https://10.0.30.15:8443/' | grep probe_success

probe_success 1. Dans Grafana, la ligne « LogAnalyzer » apparaît seule ; la règle « Service injoignable » la couvre. 234-loganalyzer-supervise.png


8 · Pièges et checklist

PiègeSymptômeOù c’est documenté
Lien de l’installeur affiché en texte brut<a href="./install.php">here</a> visible, pas cliquableTroubleshooting H-88
localhost comme hôte de baseconnexion refusée (socket local absent)§5.3
Comptage des lignes activépages lentes, charge sur le cluster§5.3
Résolution DNS des IP activéepages lentes, requêtes DNS inutiles§5.3
config.php laissé inscriptible, install.php laissé en placen’importe quel utilisateur authentifié peut relancer l’installation§5.4
Filtrer un message sans l’avoir luune erreur réelle disparaît avec le bruit§6
 Vues créées, EXPLAIN par la clé primaire
 Compte SQL : vues lisibles, tables refusées (ERROR 1142)
 Apache sur 8443 seul, port 80 fermé, 401 sans mot de passe
 Empreinte SHA-256 de l'archive identique à celle publiée
 Hôte de base 127.0.0.1, comptage des lignes et résolution DNS désactivés
 Deux sources (Journaux, Authentification)
 config.php en 640 root:www-data, install.php supprimé
 Accès refusé depuis USERS et WEB
 Sonde blackbox up, ligne « LogAnalyzer » dans Grafana
 Mots de passe dans Bitwarden, registre des comptes à jour

La règle à retenir en une phrase : on lit d’abord tout, brut, puis on filtre à la source ce qu’on a reconnu comme du bruit — jamais un échec.