Zarządzanie logami systemowymi (rsyslog) - filtrowanie i przekierowywanie logów do plików

Red Hat 6.x / CentOS 6.x
Filtrowanie logów systemowych i przekierowywanie ich części do różnych plików jest bardzo rozbudowanym tematem. Kompleksowe jego poznanie wymaga pewnie wielu godzin spędzonych z dokumentacją, ale taka znajomość dla zwykłego administratora nie jest sprawą najwyższej wagi. Zaprezentuję tu jak można zrealizować najczęstsze (czyt: takie, które kiedykolwiek miałem okazję realizować) przypadki rozdzielania logów w zależności od ich ważności czy pochodzenia.
Całość konfiguracji przeprowadzamy oczywiście w pliku /etc/rsyslog.conf

Filtrowanie logów podsystemów

Filtrowanie logów pochodzących z jakiegoś podsystemu lub o zadanym priorytecie jest chyba najprostsze do realizacji, między innymi dlatego, że gotowy szablon tego rozwiązania mamy już umieszczony w /etc/rsyslog.conf.

Definicje filtrów opierają się o tzw. selektory i mają format FACILITY.PRIORITY.

FACILITY określa podsystem, który produkuje dany wpis, i może przyjmować wartości (słowne lub numeryczne): kern (0), user (1), mail (2), daemon (3), auth (4), syslog (5), lpr (6), news (7), uucp (8), cron (9), authpriv (10), ftp (11) oraz local0 do local7 (16-23).

PRIORITY jak sama nazwa wskazuje to priorytet wiadomości, o możliwych wartościach: debug (7), info (6), notice (5), warning (4), err (3), crit (2), alert (1), oraz emerg (0).

Dla obu pozycji możliwe jest użycie znaku *, który wskazuje na wszyskie facilities lub priorities.

Dla przykładu, weźmy dwa wpisy z pliku odpowiedzialne za filtrowanie.

# Log all the mail messages in one place.
mail.*                                                  -/var/log/maillog

# Log cron stuff
cron.*                                                  /var/log/cron

Pierwszy wpis zgodnie z komentarzem umieszcza wszystkie logi facility mail w dedykowanym pliku, drugi robi to samo z logami pochodzącymi z cron-a.
Oba wpisy różnią się w swojej składni minusem przed ścieżką pliku docelowego. Umieszczenie minusa przed nazwą pliku spowoduje, że log taki będzie zapisywany synchronicznie.

Możliwe jest również definiowanie wielu pozycji w jednej linii. Jeśli potrzebujemy zdefiniować kilka priorytetów dla jednego facility, wartości oddzielamy od siebie przecinkiem, np:

mail.info,debug                               /var/log/mail.info

Definiowanie przekierowania kilku facilities do jednego pliku, użyjemy średnika, np:

mail.crit;kern.crit                             /var/log/critical

Dodatkowo istnieje możliwość użycia operatora wykluczenia w postaci wykrzyknika. Taki wpis przekeiruje wszystkie logi facility, oprócz debug oraz notice:

 daemon.!debug,!notice                            /var/log/deamons

Filtrowanie logów zależnie od ich właściwości

Drugim typem filtrowania jakiego możemy użyć jest filtr oparty o właściwości wpisów. Ma on odmienną konstrukcję od prezentowanego wcześniej, a jego schemat wygląda następująco:

:wlasciwosc, operator-porownania, "wartosc"

Właściwości jak i operatory są odgórnie zdefiniowane, a pełna ich lista jest dostępna w pliku /usr/share/doc/rsyslog-5.8.10/property_replacer.html.

Najczęściej używanymi właściwościami są:
* msg czyli typ wiadomości
* fromhost - pochodzące z konkretnego hosta (przy logowaniu z serwerem centralnym)
* fromhost-ip - pochodzące z konkretnego IP
* programname - generowane przez konkretny program

Operatorami porównania mogą być:
* isequal
* contains
* startswith
* regex

Nazwy samych operatorów opisują doskonale realizowane przez nie porónania, więc nie ma sensu tego tłumaczyć.Opcjonalnie możemy przed operatorem użyć znaku negacji !.

Wartością w regule może być dowolny ciąg znaków, którego będziemy wyszukiwać w danym wpisie.

Dla przykładu utworzymy filtr oddzielający logi konkretnego programu.

Do utworzenia takiego filtra należy zidentyfikować pod jaką nazwą dany program występuje w procesie logowania. Możemy posłużyć się wpisami w /var/log/messages, gdzie każdy z programów przedstawia się nazwą w piątej kolumnie (po miesiącu, dniu, godzinie i hostname'ie), np:

Sep 23 05:01:53 rsyslog-c1 sshd[3591]: Accepted password for root from 192.168.1.6 port 61960 ssh2
Sep 23 06:29:23 rsyslog-c1 su: pam_unix(su-l:session): session opened for user test by root(uid=0)

Oczywiście w konfiguracji filtra pomijamy pid procesu zawarty w nawiasie.
Przyjmijmy, że chcemy w osobnym pliku umieszczać logowania poprzez ssh, oraz w jeszcze innym wszelkie zmiany użytkownika w trakcie sesji, czyli reagować na su. Konfiguracja jest oczywista:

:programname, isequal, "sshd"                           /var/log/sshd
:programname, isequal, "su"                             /var/log/su

Kolejnym przykładem może być filtrowanie wszystkich logów, zawierających jakiś błąd. Filtr taki będzie mieć postać:

:msg, contains, "error"                          /var/log/errorlog

Odfiltruje wszystkie wiadomości zawierające słowo kluczowe error i umieści w odrębnym pliku.

Taka składnia może być przydatna w przypadku serwera centralnego rsyslog. Umożliwia ona rozdzielenie logów pochodzących z różnych hostów na osobne pliki, np odnosząc się do naszej przykładowej realizacji centralnego rsysloga:

:fromhost, isequal, "rsyslog-c1.my.domain"        /var/log/rsyslog-c1/messages

Regułka przekieruje wszytkie wpisy z hosta rsyslog-c1.my.domain do pliku /var/log/rsyslog-c1/messages

Filtry warunkowe

Filtrów warunkowych możemy użyć do łączenia kilku filtrów właściwościowych opisanych wcześniej, oraz umieszczania ich w pętlach if-else. Ja nie potrzebuję na codzień bardzo zaawansowanych filtrów, dlatego najczęściej używam ich do przekierowywania logów przesyłanych do serwera centralnego.
Z pomocą prostego warunku możemy umieszczać różne logi z hosta zdalnego w różnych plikach., np:

if $programname == 'sshd' and $fromhost == 'rsyslog-c1.my.domain' then /var/log/rsyslog-c1/sshd
:fromhost, isequal, "rsyslog-c1.my.domain"        /var/log/rsyslog-c1/messages

Oddzielimy w ten sposób logi generowane przez sshd na maszynie rsyslog-c1 do oddzielnego pliku, podczas gdy wszystkie logi z tego hosta trafiają do pliku messages w tym samym katalogu.

Pomijanie zapisanych pozycji

Testując powyższą przykładową konfigurację na serwerze można zauważyć, że wpisy dotyczące sshd pojawiają się w pliku /var/log/rsyslog-c1/sshd, ale niepotrzebnie dublują się również w pliku /var/log/rsyslog-c1/messages. Jest na to prosta rada - po zapisaniu części logów do pliku należy poinformować rsyslog, że nie chcemy ich już więcej używać:

if $programname == 'sshd' and $fromhost == 'rsyslog-c1.my.domain' then /var/log/rsyslog-c1/sshd
if $programname == 'sshd' and $fromhost == 'rsyslog-c1.my.domain' then ~
:fromhost, isequal, "rsyslog-c1.my.domain"        /var/log/rsyslog-c1/messages

Znak tyldy w ścieżce zapisu logu spowoduje usunięcie pozycji z pamięci rsyslog.

Dynamiczne generowanie nazw plików

Podczas używania serwera centralnego dość szybko znudzi się nam ręczne określanie nazw plików i tworzenie reguł dla każdego hosta zdalnego z osobna. Pomocna okazuje się tutaj możliwość dynamicznej definicji nazw plików.

Proces polega na określeniu szablonu nazwy w oparciu o zmienne elementy logów. Elementami mogą być (lista zawiera te najczęściej wykorzystywane, a pełną można znaleźć "googlając" hasło RSYSLOG_DebugFormat):
* %FROMHOST% - czyli przesłane z hosta
* %FROMHOST-IP% - przełane z IP
* %HOSTNAME% - hostname zawarty w logu
* %syslogtag% - tag wiadomości
* %programname% - nazwa programu generującego log
* %PROCID% - id procesu
* %MSGID% - id wiadomości (wg standardu IETF)
* %TIMESTAMP% - znacznik czasu z wiadomości
* %msg% - treść wiadomości

Sama definicja szablonu nazwy takiego pliku wygląda następująco:

$template NazwaSzablonu,"/sciezka/z/wykorzystaniem/tagow/np/%HOSTNAME%"

Użycie tak zdefiniowanego szablonu sprowadza się do użycia jego nazwy poprzedzonej znakiem ? zamiast nazwy konkretnego pliku, np:

*.* ?NazwaSzablonu

Tyle teorii, teraz jakiś działający przykład do przetestowania. Scenariusz jest następujący: kilka serwerów klienckich przesyła swoje logi do serwera centralnego. Serwer centralny zapisuje logi z poszczególnych hostów w osobnych katalogach o nazwach zgodnych z hostname klienta. Z logów odławiać będziemy zdarzenia z programu sshd, które będą trafiać do osobnego pliku w katalogu hosta.
Realizacja zadania sprowadzi się do kilku linijek, i obsłuży obecne i przyszłe hosty zdalnie logujące:

$template HostMessages,"/var/log/%hostname%/messages"
$template HostSshd,"/var/log/%hostname%/sshd"

:programname, isequal, "sshd"   ?HostSshd
:programname, isequal, "sshd"   ~

*.* ?HostMessages

Pierwsze dwie linijki definiują nam dynamiczne nazwy plików (a w zasadzie dynamiczne są katalogi, w których są pliki). Linijka trzecia przekierowuje logi z sshd do odpowiedniego pliku, podczas gdy czwarta "discarduje" je, aby nie trafiały już do pliku ogólnego. Ostatnia linijka kieruje pozostałe logi z hosta do pliku messages w katalogu zgodnym z nazwą hosta.
Voila, oto całość definicji, która równie dobrze sprawdza się dla 2 co i dla 200 hostów zdalnie logujących do serwera centralnego.

Jak pisałem na początku, temat filtrów rsyslog jest bardzo obszerny, a powyższy tekst ociera się o elementy, które okazały się przydatne w moim administratorskim bycie. Zainteresowanym osiągnięciem mistrzostwa w tej dziedzinie polecam dokumentację - zarówno systemową jak i  projektu ze strony rsyslog.

Brak komentarzy:

Prześlij komentarz