Graylog Logserver einrichten

10. August 2015

 

Betreibt man selbst Webseiten bzw. Online-Shops oder betreut man Webseiten für Kunden, kommt man eigentlich nicht umhin, auch die anfallenden Applikations- und ggf. auch die Webserver-Logs zu überwachen oder zumindest regelmässig in irgendeiner Form auszuwerten. Wie war der Traffic, gab es kritische Fehler in der Anwendung, warum waren die Verkäufe an Tag X so schlecht, aber an Tag Y so gut, wurde der Server evtl. angegriffen und wenn ja, wie… Antworten auf solche Themen und Fragestellungen findet man meist auch in Log-Dateien, die beim täglichen Betrieb anfallen.

Da hier aber oft mehrere Gigabyte an Daten pro Woche oder zumindest pro Monat anfallen können, ist es natürlich eine Herkules-Aufgabe, all die Log-Dateien manuell auszuwerten – auch Grep & Co. helfen da sicher nur bedingt weiter :)

Wir haben uns hier mögliche Tools und Dienste angesehen und sind schliesslich aufgrund der Features und nicht zuletzt der Möglichkeit, einen zentralen Log-Server selbst hosten zu können, bei Graylog 2 gelandet.

Zur Installation stehen diverse Pakete bereits, u.a. gibt es fertige VMs, man kann per Puppet/Chef usw. installieren, es gibt Installationen über Docker, Vagrant, OpenStack, AWS, usw. – hier sollte wirklich für jeden etwas dabei sein.

Wir haben uns eine Jiffybox eingerichtet und dort ein Graylog Debian Paket plus Elasticsearch sowie MongoDB installiert. Die Einrichtung verlief relativ problemlos, wir mussten lediglich mit den IPs für Graylog / Elasticsearch etwas experimentieren, Graylog-interne IPs konnten auf 127.0.0.1, für Elasticsearch ging aber nur die öffentliche IP, sonst konnte Graylog keine Verbindung aufbauen, also haben wir für Elasticsearch in „/etc/graylog/server/server.conf“ und „/etc/elasticsearch/elasticsearch.yml“ jeweils die öffentliche IP der Jiffybox eingetragen.

Auf dem Logserver stehen dann vier Services zur Verfügung, die man wie folgt starten kann:

service mongod start
service elasticsearch start
service graylog-server start
service graylog-web start

Danach sollte nach wenigen Augenblicken das Graylog-Webinterface unter Port 9000 zur Verfügung stehen:

http://123.456.789:9000/

Graylog Login

Nun geht es daran, Daten in Graylog zu bekommen. Hier gibt es verschiedenste Wege und Plugins. Um z.B. Daten aus PHP in Graylog zu bekommen, bietet sich die Verwendung des GELF-PHP Plugins an. Auch für Log4PHP gibt es z.B. ein Plugin.

Beispielhaft kann mit GELF-PHP wie folgt eine Log-Nachricht per UDP an Graylog gesendet werden:

$this->transport = new Gelf\Transport\UdpTransport($config['gelf_host'], $config['gelf_port'], 
Gelf\Transport\UdpTransport::CHUNK_SIZE_LAN);
$this->publisher = new Gelf\Publisher();
$this->publisher->addTransport($this->transport);
$this->logger = new Gelf\Logger($this->publisher, $this->channel);


$message = new Gelf\Message();
$shortMsg = $msg;
if(strlen($shortMsg) > $this->summary_length) {
    $shortMsg = substr($shortMsg, 0, $this->summary_length) . " ...";
}
$message->setShortMessage($shortMsg)
    ->setLevel($psrLogLevel)
    ->setFullMessage($msg)
    ->setFacility($this->channel)
;
$this->publisher->publish($message);

Weitere Beispiele finden sich hier.

Das Problem dabei war allerdings für uns, dass die Log-Daten in diesem Fall unverschlüsselt per UDP übertragen werden, was bei geschäftskritischen Daten natürlich ein No-Go ist. Leider unterstützt GELF-PHP hier keine Verschlüsselung o.ä. Also mussten wir uns auf die Suche machen, wie man den Transport der Nachrichten verschlüsseln kann.

Eine erste Möglichkeit, die wir für die Verschlüsselung einer UDP-Übertragung getestet haben, war die Verwendung von „socat“ als Netzwerk-Tunnel in Verbindung mit „auto-ssh“, um dauerhaft einen SSL-Tunnel vom Application-Server zum Log-Server offen zu halten. Im Prinzip sendet man damit Daten per UDP über einen definierten Port an localhost, diese werden von socat in TCP-Pakete umgewandelt und verschlüsselt an einen Remote-Server weitergeleitet. Auf dem Remote-Server ist wiederum socat installiert, die Daten werden entschlüsselt, von TCP wieder nach UDP gewandelt und dann als UDP-Pakete an einen definierten Graylog-Port gesendet, es geht also von

(PHP) Client | UDP => TCP => Log-Server | TCP => UDP (Graylog)

Auf der Konsole startet man dann z.B. für einen Cient:

socat -lf /var/log/socat.log -d -d -d -T 300 -s udp-listen:12201,reuseaddr,fork tcp:localhost:5353 &

Klingt kompliziert – ist es auch :) Ausserdem beendete sich socat immer wieder mal, wenn eine Weile keine Daten mehr ankamen, sodass wir noch ein Shellscript schreiben mussten, das per Cronjob minütlich prüft, ob noch socat-Prozesse laufen und wenn nicht, den Prozess neu startet.

Trotzdem ging hin und wieder eine wichtige Log-Meldung verloren, sodass wir uns schliesslich nach einer Alternative umsehen mussten.

Nach einiger Recherche standen für uns die Nutzung von Logstash (plus TCP-Plugin) oder die Übertragung der Log-Daten über „rsyslog“ (welches ebenfalls per TCP oder UDP versenden kann und auch eine Verschlüsselung über SSH/TLS unterstützt) zur Auswahl. Da auf den Servern bereits rsylog lief und wir nicht unbedingt auf allen betroffenen Clients noch Java installieren wollten, entschieden wir uns für die rsyslog-Alternative.

rsyslog ist sehr mächtig, unterstützt diverse Log-Kanäle, bietet Templating für die Formatierung von Nachrichten, kann lokal oder remote loggen, Daten weiterleiten, filtern usw. Es gibt sogar Möglichkeiten, direkt in Mysql, Elasticsearch, MongoDB usw. zu loggen. Wir verwenden das „imfile“-Plugin, das auch beliebige Dateien überwachen und dann in beliebige Kanäle weiterleiten kann.
Damit wir auch Wildcards in Dateinamen nutzen können, mussten wir rsylog noch auf die aktuelle Version 8.x bringen. So können wir nun neben Standard-Apache-Logs (die man direkt über Direktiven in der Apache-Config an (r)syslog weiterleiten kann) auch unsere eigenen Applikations-Logs mit rsyslog „überwachen“ und per TCP mit TLS verschlüsselt an Graylog weiterleiten.

Die Konfiguration von rsyslog über TLS wird z.B. hier ganz gut erklärt. Wichtig ist zuerst, die TLS Zertifikate zu generieren, wie z.B. hier beschrieben. Für Graylog muss man den TLS-Key allerdings noch konvertieren:

openssl pkcs8 -topk8 -inform pem -in key.pem -outform pem -nocrypt -out log.key.pem

In Graylog muss man natürlich einen entsprechenden „Input“ („Syslog TCP“, mit TLS aktiviert) anlegen und den gewünschten Port angeben, welcher die Daten dann entgegen nimmt:

Graylog TCP Syslog Input mit TLS

Hier trägt man dann den konvertierten TLS Private Key ein.

WICHTIG: die Keys / Zertifikate müssen natürlich sowohl auf dem Logserver als auch auf dem Client (rsyslog) Server lesbar sein, also z.B. nicht unbedingt im „/root/“-Verzeichnis liegen.

Ob auch Daten vom „rsyslog-Client“ auf dem Logserver ankommen, kann man auf dem Logserver mit „tcpdump“ überprüfen:

apt-get install tcpdump
tcpdump port 12202

Der Port ist natürlich der, den man für den Graylog Input vergeben hat und an den der Log-Client über „rsyslog“ sendet.

Ob rsyslog z.B. die eigenen Log-Dateien ausliest/überwacht, kann man dort z.B. mit

tail -f /var/log/syslog

testen, hier sollten Log-Meldungen aus der Anwendung auftauchen, sobald sie in die jeweilige Log-Datei geschrieben werden.

Wie üblich haben wir  auch für diese rsyslog-Konfiguration ein kleines Puppet-Modul geschrieben, sodass die Konfiguration problemlos auf beliebigen Server eingebunden bzw. schnell wieder hergestellt werden kann. Das Modul wird dann einfach im jeweiligen Server Puppet-Manifest eingebunden und v.a. der Pfad zu den Log-Dateien angegeben, z.B.:

class { proudsourcing_rsyslog:
  appLogfilesPath   => "/var/www/myshop/application/logs/log-*.php"
}

So weit, so gut … da der Teufel wie immer im Detail steckt, könnten wir noch viel mehr zum Thema Graylog und sichere Übertragungen schreiben (z.B. wie man die Daten in Graylog auswertet, Dashboards erstellt, rsyslog Konfigurationen usw.), aber das war genug Text für heute – bei Fragen gerne unten kommentieren!

Happy logging! :)