SelfLinux Systemverwaltung syslog-ng Abschnitt 3 | SelfLinux-0.13.0

| syslog-ng | Autor Formatierung GFDL

#### 3 Konfigurationsdetails

Die Konfigurations-Syntax ist an C/Java/PHP angelehnt und sehr einfach gehalten. Man sollte jedoch aufpassen, Semikolons immer richtig zu setzen.

Leider gehört es zum Charakter von Linux, dass fast jeder Autor eines Paketes sich in einer eigenwilligen Konfigurations-Syntax verewigt. Wie schön wäre es, wenn gerade bei der Konfigurations-Sprache sich ein Standard durchsetzt, an den sich alle halten. Manche großen Pakete wie samba, cups, apache machen schon gute Vorgaben, die andere Paketentwickler übernehmen. Der Einstieg in neue Pakete wird so wesentlich vereinfacht, weil man nur noch wissen muss, was man konfigurieren will und nicht mehr, wie man überhaupt konfigurieren kann. Ein vielversprechender Ansatz ist http://config4gnu.sourceforge.net/docs/article.html.

Die gesamte Konfiguration erfolgt über die Datei syslog-ng.conf, die bei Debian Linux unter /etc/syslog-ng/syslog-ng.conf liegt.

In dieser Konfigurations-Datei gibt es prinzipiell folgende Einträge:

    options { option; option; .. };

Hiermit können globale Optionen festgelegt werden.

    source <identifier> { source-driver(params); ... };

Mit jeder source Zeile wird eine syslog-Quelle festgelegt.

    filter <identifier> { expression; ... };

Hiermit können beliebig viele Filter-Objekte angelegt werden, die später in der log-Zeile benutzt werden können. Expression beschreibt die Filterregel.

    destination <identifier> {dest-driver(params); ... };

Hiermit kann man Ziel-Objekte anlegen, wohin also geloggt werden soll und mit welchen Einstellungen.

    log { source(s1); source(s2); ...; filter(f1); filter(f2); ...; destination (d1);
          destination(d2); ...; flags( flag1; ...) }

Hiermit werden log-Objekte angelegt und log-Objekte sind die einzigen, die auch Aktionen ausführen, wenn sie definiert sind. In dem Log-Objekt werden zuvor definierte Objekte ( source, filter, destination) zusammengefügt und das Logging somit aktiviert.

Nochmal zum Verständnis: Man kann beliebig viele source, filter und destination-Objekte anlegen, die von sich aus gar nichts tun. Erst das Einbinden in ein log-Objekt, aktiviert eine Logausgabe. Das log-Objekt ist das einzige, was irgendwie aktiv wird.

Dieser objektorientierte Aufbau ist sehr leicht überschaubar und wartbar. Nach ein wenig Praxis wird man spüren, wie angenehm diese Form zu handeln ist.

#### 3.1 Das options Objekt

Hier kann man globale Einstellungen vornehmen. Das meiste ist für erste Gehversuche schon korrekt eingestellt, es geht hauptsächlich um Feintuning. Einige wichtige Einstellungen sind:

- sync(n-lines)
  Hiermit kann man festlegen, wieviele Log-Zeilen auflaufen sollen, bis gesynct wird, bis also die Daten tatsächlich auf der Platte abgelegt werden und nicht noch in irgendeinem Puffer im Ram stecken. Wer sicher gehen will und auch keine Performance-Probleme hat, sollte hier 0 einstellen - es wird dann sofort jede Zeile geschrieben.
- log_fifo_size(n-lines)
  Anzahl der Zeilen, die zwischengepuffert werden können. Ist wichtig, wenn mehr Logs einlaufen, als syslog-ng wegschreiben kann. Das kann z. B. passieren, wenn eine kurzzeitige Logzeilen-Flut hereinbricht. Ein typischer Wert ist 1000.

#### 3.2 Das source Objekt

Hier kann man die Quellen angeben, woher syslog-ng Meldungen empfangen soll. Unter debian Linux reicht für das normale Logging folgende Zeile:

    source src { unix-stream("/dev/log"); internal(); };

Es wird hier ein neues Source-Objekt namens src angelegt. Dieses Source-Objekt wird nun mit zwei Quellen verbunden, zum einen mit /dev/log, zum anderen mit internal. Der Typ internal steht für die Messages, die syslog-ng selber erzeugt. Die sollte man also immer mit aufnehmen. /dev/log ist vom Typ unix-stream, ein Stream mit unix-style Übertragung, was man typischerweise unter Linux nutzt. Ein ähnlicher Typ ist unix-dgram, der in BSD Systemen verwendet wird. Unter Linux funktioniert generell auch unix-dgram, es ist aber nicht so sicher, weil bei zu hoher Systemlast Logs verloren gehen können.

Weitere Möglichkeiten von Typen einer Datenquelle sind file, pipe, udp, tcp. Hiermit kann man verrückte Sachen anstellen. Im Normalfall dürfte lediglich udp/tcp noch interessant sein, mit dem syslog-ng als Loghost übers Netz fungieren kann. Er verhält sich dann genauso, wie ein syslog, der per udp lauscht. Eine vollständige udp Quelle sieht so aus:

    udp( ip(0.0.0.0) port(514) )

Wobei ip und port auch weggelassen werden können, wenn die hier angegebenen Defaultparameter genommen werden sollen. Ip steht für die IP-Adresse, auf der gelauscht werden soll. Hat ein Rechner also mehrere IP-Adressen, kann man hier Einschränkungen machen. Default ist 0.0.0.0, was auf allen Adressen lauscht. Man kann nicht angeben, das z. B. nur Logs von einem bestimmten Host angenommen werden. Port gibt den Port an, auf dem gelauscht werden soll. Default ist lt. altem syslog der Port 514.

UDP ist ein verbindungsloses Protokoll, es kann also passieren, dass bei verlorenen Paketen auch Logs verloren gehen, weil diese nicht erneut angefordert werden. Besser ist es daher, tcp einzusetzen. Konfiguriert wird es genauso, man kann auch den gleichen Port nutzen, insofern man auf das sonst dort sitzende rshell verzichten kann (seit ssh sollte die eh überflüssig sein). Bei tcp gibt es zusätzlich noch den Parameter max-connections(n), der die Anzahl der Verbindungen limitiert.

Wer allerdings von alten syslogs aus Logs entgegennehmen muss, der ist auf udp angewiesen, weil die nur udp können.

Es gibt noch eine weitere Quelle, die man evtl. nicht vergessen darf - die Kernel-Messages. Wenn man auf seinem Linux-System einen klogd laufen hat, dann holt dieser sich alle Kernelmessages aus /proc/kmsg und reicht sie an den Syslog- Daemon (hier: syslog-ng) weiter. Somit hat man diese Messages automatisch. Das dürfte bei den meisten Distributionen der Standard-Fall sein. Der klogd hat auch den Vorteil, das er manche Logs noch weiter aufbereitet, z. B. Funktionsnamen über die .map Kernel Files dekodiert. Dadurch können Probleme leichter gefunden werden.

Läuft kein klogd, so muss man diese Kernel-Messages selber abholen. Eine komplette Sourcezeile könnte dann so aussehen:

    source src { unix-stream("/dev/log"); internal(); file("/proc/kmsg");};

Manche Distributionen benutzen hier auch pipe() statt file() für /proc/kmsg.

#### 3.3 Das destination Objekt

Mit dem Destination Objekt kann man Ziele festlegen, wohin ein Log-Stream gehen soll. Normal ist dies eine Datei. Ein einfaches Ziel könnte so aussehen:

    destination syslog { file("/var/log/syslog" owner("root") group("adm") perm (0640)); };

Hier wird das Ziel mit dem Namen syslog angelegt, wobei es mit der Datei /var/log/syslog verbunden wird. Diese Datei soll mit dem Benutzer root.adm angelegt werden und 0640er Rechte haben.

Neben den file()-Optionen owner(), group(), perm() gibt es weitere, die man bei speziellen Ansprüchen nutzen kann. Eine sehr interessante Option ist die Möglichkeit, ein Ausgabeformat mit template() festzulegen. Dies hatte ich weiter oben an einem Beispiel schon verdeutlicht. Hiermit kann man sich nahezu beliebige Logfile-Formate erstellen. Das Template ist ein String, in dem Makros mit einem $MakroName eingefügt werden können.

Eine typisches Template könnte so aussehen:

    template( "[$YEAR/$MONTH/$DAY $HOUR:$MIN:$SEC] $PRIORITY $FACILITY $MESSAGE\n")

Hier wird zuerst das Datum in einer typischen Form zusammengefügt, dann die Priorität, die Facility und die Message ausgegeben.

Folgende Makros sind verfügbar:

FACILITY

Facility der Message. Das ist eine der vordefinierten Gruppen des Subsystems, von der eine Message kommt. Möglich sind hier auth, auth-priv, cron, daemon, ftp, kern, lpr, mail, mark, news, syslog, user, uucp, local0 - local7. Was welche bedeuten und welches Programm welche Facility benutzt, ist nicht immer einfach herauszufinden. Ein Beobachten der syslogs hilft am besten. Viele Programme können vor dem Kompilieren eingestellt werden, unter welcher Facility sie loggen. Das Facility-System kann man als starr und veraltet betrachten, weil es für die meisten Filteraufgaben zu grob und unflexibel ist.

PRIORITY oder LEVEL | Die Priorität der Message. Hier gibt es: debug, info, notice, warn, err, crit, alert, emerg.
TAG | Die Priorität und Facility als 2-Zeichen Hexzahl codiert.
DATE, FULLDATE, ISODATE | Das Datum in verschiedenen standardisierten Formaten.
YEAR | Das Jahr 4-stellig.
MONTH | Der Monat 2-stellig numerisch, ggf. führende 0.
DAY | Der Tag 2-stellig numerisch, ggf. führende 0.
WEEKDAY | Wochentag 3 Buchstaben, wie unter Unix gewohnt. (Mon, Tue...)
HOUR | Die Stunde 2-stellig, ggf. führende 0.
MIN | Die Minute 2-stellig, ggf. führende 0.
SEC | Die Sekunden 2-stellig, ggf. führende 0.
FULLHOST | Vollständig qualifizierter Host, also host.domain
HOST | Hostname ohne Domainzusatz.
PROGRAM | Das Programm, welches die Messages abgesetzt hat. Hierüber lässt sich oft flexibler filtern, als über die Facilitys.

MSG oder MESSAGE

Die eigentliche Message. Da es im alten syslog keine Möglichkeit gab, das Programm oder den Prozess mitzuloggen, hat es sich als Standard herausgebildet, in die Message als erstes das Programm mit Prozessnummer anzugeben (Programm[ps-id]: ), welches die Message ausgab. Bei Unterprozessen eines Programmes, wird normal Programm/Unterprozess[ps-id]: verwendet. Erst hinter dem Doppelpunkt beginnt die eigentliche Message. Verlassen kann man sich jedoch auf diese Regel nicht, Ausnahmen gibt es immer wieder.

Es gibt bei file() einen leistungsfähigen Mechanismus, die Makro-Substitution für den Dateinamen. So kann man sich dynamische Logfilenamen generieren. Hier kann man die gleichen Makros wie für template() benutzen. Ein

    destination mylog { file("/var/log/syslog-$HOST" owner("root") group("adm") perm(0640)); };

loggt z. B. jeden Host in in eine getrennte Datei in der Form syslog-MeinErsterHost, syslog-NochEinHost. Natürlich muss man hier auch vorsichtig sein, um DoS- Attacken nicht Tür und Tor zu öffnen. Wer jedoch spezielle Möglichkeiten des Loggens braucht, kommt mit diesem Feature vielleicht weiter.

Neben file gibt es noch folgende Ziel-Typen bzw. Ziel-Treiber: tcp, udp, unix- stream, unix-dgram, fifo, usertty, program.

Udp oder tcp nutzt man ähnlich, wie schon bei dem Source-Objekt beschrieben. Als Ziel angegeben, schickt der syslog-ng nun diesen Log-Stream zu einem anderen Rechner per tcp oder udp. Ein Beispiel:

    destination a_udp { udp( "192.168.0.12" port(514) ); };

Hier sollen an den udp-Port 514 des Rechners mit der IP 192.168.0.12 Messages verschickt werden. Port 514 ist sowieso Default, könnte hier also auch weggelassen werden.

Hier gilt auch: Udp nimmt man aus Kompatibilitätsgründen, weil sich dann syslog-ng wie ein altes syslog verhält. Tcp ist das sicherere Verfahren, weil bei diesem verbindungsorientierten Protokoll Pakete nicht verloren gehen können.

Auch udp ist relativ sicher, es werden nicht regelmäßig Packete verloren gehen, vor allem nicht im lokalen Netzwerk. Nur wenn Hardware oder Leitungen defekt sind, kommt es zu Datenverlusten. Aber auch tcp kann durch einen kaputte Leitung nichts mehr schicken, es kann lediglich bei einer kurzen Störung erneut versenden. Man sollte sehen, dass udp Jahrzehnte erfolgreich für diese Aufgabe eingesetzt wird.

Mit usertty kann man Meldungen auf dem Terminal eines Benutzers ausgeben, der natürlich eingeloggt sein muss. Hier ein Beispiel:

    destination admin_tty { usertty(admin); };

Sollen Meldungen an alle eingeloggten Benutzer gehen, nimmt man:

    destination warn_to_all { usertty(*); };

#### 3.4 Das filter Objekt

Filter Objekte legen fest, wie Meldungen von einem Source-Objekt gefiltert werden sollen. Hiermit lassen sich also gewünschte Messages aus dem gesamten Datenstrom eines Source-Objektes herauspicken. Und das ist gut, wenn man z.B. in einem Ziel nur bestimmte Meldungen loggen möchte. Auch der alte syslog hat eine einfache Filtersprache, um Logausgaben in verschiedene Logdateien zu schreiben.

Mit syslog-ng kann man wesentlich erweitert und verfeinert filtern.

Ein typisches Filterobjekt könnte so definiert werden:

    filter f_cnews { level(notice, err, crit) and facility(news); };

Hier werden alle Meldungen durchgelassen, die vom Level oder der Priority auf notice, err oder crit stehen und die die Facility news haben.

Filterfunktionen lassen sich mit and, or, not verknüpfen und auch klammern. Somit kann man sehr leistungsfähige Filterkonstrukte erstellen.

Wer nicht genau weiß, wie and, or, not aufgelöst werden, sollte besser einmal zuviel klammern, als sich später zu wundern, warum was merkwürdiges bei heraus kommt. Das hilft auch anderen, die die Konfiguration verstehen wollen und auch nicht so genau bescheid wissen. Kurz gesagt bindet and mehr als or mehr als not. Ganz ähnlich wie Punktrechnung vor Strichrechnung kommt. a or b and c ist was anderes wie (a or b) and c.

Folgende Filterfunktionen gibt es:

- facility(facility1,facility2,...)
  Lass alle Messages durch, die dieser Facility entsprechen.
- level(prio1, prio2,...) (oder synonym priority())
  Lass alle Messages durch, die der angegebenen Priorität/Level entsprechen.
- program(regexp)
  Alle Meldungen, die vom Programm kommen, worauf regexp passt, werden durchgelassen. Hierbei ist regexp ein regulärer Ausdruck. Hat man Whitespaces im Programmnamen, sollte man den Ausdruck zwischen doppelte Anführungsstriche setzen.
- host(regexp)
  Filterung nach Host, woher die Message kommt, ebenfalls regulärer Ausdruck. Ein Tipp, wenn du nichts von regulären Ausdrücken verstehst: Nimm einfach den Hostnamen, z. B. so: host(myhost). Genau genommen müsstest du host("^myhost$") schreiben.
- match(regexp)
  Dies lässt nur Meldungen durch, wo die eigentliche Message auf dieses Muster passt. Dies ist ein sehr leistungsfähiger Mechanismus, lassen sich doch so ganz gezielt Meldungen herausfischen. Es gibt fast nichts, was man nicht mit regulären Ausdrücken erschlagen könnte.
- filter(filter_name)
  Um kompliziertere Filterregeln zu erstellen, kann man mehrere Filter zu einem neuen Filterkonstrukt zusammenfügen. Hiermit kann man also andere Filter in einem neuen Filter aufrufen. Damit kann man verschachtelte Filterkonstrukte erstellen. Es ist oft auch für die Lesbarkeit besser, zuerst mehrere Teilfilter zu definieren, die man dann in einer weiteren Filterregel zusammenfügt.

Mach keine Meisterschaft daraus, möglichst komplizierte Konfigurationen zu produzieren. Durch komplizierte Filterregeln kann man das hier durchaus schaffen. Das zeigt zwar deine intellektuellen Fähigkeiten, produziert aber schwer wartbare Konfig-Dateien. Mach es so einfach wie möglich, andere werden es dir danken.

#### 3.5 Das log Objekt

Alle bisherigen Objekte waren Vorarbeiten, um jetzt Zeilen zu generieren, die wirklich Aktionen auslösen. Denn ohne die log-Objekte würde gar nichts passieren. Die anderen Objekte sind nur Daten-Definitionen. Die log-Objekte führen das eigentliche Logging aus, in dem sie die zuvor definierte Source-, Destination- und Filter-Objekte zu einer Log-Aktion verbinden. Eine typische Zeile sieht so aus:

    log { source(src); filter(f_syslog); destination(syslog); };

Es wird hier also vom Source src gelesen, diese Messages durch den filter f_syslog geschickt und dann zum Ziel syslog geschrieben.

Mehrere Sourcen bindet man mit mehreren source()-Statements ein.

    log { source(src); source(src1); filter(f_syslog); destination(syslog); };

Mehrere Filter und sogar mehrere Ziele lassen sich nach gleichem Schema einbinden.

Hinter destination() lässt sich auch noch flags() angeben, mit dem man erweitere Funktionalitäten festlegen kann.