« LINUX:LogWatch » : différence entre les versions

De WIKI sur Linux (ADB)
Aller à la navigation Aller à la recherche
(Page créée avec « __FORCETOC__ ---- ''→ retour à la Surveillance'' ---- =But= Ce logiciel effectue un résumé des activités de la veille du serveur sur base majoritairement des journaux. Il met l'accent sur les problèmes et alertes rencontrés. Le résultat est envoyé par messagerie. En le visionnant, j'ai pu mettre le doigt sur divers problèmes et prendre les mesures correspondantes. ---- ''→ LINUX:Surveillance|retour à la Survei... »)
 
Aucun résumé des modifications
 
(20 versions intermédiaires par le même utilisateur non affichées)
Ligne 7 : Ligne 7 :




=Principe=
Ce logiciel passe en revue divers '''services'''. Chaque analyse s'effectue sur base d'un '''script'''. Ces scripts font souvent appel à des scripts généraux ou fonctions. Les scripts des services peuvent être divisés en deux grands groupes:
* ceux qui effectuent des commandes directes tels l'analyse des espaces disques ou des températures du matériel
* ceux qui analysent des groupes de journaux ciblés ("'''logfiles'''").
Chaque service est piloté par un fichier de configuration.


Par défaut ce sont les journaux de la veille et donc clôturés qui sont analysés.




=Installation=
La première étape consiste à installer le paquet:
dnf install logwatch
=Configuration=
==Structure==
Les fichiers de configuration personnalisables se trouvent dans le répertoire "/etc/logwatch" et ceux de référence dans le répertoire "/usr/share/logwatch".
La structure est identique; si un fichier du même nom se retrouve aux deux endroits, celui sous le répertoire "/etc/logwatch" a la priorité. Donc pour adapter la configuration, il suffit de recopier le fichier correspondant du répertoire "/usr/share/logwatch" dans le répertoire "/etc/logwatch" ou du moins de reprendre dans ce fichier, le paramètre que l'on veut changer. Normalement on ne devrait rien changer.
Voici la structure des éléments principaux:
* Les répertoires "/etc/logwatch/scripts/services" et "/usr/share/logwatch/scripts/services" contiennent les scripts qui effectuent l'analyse des journaux ou effectuent des commandes ciblées. Ces fichiers portent le nom du service correspondant.
* Les répertoires "/etc/logwatch/conf/services" et "/usr/share/logwatch/default.conf/services" regroupent les divers paramètres de configuration du service correspondant. Dans le cas d'une analyse de journaux, ils font référence à un groupe de journaux. C'est la variable "LogFile" qui redirige cette action vers un fichier du point suivant. Ces fichiers portent le nom du service correspondant suivis de l’extension ".conf".
* Les répertoires "/etc/logwatch/conf/logfiles" et "/usr/share/logwatch/default.conf/logfiles" définissent un groupe de journaux à analyser. Ces fichiers portent le nom du groupe de journaux correspondant suivis de l'extention ".conf".
* Les fichiers de configuration des répertoires "/etc/logwatch/conf" et ""/usr/share/logwatch/default.conf" définissent les paramètres généraux du logiciel. Nous y retrouvons les fichiers:
** '''logwatch.conf''' : fichier de configuration de LogWatch
** '''override.conf''' : fichier contenant les paramètres qui auront la priorité absolue sur tout autre défini autre part
** '''ignore.conf''' : fichier contenant les lignes du rapport final que l'on ne veut plus voir apparaître
Il est à noter que certains services n'analysent aucun fichier journal mais ont leur propre type de traitement.
Quelques exemples:
* Analyse des journaux du service "SSHD"
Ce service porte le nom de "sshd". Il utilisera le script "/usr/share/logwatch/scripts/services/sshd", le fichier de paramétrage "/usr/share/logwatch/default.conf/services/sshd". Ce dernier fait référence aux groupes de journaux ""/usr/share/logwatch/default.conf/logfiles/secure"  "/usr/share/logwatch/default.conf/logfiles/messages". On y retrouve notamment parmi bien d'autres les journaux "/var/log/secure" et "/var/log/messages". Dans ces journaux, ils vont repérer les lignes correspondant au processus "sshd".
* Analyse des espaces disques
Ce service porte le nom de "zz-disk_space". Il utilisera le script "/usr/share/logwatch/scripts/services/zz-disk_space", le fichier de paramétrage "/usr/share/logwatch/default.conf/services/zz-disk_space". Il n'analyse aucun journal et donc ne fera pas appel à un fichier groupe de journaux. Mais dans le script, on y retrouvera l'appel à la commande de ligne "df".
==Fichier "logwatch.conf"==
En premier lieu, on peut s'intéresser au fichier de configuration générale: "logwatch.conf"
et spécialement au paramètres suivants:
* MailTo = root : le message est envoyé à l'utilisateur "root"
* Detail = Low : le niveau de détail affiché est au plus bas. Je conseille de le laisser à cette valeur. On peut le mettre à la valeur "Med" pour obtenir plus de détails mais on risque d'être submergé avec pour conséquence de ne plus regarder le rapport. Ne parlons pas du niveau maximal "High".
==Fichier "override.conf"==
Ce fichier sert à outrepasser certains paramètres définis autre part.
Nous l'avons utilisé pour l'activation de services désactivés.
Dans le fichier de fonfiguration générale "/usr/share/logwatch/default.conf/logwatch.conf", les services "zz-network" et "zz-sys" sont désactivés. Nous désirons les réactiver sauf le service "eximstats". Cette opération demande une configuration spéciale.
Dans le fichier de configuration "/etc/logwatch/conf/override.conf", on ajoute les lignes suivantes:
----
logwatch: Service =
logwatch: Service = All
logwatch: Service = "-eximstats"
----
La première ligne annule les options "Service" dans le fichier "/usr/share/logwatch/default.conf/logwatch.conf" (première partie de la variable : "logwatch: Service"). On les remplace par l'activation de tous les services ("All") sauf le service "eximstats" ("-eximstats").
==Fichier "ignore.conf"==
Ce fichier permet d'occulter les lignes du rapport final que l'on ne veut plus voir affiché.
Par exemple dans le rapport, on voit apparaître une sous-section "**Unmatched Entries**". En dessous viennent les lignes des journaux qui ne sont pas traitées par les scripts.
Bien sûr, il faut se demander d'où vient cette entrée dans le journal et essayer de résoudre le problème. Ceci provient en majorité d'un problème lors de l'exécution d'un processus qu'il faut corriger. En second recours, on peut créer son propre script ou son propre service: ce qu'on verra par la suite au travers de divers exemples. Enfin si cette ligne est récurrente et non problématique, on ajoute un extrait identifiant de la ligne problématique dans le fichier "ignore.conf". On l'agrément d'expressions régulières pour tenir compte de certains mots variables comme d'PID d'un processus.
Par exemple, nous avons les entrées suivantes:
----
...
  **Unmatched Entries**
    userhelper: pam_timestamp(chkrootkit:session): updated timestamp file `/var/run/pam_timestamp/root/unknown': 1 Time(s)
...
  **Unmatched Entries**
    Reexecution requested from client PID 540752 ('systemctl') (unit dnf5-automatic.service)...: 1 Time(s)
    Reexecution requested from client PID 541061 ('systemctl') (unit dnf5-automatic.service)...: 1 Time(s)
    Reload requested from client PID 541212 ('systemctl') (unit dnf5-automatic.service)...: 1 Time(s)
    Reload requested from client PID 541270 ('systemctl') (unit dnf5-automatic.service)...: 1 Time(s)
...
----
Notre fichier "ignore.conf" est modifié en conséquence en ajoutant une chaîne de mots identifiants sur base de ces lignes:
----
userhelper: pam_timestamp\(chkrootkit:session\): updated timestamp file `/var/run/pam_timestamp/root/unknown'
Reload requested from client PID (\d+) \('systemctl'\)
Reexecution requested from client PID (\d+) \('systemctl'\)
----
On remarque qu'un back-slash a été ajouté devant les parenthèses. En effet les parenthèses définissent un bloc d'une expression régulière. Ces back-slash évite ce type de traitement. En deuxième ligne et suivantes, nous avons affaire au PID; ce n° est variable et numérique. Nous les traitons par l'expression régulière "(\d+)" qui remplace tout mot constitué de chiffres ("\d" pour digit et "+" pour multiples).
Dès lors le rapport devient:
----
...
  **Unmatched Entries**
  1 Ignored Lines
...
  **Unmatched Entries**
  4 Ignored Lines
...
----
Notons qu'à l'avenir, ces lignes dans les journaux peuvent être prises en compte dans les scripts du logiciel à la suite d'une mise à jour.
=Personnalisation de la configuration=
Normalement la configuration fournie est opérationnelle mais en fouillant cette configuration, nous avons été amené à l'adapter. Malgré tout, il arrive que l'on veuille contourner quelques cas. Rien de tel que de le faire au travers d'exemples.
Voici quelques cas rencontrés. Certains font suite à des modifications personnelles.
==PHP==
En analysant le fichier "/usr/share/logwatch/default.conf/logfiles/php.conf", nous avons remarqué que les noms des journaux n'étaient pas les bons et en outre, nous avions ajouté le support des divers anciennes versions de PHP provenant les dépôts de Remi.
Nous avons donc créé le fichier de configuration "/etc/logwatch/conf/logfiles/php.conf" dont voici le contenu hors commentaires sur base du fichier "/usr/share/logwatch/default.conf/logfiles/php.conf":
----
# PHP (8.3) de la distribution
LogFile = php-fpm/error.log
LogFile = php-fpm/www-error.log
# PHP (7.4, 8.0 et 8.1) du dépôt de Remi
#LogFile = /var/opt/remi/php74/log/php-fpm/error.log
#LogFile = /var/opt/remi/php74/log/php-fpm/www-error.log
LogFile = /var/opt/remi/php80/log/php-fpm/error.log
LogFile = /var/opt/remi/php80/log/php-fpm/www-error.log
LogFile = /var/opt/remi/php81/log/php-fpm/error.log
LogFile = /var/opt/remi/php81/log/php-fpm/www-error.log
 
# PHP (8.3) de la distribution
Archive = php-fpm/error.log-*
Archive = php-fpm/www-error.log-*
# PHP (7.4, 8.0 et 8.1) du dépôt de Remi
#Archive = /var/opt/remi/php74/log/php-fpm/error.log-*
#Archive = /var/opt/remi/php74/log/php-fpm/www-error.log-*
Archive = /var/opt/remi/php80/log/php-fpm/error.log-*
Archive = /var/opt/remi/php80/log/php-fpm/www-error.log-*
Archive = /var/opt/remi/php81/log/php-fpm/error.log-*
Archive = /var/opt/remi/php81/log/php-fpm/www-error.log-*
----
==IPTABLES==
Nous redirigeons les messages venant du FireWall IPtables vers le fichier "/var/log/iptables" et via le logiciel LogRotate, les archives se retrouvent dans les fichiers "/var/log/iptables-*".
Nous avons donc créé le fichier de configuration "/etc/logwatch/conf/logfiles/php.conf" dont voici le contenu hors commentaires sur base du fichier "/usr/share/logwatch/default.conf/logfiles/iptables.conf":
----
LogFile = iptables
Archive = iptables-*
*ApplyStdDate
----
==MariaDB==
Il existe un service "mysql" mais il est non opérationnel pour MariaDB principalement suite au format de la date précédent tout message.
Dans ce script, le format de la date est '%y%m%d %H:%M:%S', par exemple "230814 12:03:45" alors que nous avons besoin d'un format '%Y-%m-%d %H:%M:%S', par exemple "2023-08-14 12:03:45". En outre, nous souhaitions ne voir apparaître les messages "Note" que dans le cas d'un niveau de détail "High". De plus le nom des journaux étaient autres que ceux de MySQL. L'ordre des types de messages a été modifié. Nous avons donc créé un nouveau service sur base des fichiers du service "mysql".
Nous avons créé le fichier de configuration "/etc/logwatch/conf/logfiles/mariadb.conf" dont voici le contenu hors commentaires:
----
LogFile = mariadb/mariadb.log
Archive = mariadb/mariadb.log-*
*ExpandRepeats
----
Nous avons créé aussi le fichier de configuration "/etc/logwatch/conf/services/mariadb.conf" dont voici le contenu hors commentaires:
----
Title = "MariaDB"
LogFile = mariadb
----
Et nous avons adapté le script "/etc/logwatch/scripts/services/mariadb" sur base du script "/usr/share/logwatch/scripts/services/mysql" hors commentaires du début et de la fin pour ne pas surcharger la présentation. Il est écrit en Perl.
Voici son contenu, en gras et en italique les modifications apportées et les lignes modifiées sont mises en commentaire:
----
use strict;
use Logwatch ':dates';
use Time::Local;
use POSIX qw(strftime);
 
#my $date_format = '%y%m%d %H:%M:%S';
'''''my $date_format = '%Y-%m-%d %H:%M:%S';'''''
 
my $filter = TimeFilter($date_format);
my $detail = exists $ENV{'LOGWATCH_DETAIL_LEVEL'} ? $ENV{'LOGWATCH_DETAIL_LEVEL'} : 0;
 
# we do not use any Date:: package (or strptime) as they are probably not available
my %month2num = ( Jan => 0, Feb => 1, Mar => 2, Apr => 3,
                  May => 4, Jun => 5, Jul => 6, Aug => 7,
                  Sep => 8, Oct => 9, Nov => 10, Dec => 11 );
 
# array of message categories (we do not use a hash to keep the order)
# first element: category name
# second element: matching regexp ($1 should contain the message)
# third element: anonymous hash ref (stores message  counts)
my @message_categories = '''''(['Note', qr/\[Note\] (.*)$/o, {}],'''''
                          '''''['Warnings', qr/\[Warning] (.*)$/o, {}],'''''
                          '''''['Errors', qr/\[ERROR\] (.*)$/o, {}],'''''
                          '''''['Other', qr/(.*)$/o, {}]);'''''
 
# counting messages
while(<>) {
    my $line = $_;
    # skipping messages that are not within the requested range
    next unless $line =~ /^($filter)/o; 
&nbsp;
#    $1 =~ /(\d\d)(\d\d)(\d\d)\s+(\d+):(\d+):(\d+)/;
    '''''$1 =~ /(\d+)-(\d+)-(\d+)\s+(\d+):(\d+):(\d+)/;'''''
&nbsp;
    my $time;
&nbsp;
    {
        # timelocal is quite chatty
        local $SIG{'__WARN__'}  = sub {};
        $time = timelocal($6, $5, $4, $3, $2-1, $1);
    }
&nbsp;
    # Count lines with increasing number as one:
    #  [Warning] Aborted connection 107194 to db: ...
    $line =~ s/(Aborted connection) \d+ (to db)/$1 $2/;
&nbsp;
    foreach my $cur_cat (@message_categories) {
        if($line =~ /$cur_cat->[1]/) {
            my $msgs = $cur_cat->[2];
            $msgs->{$1} = {count => '0',
                            first_occurrence => $time,
                            sum => 0,
                            sqrsum => 0} unless exists $msgs->{$1};
            $msgs->{$1}->{'count'}++;
            # summing up timestamps and squares of timestamps
            # in order to calculate the rms
            # using first occurrence of message as offset in calculation to
            # prevent an integer overflow
            $msgs->{$1}->{'sum'} += $time - $msgs->{$1}->{'first_occurrence'};
            $msgs->{$1}->{'sqrsum'} += ($time - $msgs->{$1}->{'first_occurrence'}) ** 2;
            last;
        }
    }
}
&nbsp;
# generating summary
foreach my $cur_cat (@message_categories) {
  # skipping non-requested message types
  next unless keys %{$cur_cat->[2]};
  my ($name, undef, $msgs) = @{$cur_cat};
&nbsp;
  '''''my $etat = 0;'''''
  '''''if(($detail <= 5) and ($name eq "Note")) {$etat = 1};'''''
  '''''if($etat == 0) {'''''
    print $name, ":\n";
    my $last_count = 0;
&nbsp;
    # sorting messages by count
    my @sorted_msgs = sort { $msgs->{$b}->{'count'} <=> $msgs->{$a}->{'count'} } keys %{$msgs};
&nbsp;
    foreach my $msg (@sorted_msgs) {
        # grouping messages by number of occurrence
        print "\n", $msgs->{$msg}->{'count'}, " times:\n" unless $last_count == $msgs->{$msg}->{'count'};
        my $rms = 0;
&nbsp;
        # printing timestamp
        print '[';
&nbsp;
        if($msgs->{$msg}->{'count'} > 1) {
            # calculating rms
            $rms = int(sqrt(
                            ($msgs->{$msg}->{'count'} *
                            $msgs->{$msg}->{'sqrsum'} -
                            $msgs->{$msg}->{'sum'}) /
                            ($msgs->{$msg}->{'count'} *
                            ($msgs->{$msg}->{'count'} - 1))));
&nbsp;
            print strftime($date_format, localtime($msgs->{$msg}->{'first_occurrence'}+int($rms/2)));
&nbsp;
            print ' +/-';
&nbsp;
            # printing rms
            if($rms > 86400) {
                print int($rms/86400) , ' day(s)';
            } elsif($rms > 3600) {
                print int($rms/3600) , ' hour(s)';
            } elsif($rms > 60) {
                print int($rms/60) , ' minute(s)';
            } else {
                print $rms, ' seconds';
            }
        } else {
            # we have got this message a single time
            print strftime($date_format, localtime($msgs->{$msg}->{'first_occurrence'}));
        }
&nbsp;
        print '] ', $msg, "\n";
        $last_count = $msgs->{$msg}->{'count'};
    }
&nbsp;
    print "\n";
  '''''}'''''
}
----
==Audit==
Si on élève le niveau de détail de "Low" à "Med", on est submergé par le très grand nombre de messages d'audit.
Pour y pallier, nous avons créé le fichier de configuration "/etc/logwatch/conf/services/audit.conf" dont voici le contenu:
----
Detail = Low
----
==Sshd-Session==
Suite au passage de la version de Fedora 40 à Fedora 41, une série de messages ont changés de non de service. Dans le fichier "/var/log/secure" (et archives) ce nom est passé de "sshd" à "sshd-session". N'étant plus traité, il a été repris dans le service "secure" de LogWatch en tant que "**Unmatched Entries**".
Par exemple, la session:
----
Oct 27 12:19:34 serverdb69 sshd[1313205]: User child is on pid 1313252
Oct 27 12:19:34 serverdb69 sshd[1313252]: Starting session: shell on pts/0 for admin from 192.168.1.2 port 51754 id 1005
Oct 27 12:26:35 serverdb69 sshd[1313252]: Connection closed by 192.168.1.2 port 51754
Oct 27 12:26:35 serverdb69 sshd[1313252]: Close session: user admin from 192.168.1.2 port 51754 id 1005
Oct 27 12:26:35 serverdb69 sshd[1313252]: Transferred: sent 404912, received 26504 bytes
Oct 27 12:26:35 serverdb69 sshd[1313252]: Closing connection to 192.168.1.2 port 51754
----
est devenue:
----
Nov 17 18:00:46 serverdb69 sshd-session[2860003]: User child is on pid 2860060
Nov 17 18:00:47 serverdb69 sshd-session[2860060]: Starting session: shell on pts/0 for admin from 192.168.1.2 port 59908 id 1005
Nov 17 18:29:38 serverdb69 sshd-session[2860060]: Connection closed by 192.168.1.2 port 59908
Nov 17 18:29:38 serverdb69 sshd-session[2860060]: Close session: user admin from 192.168.1.2 port 59908 id 1005
Nov 17 18:29:38 serverdb69 sshd-session[2860060]: Transferred: sent 136416, received 18392 bytes
Nov 17 18:29:38 serverdb69 sshd-session[2860060]: Closing connection to 192.168.1.2 port 59908
----
La solution est passée par la création d'un nouveau service "sshd-session", clone du service "sshd".
Ceci passe par la création de divers fichiers personnalisés:
* En premier on désactive le traitement du service "sshd-session" par le service "secure" de la même façon qu'il est désactivé pour le service "sshd". On crèe, pour y arriver, le fichier "/etc/logwatch/conf/services/secure.conf" qui contient une ligne:
----
$ignore_services = '''sshd-session''' sshd Pluto stunnel proftpd saslauthd imapd postfix/smtpd
----
On y a ajouté la désactivation du traitement du service "sshd-session" à la ligne d'origine du service "secure".
* On crée ensuite le fichier de configuration du service "sshd-session". On recopie le contenu du fichier "/usr/share/logwatch/default.conf/services/sshd.conf" dans le fichier "/etc/logwatch/conf/services/sshd-session.conf". On élague les commentaires dans un soucis de clareté et on le personnalise pour le service "sshd-session":
----
#
# service sshd-session
#
Title = '''"SSHD-SESSION"'''
&nbsp;
# Which logfile group...
LogFile = secure
LogFile = messages
&nbsp;
# Only give lines pertaining to the sshd-session service...
*OnlyService = '''sshd-session'''
*RemoveHeaders
&nbsp;
# Set to No to disable IP lookups
$sshd_ip_lookup = Yes
----
* Il faut maintenant créer le script de ce nouveau service "sshd-session". On ne doit rien changer au script du service "sshd". Au lieu de le recopier, nous avons opté pour un lien symbolique avec la commande:
ln -s /usr/share/logwatch/scripts/services/sshd /etc/logwatch/scripts/services/sshd-session
Maintenant, dans le rapport, nous aurons deux sections liées à Sshd: SSHD et SSHD-SESSION qui sont complémentaires.
Note: Si nous avions laissé le même titre, nous aurions eu quand même deux sections d'où le changement de titre pour pouvoir les différencier.
=Exécution=
Ce programme s'exécute une fois par jour via le service Cron. Cette commande se trouve dans le fichier "/etc/cron.daily/0logwatch". Il traite les journaux de la veille et envoie un message à l'utilisateur "root" par défaut.
Il est possible de l'exécuter en direct via la commande:
logwatch
Dans ce cas, le résultat s'affiche directement à l'écran et concerne tous les services de la veille.
On peut se limiter à un service en le précisant. Par exemple pour le service "postfix, cette commande:
logwatch --service postfix
donne:
----
################### Logwatch 7.9 (07/22/23) ####################
        Processing Initiated: Fri Aug 18 15:11:28 2023
        Date Range Processed: yesterday
                              ( 2023-Aug-17 )
                              Period is day.
        Detail Level of Output: 0
        Type of Output/Format: stdout / text
        Logfiles for Host: serverdb.home.dom
##################################################################
&nbsp;
--------------------- Postfix Begin ------------------------
&nbsp;
    2.419M  Bytes accepted                          2,536,824
    2.419M  Bytes delivered                          2,536,824
========  ==================================================
&nbsp;
      119  Accepted                                  100.00%
--------  --------------------------------------------------
      119  Total                                      100.00%
========  ==================================================
&nbsp;
      530  Connections                                    530
      530  Disconnections                                530
      119  Removed from queue                            119
      119  Delivered                                      119
&nbsp;
        1  Postfix start                                    1
        1  Postfix stop                                    1
&nbsp;
---------------------- Postfix End -------------------------
&nbsp;
###################### Logwatch End #########################
----
D'autre paramètres sont disponibles; un mérite notre attention: "--detail" suivi du niveau: ("Low", "Med" ou "High").
La commande équivalente à celle ci-dessus devient:
logwatch --service postfix --detail Low
Par défaut ce sont les événements de la veille qui sont synthétisés. Si on veut ceux du jour même, on utilise l'option suivante:
logwatch --service postfix --range Today
Si le service n'est pas utilisé ou si aucune information n'est retenue, il n'y a pas d'affichage.
Ces commandes exécutées en direct sont intéressantes pour vérifier le bon fonctionnement d'un service suite à toute modification ou dans une phase de test.
=Compléments=
Voyez l'article sur la [[LINUX:Surveiller la température|Surveillance de la température]]; il permet d'ajouter une section liée à la surveillance des températures de la carte mère (CPU, GPU,...) et des disques durs.





Dernière version du 17 novembre 2024 à 21:15


retour à la Surveillance


But

Ce logiciel effectue un résumé des activités de la veille du serveur sur base majoritairement des journaux. Il met l'accent sur les problèmes et alertes rencontrés. Le résultat est envoyé par messagerie. En le visionnant, j'ai pu mettre le doigt sur divers problèmes et prendre les mesures correspondantes.


Principe

Ce logiciel passe en revue divers services. Chaque analyse s'effectue sur base d'un script. Ces scripts font souvent appel à des scripts généraux ou fonctions. Les scripts des services peuvent être divisés en deux grands groupes:

  • ceux qui effectuent des commandes directes tels l'analyse des espaces disques ou des températures du matériel
  • ceux qui analysent des groupes de journaux ciblés ("logfiles").

Chaque service est piloté par un fichier de configuration.

Par défaut ce sont les journaux de la veille et donc clôturés qui sont analysés.


Installation

La première étape consiste à installer le paquet:

dnf install logwatch


Configuration

Structure

Les fichiers de configuration personnalisables se trouvent dans le répertoire "/etc/logwatch" et ceux de référence dans le répertoire "/usr/share/logwatch".

La structure est identique; si un fichier du même nom se retrouve aux deux endroits, celui sous le répertoire "/etc/logwatch" a la priorité. Donc pour adapter la configuration, il suffit de recopier le fichier correspondant du répertoire "/usr/share/logwatch" dans le répertoire "/etc/logwatch" ou du moins de reprendre dans ce fichier, le paramètre que l'on veut changer. Normalement on ne devrait rien changer.


Voici la structure des éléments principaux:

  • Les répertoires "/etc/logwatch/scripts/services" et "/usr/share/logwatch/scripts/services" contiennent les scripts qui effectuent l'analyse des journaux ou effectuent des commandes ciblées. Ces fichiers portent le nom du service correspondant.
  • Les répertoires "/etc/logwatch/conf/services" et "/usr/share/logwatch/default.conf/services" regroupent les divers paramètres de configuration du service correspondant. Dans le cas d'une analyse de journaux, ils font référence à un groupe de journaux. C'est la variable "LogFile" qui redirige cette action vers un fichier du point suivant. Ces fichiers portent le nom du service correspondant suivis de l’extension ".conf".
  • Les répertoires "/etc/logwatch/conf/logfiles" et "/usr/share/logwatch/default.conf/logfiles" définissent un groupe de journaux à analyser. Ces fichiers portent le nom du groupe de journaux correspondant suivis de l'extention ".conf".
  • Les fichiers de configuration des répertoires "/etc/logwatch/conf" et ""/usr/share/logwatch/default.conf" définissent les paramètres généraux du logiciel. Nous y retrouvons les fichiers:
    • logwatch.conf : fichier de configuration de LogWatch
    • override.conf : fichier contenant les paramètres qui auront la priorité absolue sur tout autre défini autre part
    • ignore.conf : fichier contenant les lignes du rapport final que l'on ne veut plus voir apparaître

Il est à noter que certains services n'analysent aucun fichier journal mais ont leur propre type de traitement.


Quelques exemples:

  • Analyse des journaux du service "SSHD"

Ce service porte le nom de "sshd". Il utilisera le script "/usr/share/logwatch/scripts/services/sshd", le fichier de paramétrage "/usr/share/logwatch/default.conf/services/sshd". Ce dernier fait référence aux groupes de journaux ""/usr/share/logwatch/default.conf/logfiles/secure" "/usr/share/logwatch/default.conf/logfiles/messages". On y retrouve notamment parmi bien d'autres les journaux "/var/log/secure" et "/var/log/messages". Dans ces journaux, ils vont repérer les lignes correspondant au processus "sshd".

  • Analyse des espaces disques

Ce service porte le nom de "zz-disk_space". Il utilisera le script "/usr/share/logwatch/scripts/services/zz-disk_space", le fichier de paramétrage "/usr/share/logwatch/default.conf/services/zz-disk_space". Il n'analyse aucun journal et donc ne fera pas appel à un fichier groupe de journaux. Mais dans le script, on y retrouvera l'appel à la commande de ligne "df".


Fichier "logwatch.conf"

En premier lieu, on peut s'intéresser au fichier de configuration générale: "logwatch.conf" et spécialement au paramètres suivants:

  • MailTo = root : le message est envoyé à l'utilisateur "root"
  • Detail = Low : le niveau de détail affiché est au plus bas. Je conseille de le laisser à cette valeur. On peut le mettre à la valeur "Med" pour obtenir plus de détails mais on risque d'être submergé avec pour conséquence de ne plus regarder le rapport. Ne parlons pas du niveau maximal "High".


Fichier "override.conf"

Ce fichier sert à outrepasser certains paramètres définis autre part.

Nous l'avons utilisé pour l'activation de services désactivés.

Dans le fichier de fonfiguration générale "/usr/share/logwatch/default.conf/logwatch.conf", les services "zz-network" et "zz-sys" sont désactivés. Nous désirons les réactiver sauf le service "eximstats". Cette opération demande une configuration spéciale.

Dans le fichier de configuration "/etc/logwatch/conf/override.conf", on ajoute les lignes suivantes:


logwatch: Service =
logwatch: Service = All
logwatch: Service = "-eximstats"

La première ligne annule les options "Service" dans le fichier "/usr/share/logwatch/default.conf/logwatch.conf" (première partie de la variable : "logwatch: Service"). On les remplace par l'activation de tous les services ("All") sauf le service "eximstats" ("-eximstats").


Fichier "ignore.conf"

Ce fichier permet d'occulter les lignes du rapport final que l'on ne veut plus voir affiché.

Par exemple dans le rapport, on voit apparaître une sous-section "**Unmatched Entries**". En dessous viennent les lignes des journaux qui ne sont pas traitées par les scripts.

Bien sûr, il faut se demander d'où vient cette entrée dans le journal et essayer de résoudre le problème. Ceci provient en majorité d'un problème lors de l'exécution d'un processus qu'il faut corriger. En second recours, on peut créer son propre script ou son propre service: ce qu'on verra par la suite au travers de divers exemples. Enfin si cette ligne est récurrente et non problématique, on ajoute un extrait identifiant de la ligne problématique dans le fichier "ignore.conf". On l'agrément d'expressions régulières pour tenir compte de certains mots variables comme d'PID d'un processus.

Par exemple, nous avons les entrées suivantes:


...
 **Unmatched Entries**
    userhelper: pam_timestamp(chkrootkit:session): updated timestamp file `/var/run/pam_timestamp/root/unknown': 1 Time(s)
...
 **Unmatched Entries**
    Reexecution requested from client PID 540752 ('systemctl') (unit dnf5-automatic.service)...: 1 Time(s)
    Reexecution requested from client PID 541061 ('systemctl') (unit dnf5-automatic.service)...: 1 Time(s)
    Reload requested from client PID 541212 ('systemctl') (unit dnf5-automatic.service)...: 1 Time(s)
    Reload requested from client PID 541270 ('systemctl') (unit dnf5-automatic.service)...: 1 Time(s)
...

Notre fichier "ignore.conf" est modifié en conséquence en ajoutant une chaîne de mots identifiants sur base de ces lignes:


userhelper: pam_timestamp\(chkrootkit:session\): updated timestamp file `/var/run/pam_timestamp/root/unknown'
Reload requested from client PID (\d+) \('systemctl'\)
Reexecution requested from client PID (\d+) \('systemctl'\)

On remarque qu'un back-slash a été ajouté devant les parenthèses. En effet les parenthèses définissent un bloc d'une expression régulière. Ces back-slash évite ce type de traitement. En deuxième ligne et suivantes, nous avons affaire au PID; ce n° est variable et numérique. Nous les traitons par l'expression régulière "(\d+)" qui remplace tout mot constitué de chiffres ("\d" pour digit et "+" pour multiples).

Dès lors le rapport devient:


...
 **Unmatched Entries**
 1 Ignored Lines
...
 **Unmatched Entries**
 4 Ignored Lines
...

Notons qu'à l'avenir, ces lignes dans les journaux peuvent être prises en compte dans les scripts du logiciel à la suite d'une mise à jour.


Personnalisation de la configuration

Normalement la configuration fournie est opérationnelle mais en fouillant cette configuration, nous avons été amené à l'adapter. Malgré tout, il arrive que l'on veuille contourner quelques cas. Rien de tel que de le faire au travers d'exemples.


Voici quelques cas rencontrés. Certains font suite à des modifications personnelles.


PHP

En analysant le fichier "/usr/share/logwatch/default.conf/logfiles/php.conf", nous avons remarqué que les noms des journaux n'étaient pas les bons et en outre, nous avions ajouté le support des divers anciennes versions de PHP provenant les dépôts de Remi.

Nous avons donc créé le fichier de configuration "/etc/logwatch/conf/logfiles/php.conf" dont voici le contenu hors commentaires sur base du fichier "/usr/share/logwatch/default.conf/logfiles/php.conf":


# PHP (8.3) de la distribution
LogFile = php-fpm/error.log
LogFile = php-fpm/www-error.log
# PHP (7.4, 8.0 et 8.1) du dépôt de Remi
#LogFile = /var/opt/remi/php74/log/php-fpm/error.log
#LogFile = /var/opt/remi/php74/log/php-fpm/www-error.log
LogFile = /var/opt/remi/php80/log/php-fpm/error.log
LogFile = /var/opt/remi/php80/log/php-fpm/www-error.log
LogFile = /var/opt/remi/php81/log/php-fpm/error.log
LogFile = /var/opt/remi/php81/log/php-fpm/www-error.log
 
# PHP (8.3) de la distribution
Archive = php-fpm/error.log-*
Archive = php-fpm/www-error.log-*
# PHP (7.4, 8.0 et 8.1) du dépôt de Remi
#Archive = /var/opt/remi/php74/log/php-fpm/error.log-*
#Archive = /var/opt/remi/php74/log/php-fpm/www-error.log-*
Archive = /var/opt/remi/php80/log/php-fpm/error.log-*
Archive = /var/opt/remi/php80/log/php-fpm/www-error.log-*
Archive = /var/opt/remi/php81/log/php-fpm/error.log-*
Archive = /var/opt/remi/php81/log/php-fpm/www-error.log-*


IPTABLES

Nous redirigeons les messages venant du FireWall IPtables vers le fichier "/var/log/iptables" et via le logiciel LogRotate, les archives se retrouvent dans les fichiers "/var/log/iptables-*".

Nous avons donc créé le fichier de configuration "/etc/logwatch/conf/logfiles/php.conf" dont voici le contenu hors commentaires sur base du fichier "/usr/share/logwatch/default.conf/logfiles/iptables.conf":


LogFile = iptables
Archive = iptables-*
*ApplyStdDate


MariaDB

Il existe un service "mysql" mais il est non opérationnel pour MariaDB principalement suite au format de la date précédent tout message.

Dans ce script, le format de la date est '%y%m%d %H:%M:%S', par exemple "230814 12:03:45" alors que nous avons besoin d'un format '%Y-%m-%d %H:%M:%S', par exemple "2023-08-14 12:03:45". En outre, nous souhaitions ne voir apparaître les messages "Note" que dans le cas d'un niveau de détail "High". De plus le nom des journaux étaient autres que ceux de MySQL. L'ordre des types de messages a été modifié. Nous avons donc créé un nouveau service sur base des fichiers du service "mysql".

Nous avons créé le fichier de configuration "/etc/logwatch/conf/logfiles/mariadb.conf" dont voici le contenu hors commentaires:


LogFile = mariadb/mariadb.log
Archive = mariadb/mariadb.log-*
*ExpandRepeats

Nous avons créé aussi le fichier de configuration "/etc/logwatch/conf/services/mariadb.conf" dont voici le contenu hors commentaires:


Title = "MariaDB"
LogFile = mariadb

Et nous avons adapté le script "/etc/logwatch/scripts/services/mariadb" sur base du script "/usr/share/logwatch/scripts/services/mysql" hors commentaires du début et de la fin pour ne pas surcharger la présentation. Il est écrit en Perl. Voici son contenu, en gras et en italique les modifications apportées et les lignes modifiées sont mises en commentaire:


use strict;
use Logwatch ':dates';
use Time::Local;
use POSIX qw(strftime);
 
#my $date_format = '%y%m%d %H:%M:%S';
my $date_format = '%Y-%m-%d %H:%M:%S';
 
my $filter = TimeFilter($date_format);
my $detail = exists $ENV{'LOGWATCH_DETAIL_LEVEL'} ? $ENV{'LOGWATCH_DETAIL_LEVEL'} : 0;
 
# we do not use any Date:: package (or strptime) as they are probably not available
my %month2num = ( Jan => 0, Feb => 1, Mar => 2, Apr => 3,
                  May => 4, Jun => 5, Jul => 6, Aug => 7,
                  Sep => 8, Oct => 9, Nov => 10, Dec => 11 );
 
# array of message categories (we do not use a hash to keep the order)
# first element: category name
# second element: matching regexp ($1 should contain the message)
# third element: anonymous hash ref (stores message  counts)
my @message_categories = (['Note', qr/\[Note\] (.*)$/o, {}],
                          ['Warnings', qr/\[Warning] (.*)$/o, {}],
                          ['Errors', qr/\[ERROR\] (.*)$/o, {}],
                          ['Other', qr/(.*)$/o, {}]);
 
# counting messages
while(<>) {
    my $line = $_;
    # skipping messages that are not within the requested range
    next unless $line =~ /^($filter)/o;  
 
#    $1 =~ /(\d\d)(\d\d)(\d\d)\s+(\d+):(\d+):(\d+)/;
    $1 =~ /(\d+)-(\d+)-(\d+)\s+(\d+):(\d+):(\d+)/;
 
    my $time;
 
    {
        # timelocal is quite chatty
        local $SIG{'__WARN__'}  = sub {};
        $time = timelocal($6, $5, $4, $3, $2-1, $1);
    }
 
    # Count lines with increasing number as one:
    #  [Warning] Aborted connection 107194 to db: ...
    $line =~ s/(Aborted connection) \d+ (to db)/$1 $2/;
 
    foreach my $cur_cat (@message_categories) {
        if($line =~ /$cur_cat->[1]/) {
            my $msgs = $cur_cat->[2];
            $msgs->{$1} = {count => '0',
                           first_occurrence => $time,
                           sum => 0,
                           sqrsum => 0} unless exists $msgs->{$1};
            $msgs->{$1}->{'count'}++;
            # summing up timestamps and squares of timestamps
            # in order to calculate the rms
            # using first occurrence of message as offset in calculation to
            # prevent an integer overflow
            $msgs->{$1}->{'sum'} += $time - $msgs->{$1}->{'first_occurrence'};
            $msgs->{$1}->{'sqrsum'} += ($time - $msgs->{$1}->{'first_occurrence'}) ** 2;
            last;
        }
    }
}
 
# generating summary
foreach my $cur_cat (@message_categories) {
  # skipping non-requested message types
  next unless keys %{$cur_cat->[2]};
  my ($name, undef, $msgs) = @{$cur_cat};
 
  my $etat = 0;
  if(($detail <= 5) and ($name eq "Note")) {$etat = 1};
  if($etat == 0) {
    print $name, ":\n";
    my $last_count = 0;
 
    # sorting messages by count
    my @sorted_msgs = sort { $msgs->{$b}->{'count'} <=> $msgs->{$a}->{'count'} } keys %{$msgs};
 
    foreach my $msg (@sorted_msgs) {
        # grouping messages by number of occurrence
        print "\n", $msgs->{$msg}->{'count'}, " times:\n" unless $last_count == $msgs->{$msg}->{'count'};
        my $rms = 0;
 
        # printing timestamp
        print '[';
 
        if($msgs->{$msg}->{'count'} > 1) {
            # calculating rms
            $rms = int(sqrt(
                           ($msgs->{$msg}->{'count'} *
                            $msgs->{$msg}->{'sqrsum'} -
                            $msgs->{$msg}->{'sum'}) /
                           ($msgs->{$msg}->{'count'} *
                            ($msgs->{$msg}->{'count'} - 1))));
 
            print strftime($date_format, localtime($msgs->{$msg}->{'first_occurrence'}+int($rms/2)));
 
            print ' +/-';
 
            # printing rms
            if($rms > 86400) {
                print int($rms/86400) , ' day(s)';
            } elsif($rms > 3600) {
                print int($rms/3600) , ' hour(s)';
            } elsif($rms > 60) {
                print int($rms/60) , ' minute(s)';
            } else {
                print $rms, ' seconds';
            }
        } else {
            # we have got this message a single time
            print strftime($date_format, localtime($msgs->{$msg}->{'first_occurrence'}));
        }
 
        print '] ', $msg, "\n";
        $last_count = $msgs->{$msg}->{'count'};
    }
 
    print "\n";
  }
}


Audit

Si on élève le niveau de détail de "Low" à "Med", on est submergé par le très grand nombre de messages d'audit.

Pour y pallier, nous avons créé le fichier de configuration "/etc/logwatch/conf/services/audit.conf" dont voici le contenu:


Detail = Low


Sshd-Session

Suite au passage de la version de Fedora 40 à Fedora 41, une série de messages ont changés de non de service. Dans le fichier "/var/log/secure" (et archives) ce nom est passé de "sshd" à "sshd-session". N'étant plus traité, il a été repris dans le service "secure" de LogWatch en tant que "**Unmatched Entries**".

Par exemple, la session:


Oct 27 12:19:34 serverdb69 sshd[1313205]: User child is on pid 1313252
Oct 27 12:19:34 serverdb69 sshd[1313252]: Starting session: shell on pts/0 for admin from 192.168.1.2 port 51754 id 1005
Oct 27 12:26:35 serverdb69 sshd[1313252]: Connection closed by 192.168.1.2 port 51754
Oct 27 12:26:35 serverdb69 sshd[1313252]: Close session: user admin from 192.168.1.2 port 51754 id 1005
Oct 27 12:26:35 serverdb69 sshd[1313252]: Transferred: sent 404912, received 26504 bytes
Oct 27 12:26:35 serverdb69 sshd[1313252]: Closing connection to 192.168.1.2 port 51754

est devenue:


Nov 17 18:00:46 serverdb69 sshd-session[2860003]: User child is on pid 2860060
Nov 17 18:00:47 serverdb69 sshd-session[2860060]: Starting session: shell on pts/0 for admin from 192.168.1.2 port 59908 id 1005
Nov 17 18:29:38 serverdb69 sshd-session[2860060]: Connection closed by 192.168.1.2 port 59908
Nov 17 18:29:38 serverdb69 sshd-session[2860060]: Close session: user admin from 192.168.1.2 port 59908 id 1005
Nov 17 18:29:38 serverdb69 sshd-session[2860060]: Transferred: sent 136416, received 18392 bytes
Nov 17 18:29:38 serverdb69 sshd-session[2860060]: Closing connection to 192.168.1.2 port 59908

La solution est passée par la création d'un nouveau service "sshd-session", clone du service "sshd".

Ceci passe par la création de divers fichiers personnalisés:

  • En premier on désactive le traitement du service "sshd-session" par le service "secure" de la même façon qu'il est désactivé pour le service "sshd". On crèe, pour y arriver, le fichier "/etc/logwatch/conf/services/secure.conf" qui contient une ligne:

$ignore_services = sshd-session sshd Pluto stunnel proftpd saslauthd imapd postfix/smtpd

On y a ajouté la désactivation du traitement du service "sshd-session" à la ligne d'origine du service "secure".

  • On crée ensuite le fichier de configuration du service "sshd-session". On recopie le contenu du fichier "/usr/share/logwatch/default.conf/services/sshd.conf" dans le fichier "/etc/logwatch/conf/services/sshd-session.conf". On élague les commentaires dans un soucis de clareté et on le personnalise pour le service "sshd-session":

#
# service sshd-session
#
Title = "SSHD-SESSION"
 
# Which logfile group...
LogFile = secure
LogFile = messages
 
# Only give lines pertaining to the sshd-session service...
*OnlyService = sshd-session
*RemoveHeaders
 
# Set to No to disable IP lookups
$sshd_ip_lookup = Yes

  • Il faut maintenant créer le script de ce nouveau service "sshd-session". On ne doit rien changer au script du service "sshd". Au lieu de le recopier, nous avons opté pour un lien symbolique avec la commande:
ln -s /usr/share/logwatch/scripts/services/sshd /etc/logwatch/scripts/services/sshd-session


Maintenant, dans le rapport, nous aurons deux sections liées à Sshd: SSHD et SSHD-SESSION qui sont complémentaires.

Note: Si nous avions laissé le même titre, nous aurions eu quand même deux sections d'où le changement de titre pour pouvoir les différencier.


Exécution

Ce programme s'exécute une fois par jour via le service Cron. Cette commande se trouve dans le fichier "/etc/cron.daily/0logwatch". Il traite les journaux de la veille et envoie un message à l'utilisateur "root" par défaut.


Il est possible de l'exécuter en direct via la commande:

logwatch

Dans ce cas, le résultat s'affiche directement à l'écran et concerne tous les services de la veille.

On peut se limiter à un service en le précisant. Par exemple pour le service "postfix, cette commande:

logwatch --service postfix

donne:


################### Logwatch 7.9 (07/22/23) ####################
       Processing Initiated: Fri Aug 18 15:11:28 2023
       Date Range Processed: yesterday
                             ( 2023-Aug-17 )
                             Period is day.
       Detail Level of Output: 0
       Type of Output/Format: stdout / text
       Logfiles for Host: serverdb.home.dom
##################################################################
 
--------------------- Postfix Begin ------------------------
 
   2.419M  Bytes accepted                           2,536,824
   2.419M  Bytes delivered                          2,536,824
========   ==================================================
 
     119   Accepted                                   100.00%
--------   --------------------------------------------------
     119   Total                                      100.00%
========   ==================================================
 
     530   Connections                                    530
     530   Disconnections                                 530
     119   Removed from queue                             119
     119   Delivered                                      119
 
       1   Postfix start                                    1
       1   Postfix stop                                     1
 
---------------------- Postfix End -------------------------
 
###################### Logwatch End #########################

D'autre paramètres sont disponibles; un mérite notre attention: "--detail" suivi du niveau: ("Low", "Med" ou "High"). La commande équivalente à celle ci-dessus devient:

logwatch --service postfix --detail Low

Par défaut ce sont les événements de la veille qui sont synthétisés. Si on veut ceux du jour même, on utilise l'option suivante:

logwatch --service postfix --range Today


Si le service n'est pas utilisé ou si aucune information n'est retenue, il n'y a pas d'affichage.

Ces commandes exécutées en direct sont intéressantes pour vérifier le bon fonctionnement d'un service suite à toute modification ou dans une phase de test.


Compléments

Voyez l'article sur la Surveillance de la température; il permet d'ajouter une section liée à la surveillance des températures de la carte mère (CPU, GPU,...) et des disques durs.




retour à la Surveillance