Elasticsearch Logstash Kibana Cluster
Inhaltsverzeichnis
- 1 Redundanter Elasticsearch Logservercluster mit Logstash und Kibana4
- 1.1 Einleitung
- 1.2 Hardware
- 1.3 Aufbau / Umsetzung
- 1.4 Hinweis
- 1.5 Vorarbeiten
- 1.6 Installation von Keepalived
- 1.7 Installation der Daten Nodes
- 1.8 Elasticsearch Konfiguration
- 1.9 Elasticsearch Quorum Nodes
- 1.10 Logstash Elasticsearch Daten Nodes
- 1.11 Installation von Nginx
- 1.12 Kibana (4)
- 1.13 Reboot
- 1.14 Checkliste
- 1.15 Abschluss
- 1.16 Quellen
- 1.17 Spende
Redundanter Elasticsearch Logservercluster mit Logstash und Kibana4
Einleitung
Da ich für die Firma einen neuen Logserver benötigte, habe ich mich auf dem "Markt" umgeschaut und mich für die gewählte Kombination wie in der Überschrift entschieden. Diese Anleitung ist mehr eine Notiz für mich, damit ich es später wieder nachvollziehen kann :-)
Hardware
Als Hardware habe ich zwei Lenovo (ehemals IBM) X3250 M5 (Typ 5458) Server im Einsatz, mit einer Standardausstattung von 16GB Ram und zwei 1TB SAS Platten im Raid HW Verbund. Um einen möglichst hohen Nutzwert aus der Hardware zu ziehen, läuft auf der Hardware Proxmox 3.x als Hypervisor. Darauf wurden dann pro physischen Host zwei Debian Jessie VMs eingerichtet. In der Summe stehen damit vier virtuelle Server bereit.
Aufbau / Umsetzung
Um eine gewisse Ausfallsicherheit zu haben, sollte der Elastisearchcluster über mindestens drei Nodes verfügen. Dabei replizieren zwei Nodes die Daten untereinander, die dritte Instanz dient lediglich als "Wahlstimme, um Split-Brain Situationen zuvorzukommen. Durch die Gebäudesituation (zwei Brandabschnitte) zzgl. anderer Gegebenheiten, setze ich auf zwei Wahlstimmen, sodass letzten Endes zwei Eleasticsearchserver die Daten verwalten und zwei Instanzen lediglich als Quorum herhalten.
- Loghost-01 - Proxmox
- elasearch01 - VM - 192.168.23.1
- elaquorum-01 - VM - 192.168.23.3
- Loghost-02 - Proxmox
- elasearch02 - VM - 192.168.23.2
- elaquorum-02 - VM - 192.168.23.4
Die Netzwerkverbindungen werden hier zwar über zwei separate VLANs geschoben (intern / extern), aber das ist ohnehin für jede Installation anders. Wichtig an dieser Stelle ist nur, dass Elasticsearch zwar mittels Multicast seine Clustermitglieder selbst finden kann, dieses Prozedere jedoch in vielen Konstellationen nicht die richtige Wahl ist. Daher setzte ich auf Unicast, was auch von der Firewall her einfacher ist.
Da ich ebenfalls kein allzu großer Verfechter von komplexer Software bin, setzte ich statt auf Pacemaker und Co, auf ein "simples" keepalived, welches mir meine externe IP Adresse auf die jeweils verbliebenen / aktive Node umzieht.
Auf beiden Datennodes (elasearch-01/02) läuft jeweils ein Nginx, Logstash und Kibana4. Somit kann ich auch die jeweilige Node direkt ansprechen, sofern ein Zugriff auf die interne IP erlaubt ist. Die Clients die ihre Logdaten an den Logserver senden wollen, sprechen dagegen immer nur die externe IP Adresse an. Da Logstash (der die Daten annimmt) per Definition nicht als Rootuser läuft und damit auch keinen privilegierten Port (514) verwenden darf, wird per IPTables der Port 514 auf 5144 umgeleitet. Man könnte zwar z.B. auch Rsyslog einbinden, der die Daten annimmt und dann an Logstash weiterreicht (entweder via Logdatei od. via TCP/UDP/Unix Socket), aber diese Lösung hat mir einfach besser gefallen.
Der komplette Pfad sieht dann wie im folgenden aus:
Die Qorumserver habe ich jetzt außen vor gelassen, da die wirklich nicht viel tun außer da zu sein.
Hinweis
Um diese Server zu installieren, nutze ich zum einen Fai für die Basisinstallation von Jessie und für die Nacharbeiten Puppet. Da es zu sehr ausschweifen würde auch noch Puppet mit zu erläutern, werde ich nur das fertige Ergebnis hier aufzeigen, jedoch nicht die Puppet Manifests etc. Was ich jedoch tun kann, hier die von mir genutzten Puppet Module auflisten:
- arioch-keepalived
- elasticsearch-elasticsearch
- elasticsearch-logstash
- evenup-kibana
- puppetlabs-apt
- saz-rsyslog
- jfryman-nginx
Der Rest ergibt sich aus den Abhängigkeiten der jeweiligen Module.
Sofern man keine Technik alla Pupper/Chef/Ansible nutzt, sollte man sich entweder ClusterSSH besorgen, oder man klont am Ende die fertige Maschine und ändert nur noch den Hostname/IP Adresse etc. allerdings ist das doch ein wenig fehleranfällig. |
Hinweis
Die Anleitung hier geht ganz stupide die einzelnen Abschnitte durch. Dabei wird erst einmal keine Rücksicht darauf genommen, ob der Dienst nach der jeweiligen Installation und Konfiguration danach funktioniert. Sobald alles durchlaufen wurde, folgt ganz am Ende ein kompletter Neustart aller VMs. Damit wird dann sichergestellt, dass alle Dienste (neu-)gestartet werden. Daher erst nach dem Neustart alles prüfen, ob alle Dienste passend laufen.
Vorarbeiten
Mit zu den ersten Dingen die getan werden sollten, ist es die IP Adressen und Hostnamen in der /etc/hosts zu hinterlegen. Das erspart einem unnötige Probleme, wenn der DNS Dienst einmal versagt:
- /etc/hosts
192.168.23.1 elasearch-01.mydomain.local elasearch-01 192.168.23.2 elasearch-02.mydomain.local elasearch-02 192.168.23.3 elaquorum-01.mydomain.local elaquorum-01 192.168.23.4 elaquorum-02.mydomain.local elaquorum-02 |
Installation von Keepalived
Da der Zugriff auf das Webfrontend und die eingehenden Logmeldungen nur über eine "öffentliche/externe" laufen soll, muss dafür gesorgt werden, dass die IP Adresse an der aktiven Node (elasearch-01 oder elasearch-02) hochgefahren wird. Dafür eignet sich der Keepalived. Dieser Dienst kommuniziert via VRRP Protokoll und kann Aktionen bei einem Ausfall einer Node ausführen. Auf meinem System habe ich zwei Netzwerkkarten (Interfaces):
- eth0 -> internes Interface
- eth1 -> externes Interface
Da eth1 keine weitere aktive IP Adresse hat, sieht die /etc/network/interfaces entsprechend so aus:
- /etc/network/interfaces
auto eth1 iface eth1 inet manual pre-up ifconfig $IFACE up post-down ifconfig $IFACE down |
Damit wird das Interface ohne aktive IP Adresse hochgefahren. Nun kann keepalived selbst installiert werden.
# apt-get install keepalived -y |
Die Konfiguration ist in diesem Fall sehr übersichtlich:
elasearch-01
- /etc/keepalived/keepalived.conf
vrrp_instance VI_ELASEARCH { # Dieses Interface interessiert uns interface eth1 state MASTER virtual_router_id 50 priority 101 advert_int 1 garp_master_delay 5 authentication { auth_type PASS auth_pass secret } track_interface { eth0 } # Hier ist die öffentliche / externe Adresse virtual_ipaddress { 10.10.10.1/24 dev eth1 } # Darüber soll keepalived kommunzieren unicast_src_ip 192.168.23.1 # Die Nachbarn, elasearch-01 und elasearch-02 unicast_peer { 192.168.23.1 192.168.23.2 } } |
elasearch-02
- /etc/keepalived/keepalived.conf
vrrp_instance VI_ELASEARCH { interface eth1 state MASTER virtual_router_id 50 priority 101 advert_int 1 garp_master_delay 5 authentication { auth_type PASS auth_pass secret } track_interface { eth0 } virtual_ipaddress { 10.10.10.1/24 dev eth1 } unicast_src_ip 192.168.23.2 unicast_peer { 192.168.23.1 192.168.23.2 } } |
Installation der Daten Nodes
Nun werden die Nodes eingerichtet, die auch Daten vorhalten und nicht zu den Qorums gehören. Für die essentiellen Programme gibt es entsprechende Debian Pakete, daher hinterlegen wir die Quellen in /etc/apt/sources.list.d/
- /etc/apt/sources.list.d/debian_elastic.list
deb http://packages.elastic.co/elasticsearch/1.7/debian stable main |
- /etc/apt/sources.list.d/debian_logstash.list
deb http://packages.elastic.co/logstash/1.5/debian stable main |
# wget -O - http://packages.elasticsearch.org/GPG-KEY-elasticsearch | apt-key add - # apt-get update && apt-get upgrade |
Elasticsearch benötigt Java, daher installieren wie die passende JRE, allerdings in der "Headless" Version, die uns einiges an Plattenplatz erspart:
# apt-get install default-jre-headless -y |
Dann kommen Elasticsearch und Logstash.
# apt-get install elasticsearch logstash curl |
Elasticsearch Konfiguration
Ohne jetzt näher auf die Elasticsearch Eigenschaften einzugehen (die kann man hier nachlesen), sollte man vorab wissen, dass mehrere Elasticsearch Instanzen parallel auf einem Server laufen können. Die haben dann ihre jeweils eigenen Parameter und Konfigurationen.
Die Konfigurationsdateien:
- /etc/default/elasticsearch-* - Defaulteinstellungen der jeweiligen Elasticsearch Instanz.
- /etc/elasticsearch/ - Hauptkonfigurationsverzeichnis
Da bei mir Puppet automatisch die passenden Init/Systemd Scripte für die jeweilige Instanz hinterlegt, habe ich nichts mehr zu tun, für die anderen sollte jedoch /etc/default/elasticsearch angepasst werden:
- /etc/default/elasticsearch
# Wo ist unser Konfigurationsverezichnis für diese Instanz mit Namen "mylog" (vorzugsweise Cluster-/Instanzname) CONF_DIR=/etc/elasticsearch/mylog # Die passende Datei dazu CONF_FILE=/etc/elasticsearch/mylog/elasticsearch.yml ES_GROUP=elasticsearch ES_HOME=/usr/share/elasticsearch ES_USER=elasticsearch # Wo sollen die (Debug) Logs hin LOG_DIR=/var/log/elasticsearch/mylog MAX_OPEN_FILES=65535 |
Das Verzeichnis /etc/elasticsearch/mylog existiert natürlich noch nicht und muss erstellt werden:
# mkdir -p /etc/elasticsearch/mylog /var/log/elasticsearch/mylog # chown elasticsearch:elasticsearch -R /etc/elasticsearch/ /var/log/elasticsearch/ |
Da wir Elasticsearch im Cluster betreiben wollen, benötigen wir dazu eine passende Konfiguration. Die wichtigen Parameter sind:
- Die (interne) IP Adresse unter der die Nodes miteinander kommunizieren
- Der Clustername
- Anzahl der Nodes im Cluster und wer von ihnen auch Daten bereitstellt (und nicht nur Quorum ist)
eleasearch-01
- /etc/elasticsearch/mylog/elasticsearch.yml
--- bootstrap: mlockall: true # Clustername -> Hier mylog cluster: name: mylog discovery: zen: # Es muss mindestens zwei Master Nodes geben, in einem 3 Node Cluster. Dies schützt vor Split-Brain und dient der Mehrheitsfindung \ # In diesem Setup wäre auch ein minimum_master_nodes: 3 ok, da es zwei Quorums gibt. minimum_master_nodes: 2 ping: # Multicast ausschalten, wie weisen die Nodes dediziert zu multicast: enabled: false timeout: 30s # Hier Unicast aktivieren und die Mitglieder auflisten (hier Name, statt IP) unicast: hosts: - elasearch-01 - elasearch-02 - elasearch-quorum-01 - elasearch-quorum-02 gateway: # Wir haben in Summe 4 Nodes expected_nodes: 4 # Aber es reicht, wenn 3 Nodes da sind, damit der Cluster seine Arbeit aufnimmt recover_after_nodes: 3 recover_after_time: 5m http: host: 127.0.0.1 # Nur eine Node erhält auch eine Kopie der Daten (ein Original + eine Kopie + ein Quorum = Cluster) index: number_of_replicas: 1 # Diese Node darf Master sein node: master: true # und auch Daten halten (!) data: true # Der Name dieser Node name: elasearch-01.mydomain.local # Die (schnell) wachsenden Datenmengen werden hier abgelegt path: data: /var/lib/elasticsearch/mylog # Die interne IP Adresse, an der die Node Daten annehmen darf/soll -> =! externe IP transport: host: 192.168.23.1 |
eleasearch-02
Hier nun unsere zwei Datennode, mit der sich elasearch-01 synchronisiert und Daten austauscht.
- /etc/elasticsearch/mylog/elasticsearch.yml
--- bootstrap: mlockall: true cluster: name: mylog discovery: zen: minimum_master_nodes: 2 ping: multicast: enabled: false timeout: 30s unicast: hosts: - elasearch-01 - elasearch-02 - elaquorum-01 - elaquorum-02 gateway: expected_nodes: 4 recover_after_nodes: 3 recover_after_time: 5m http: host: 127.0.0.1 index: number_of_replicas: 1 node: master: true data: true name: elasearch-02.mydomain.local path: data: /var/lib/elasticsearch/mylog transport: host: 192.168.23.2 |
Elasticsearch Quorum Nodes
Nachdem nun die Elasticsearch DATEN Nodes soweit fertig sind, verbleiben nur noch die zwei Quorum Nodes. Deren einzige Aufgabe ist es Split-Brain Situationen nicht entstehen zu lassen. Es ist zwar auch Möglich mit wirklich nur zwei Nodes zu arbeiten, aber der Autor (ich) hatte da sehr häufig Probleme, einen grünen Cluster Status zu erhalten. Da die Quorum Nodes keine Datenhaltung betreiben, benötigen die VMs nur sehr wenige Ressourcen. Als Festplattenspeicher genügen 20GByte und als Ram 512MByte bis maximal 1GByte an Arbeitsspeicher. Die Installation ist nahezu identisch und auch die Konfigurationsdatei ist fast genau gleich. Der einzige Unterschied ist "data: false" sowie die IP Adresse von transport:
elaquorum-01
- /etc/elasticsearch/mylog/elasticsearch.yml
--- bootstrap: mlockall: true cluster: name: mylog discovery: zen: minimum_master_nodes: 2 ping: multicast: enabled: false timeout: 30s unicast: hosts: - elasearch-01 - elasearch-02 - elaquorum-01 - elaquorum-02 gateway: expected_nodes: 4 recover_after_nodes: 3 recover_after_time: 5m http: host: 127.0.0.1 index: number_of_replicas: 1 node: # Ich darf Master sein ... master: true # aber darf _keine_ Daten halten, da ich nur Quorum sein soll data: false name: elaquorum-01.mydomain.local path: data: /var/lib/elasticsearch/mylog transport: host: 192.168.23.3 |
elaquorum-02
Nun unsere zweite Quorum Node
- /etc/elasticsearch/mylog/elasticsearch.yml
--- bootstrap: mlockall: true cluster: name: mylog discovery: zen: minimum_master_nodes: 2 ping: multicast: enabled: false timeout: 30s unicast: hosts: - elasearch-01 - elasearch-02 - elaquorum-01 - elaquorum-02 gateway: expected_nodes: 4 recover_after_nodes: 3 recover_after_time: 5m http: host: 127.0.0.1 index: number_of_replicas: 1 node: # Ich darf Master sein ... master: true # aber darf _keine_ Daten halten, da ich nur Quorum sein soll data: false name: elaquorum-02.mydomain.local path: data: /var/lib/elasticsearch/mylog transport: host: 192.168.23.4 |
Logstash Elasticsearch Daten Nodes
Nun steht die Basiskonfiguration der Elasticsearch Nodes und können Logstash einrichten. Dies findet nur auf den Datennodes statt und nicht auf den Quorum Nodes.
Die Aufgabe von Logstash besteht einfach nur darin die eingehenden Meldungen die entweder von Syslog Clients kommen (udp/tcp), oder aus Logdateien (/var/log/...) passend vorzufiltern und dann dem Elasticsearch zu übergeben.
Installation
Die Debian Quellen sollten ja bereits vorhanden sein, daher reicht:
# apt-get install logstash -y |
Konfiguration
Die Basiskonfiguration ist eigentlich sehr simpel gestrickt:
- /etc/logstash/conf.d/logstash.conf
input { # Dieser Input wird z.B. für logstashforwder genutzt # Beispiel SSL Kommando: openssl req -x509 -batch -nodes -newkey rsa:2048 -keyout logstash-forwarder.key -out logstash-forwarder.crt -days 1829 lumberjack { type => "logs" port => 5000 ssl_certificate => "/etc/ssl/certs/logstash-forwarder.crt" ssl_key => "/etc/ssl/private/logstash-forwarder.key" } # Hat man Rsyslog 6.4.x -> http://www.rsyslog.com/doc/v8-stable/configuration/modules/omelasticsearch.html tcp { type => syslogjson port => 5500 codec => "json" } # Standard TCP Syslog, allerdings unprivilegierter Port, Weiterleitung von 514 erfolgt via IPTables tcp { port => 5144 type => "syslog" } # Standard UDP Syslog, allerdings unprivilegierter Port, Weiterleitung von 514 erfolgt via IPTables udp { port => 5144 type => "syslog" } } # An dieser Stelle übergeben wir die gefilterten Nachricht an Elasticsearch output { elasticsearch { host => ["elasearch-01","elasearch-02"] cluster => "informatiklog" protocol => "transport" flush_size => 2000 } # Praktisch um zu sehen, warum etwas _nicht_ funktioniert. stdout { codec => rubydebug } } # ... # .... jetzt die Filter |
Konfiguration
Die Basiskonfiguration ist eigentlich sehr simpel gestrickt:
- /etc/logstash/conf.d/logstash.conf
input { # Dieser Input wird z.B. für logstashforwder genutzt # Beispiel SSL Kommando: openssl req -x509 -batch -nodes -newkey rsa:2048 -keyout logstash-forwarder.key -out logstash-forwarder.crt -days 1829 lumberjack { type => "logs" port => 5000 ssl_certificate => "/etc/ssl/certs/logstash-forwarder.crt" ssl_key => "/etc/ssl/private/logstash-forwarder.key" } # Hat man Rsyslog 6.4.x -> http://www.rsyslog.com/doc/v8-stable/configuration/modules/omelasticsearch.html tcp { type => syslogjson port => 5500 codec => "json" } # Standard TCP Syslog, allerdings unprivilegierter Port, Weiterleitung von 514 erfolgt via IPTables tcp { port => 5144 type => "syslog" } # Standard UDP Syslog, allerdings unprivilegierter Port, Weiterleitung von 514 erfolgt via IPTables udp { port => 5144 type => "syslog" } } # An dieser Stelle übergeben wir die gefilterten Nachricht an Elasticsearch output { elasticsearch { host => ["elasearch-01","elasearch-02"] cluster => "mylog" protocol => "transport" flush_size => 2000 } # Praktisch um zu sehen, warum etwas _nicht_ funktioniert. stdout { codec => rubydebug } } # ... # .... jetzt die Filter |
Filter
Nun kommt der für mich komplizierte Teil: die Filter. Die Filter sind der Kernprozess von Logstash und ist maßgeblich dafür verantwortlich, wie gut sich die späteren Logmeldungen im Kibana verwerten lassen.
Die Filter können in zwei Variationen hinterlegt werden:
- Bedingung und Pattern in einem
- Bedingung und Pattern getrennt ablegen
Für die getrennte Haltung gibt es:
- /etc/logstash/conf.d/ -> Konfigurationsverzeichnis
- /etc/logstash/patterns/ -> Patternverzeichnis
Da es sehr stark darauf ankommt von wem und wie die Meldungen reinkommen, ist es nicht sehr sinnvoll hier meine gesamte Filterkonfiguration einzustellen, aber zumindest die Basics sollte vorhanden sein. Die größte Schwierigkeit besteht meistens darin, die reinkommenden Daten zu normalisieren, sodass Logstash die Daten passend im JSON Format übergeben kann. Gerade mit Hinblick auf die Datumsformate kann sehr viel schief gehen, sodass man nicht das gewünschte Verhalten erreicht.
- Original Quelle: https://gist.github.com/robinsmidsrod/019ef6d415dbc3f9e0f1
Syslog
Der wichtigste Filter dürfte Syslog sein, da auf ihm verschiedene andere aufbauen:
- /etc/logstash/conf.d/logstash.conf
#### SYSLOG filter { if [type] == "syslog" { # Parse syslog messages grok { # match => { "message" => "%{SYSLOGTIMESTAMP:syslog_timestamp} %{SYSLOGHOST:syslog_hostname} %{DATA:syslog_program}(?:\[%{POSINT:syslog_pid}\])?: %{GREEDYDATA:syslog_message}" } match => [ "message", "<%{POSINT:syslog_pri}>(?:%{SYSLOGTIMESTAMP:syslog_timestamp}|%{TIMESTAMP_ISO8601:syslog_timestamp8601}) (?:%{SYSLOGHOST:syslog_hostname})? %{PROG:syslog_program}(?:\[%{POSINT:syslog_pid}\])?: %{GREEDYDATA:syslog_message}" ] add_field => [ "received_at", "%{@timestamp}" ] add_field => [ "received_from", "%{host}" ] add_tag => [ "grokked" ] } if "grokked" in [tags] { # Convert syslog priority number into facility and severity name/number syslog_pri {} # Parse timestamp if [syslog_timestamp8601] { # Parse proper ISO8601 syslog timestamps date { match => [ "syslog_timestamp8601", "ISO8601" ] # RSYSLOG_ForwardFormat } } else { if [syslog_timestamp] { # Parse traditional syslog timestamps date { match => [ "syslog_timestamp", "MMM d HH:mm:ss", "MMM dd HH:mm:ss" ] } } } # If has a hostname, replace host if [received_from] { mutate { replace => [ "host", "%{syslog_hostname}" ] } } # Replace message with syslog_message (if message is available) if [syslog_message] { mutate { replace => [ "message", "%{syslog_message}" ] } } else { mutate { replace => [ "message", "(empty message)" ] } } # Rename some fields mutate { rename => [ "syslog_program", "program" ] rename => [ "syslog_pid", "pid" ] rename => [ "syslog_severity", "severity" ] rename => [ "syslog_facility", "category" ] } # Clean up redundant parameters mutate { convert => [ "syslog_facility_code", "integer" ] convert => [ "syslog_severity_code", "integer" ] convert => [ "pid", "integer" ] remove_field => [ "syslog_timestamp", "syslog_timestamp8601", "syslog_hostname", "syslog_message", "syslog_pri" ] } } # Extract remote address from sshd log lines if [program] == "sshd" { grok { match => { "message" => [ "Invalid user %{USERNAME:username} from %{IP:remote_addr}", "Failed %{WORD:login_method} for invalid user %{USERNAME:username} from %{IP:remote_addr} port %{POSINT:port} ssh2", "pam_unix(sshd:auth): authentication failure; logname= uid=%{POSINT:uid} euid=%{POSINT:euid} tty=ssh ruser= rhost=%{IPORHOST:remote_addr}(?: user=%{USERNAME:username})?", "PAM %{POSINT} more authentication failures; logname= uid=%{POSINT:uid} euid=%{POSINT:euid} tty=ssh ruser= rhost=%{IPORHOST:remote_addr}(?: user=%{USERNAME:username})?", "Did not receive identification string from %{IPORHOST:remote_addr}" ] } } # Filter bottom end -> do no touch if "_grokparsefailure" not in [tags] { if [remote_addr] =~ /%{HOST}/ { dns { resolve => [ "remote_addr" ] action => "replace" } } } } # Extract remote address from fail2ban log lines if [program] == "fail2ban.actions" { grok { match => { "message" => "WARNING \[%{WORD:service}\] %{WORD:action} %{IP:remote_addr}" } } if "_grokparsefailure" not in [tags] { mutate { lowercase => [ "action" ] } } } # # Get rid of the tags field, as it should be empty # mutate { # remove_field => [ "tags" ] # } # Add visitor geolocation information if remote_addr is available if [remote_addr] { geoip { source => "remote_addr" } } } } |
Diese Zeilen würden ausreichen, um eine funktionierende Konfiguration zu erhalten. Am Ende im Quellen-Bereich finden sich noch ein paar weitere Filter für Logstash(Grok).
IPTables Umleitung
Da Logstash auf Port 5144 lauscht und der Standardsyslog Port 514 ist, leiten wir diesen per IPTables einfach um. Dazu öffnen wir die entsprechende Ports und leiten sie um:
- Ein Beispiel:
... -A INPUT -s 10.10.10.0/24 -p tcp -m multiport --ports 5000,514,5144 -m comment --comment "112 allow logstash and syslog tcp" -j ACCEPT -A INPUT -s 10.10.10.0/24 -p udp -m multiport --ports 5000,514,5144 -m comment --comment "112 allow logstash and syslog udp" -j ACCEPT ... -A PREROUTING -d 10.10.10.1/32 -p tcp -m multiport --dports 514 -m comment --comment "113 forward syslog udp to elasearch" -j DNAT --to-destination 10.10.10.1:5144 -A PREROUTING -d 10.10.10.1/32 -p udp -m multiport --dports 514 -m comment --comment "114 forward syslog udp to elasearch" -j DNAT --to-destination 10.10.10.1:5144 ...
Die müssten natürlich für die eigene Umgebung angepasst werden :-)
Es muss natürlich dafür gesorgt werden, dass kein anderer Dienst diesen Port blockiert, also z.B. Rsyslog, Syslog oder auch syslog-ng. Diese Dienste müssen entsprechend darauf angepasst werden. |
Installation von Nginx
Kibana4 bringt zwar einen eigenen Webdienst mit, allerdings sollte man nach Möglichkeit die Benutzer nicht direkt auf diesen zugreifen lassen, zumal Nginx einfach mehr Möglichkeiten der Absicherung mitbringt. Die Konfiguration hält sich sehr stark in Grenzen, da im Grunde nur eine Proxy Konfiguration erfolgt. Das Ganze lässt sich natürlich auch mit dem Apachen lösen, aber man muss ja auch mal über den Tellerrand schauen:
# apt-get install nginx apache2-utils -y # htpasswd -c /etc/nginx/htpasswd admin <passwort eintippen> |
Die (SSL) Konfiguration ist dementsprechend sehr einfach gehalten.
- /etc/nginx/sites-enabled/log.mydomain.local.conf
server { listen *:443 ssl; server_name log.mydomain.local; ssl on; ssl_certificate /etc/ssl/certs/log.mydomain.local.pem; ssl_certificate_key /etc/ssl/private/log.mydomain.local.key; ssl_session_cache shared:SSL:10m; ssl_session_timeout 5m; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA; ssl_prefer_server_ciphers on; index index.html index.htm index.php; access_log /var/log/nginx/ssl-log.mydomain.local.access.log combined; error_log /var/log/nginx/ssl-log.mydomain.local.error.log; location / { # Kibana4 lauscht auf Port 5601 proxy_pass http://localhost:5601; proxy_read_timeout 90; proxy_connect_timeout 90; proxy_redirect off; } # Es dürfen nur Benutzer drauf, mit dem entsprechenden User:passwort in dieser Datei auth_basic Restricted; auth_basic_user_file /etc/nginx/htpasswd; } |
Die Konfiguration lässt die Möglichkeit auf, statt über die öffentliche Adresse auch gezielt die jeweilige Node anzusprechen. Man weiß ja nie.
Kibana (4)
Um nun die Logs bequem durchsuchen zu können, wird oftmals [Kibana] verwendet. Die Handhabung bzw. Installation ist recht einfach. Leider gibt es dafür aktuell noch keine Debianpakete, weshalb die Installation (und damit auch die Pflege) von Hand durchgeführt werden muss. Kibana wird in diesem Fall nach /opt installiert.
Installation
- Archiv herunterladen und auspacken:
# cd /opt # wget https://download.elastic.co/kibana/kibana/kibana-4.1.2-linux-x64.tar.gz # wget https://download.elastic.co/kibana/kibana/kibana-4.1.2-linux-x64.tar.gz.sha1.txt # sha1sum -c kibana-4.1.2-linux-x64.tar.gz.sha1.txt # tar xzf kibana-4.1.2-linux-x64.tar.gz # ln -s kibana-4.1.2-linux-x64 kibana |
Dann noch einen passenden Benutzer erzeugen, unter dem Kibana laufen soll:
# useradd -r -d /opt/kibana -s /bin/sh kibana |
Das war es auch fast schon. Im Verzeichnis /opt/kibana/config findet sich noch die Datei kibana.yml in der noch diverse Einstellungen vorgenommen werden können. Die Standardeinstellungen können jedoch so verbleiben (Port 5601 / elasticsearch_url), da der Zugriff über Nginx stattfindet.
Da kein Init/Systemd Script mitgeliefert wird, muss eins erstellt werden:
- /etc/systemd/system/kibana4.service
[Service] ExecStart=/opt/kibana/bin/kibana Restart=always StandardOutput=syslog StandardError=syslog SyslogIdentifier=kibana4 User=kibana Group=kibana Environment=NODE_ENV=production [Install] WantedBy=multi-user.target |
Und am Ende noch den Dienst aktivieren (aber noch nicht starten):
# systemctl enable kibana4 |
Damit ist Kibana vorerst (shell- seitig) fertig konfiguriert.
Reboot
Sofern nun alles installiert und eingerichtet wurde, können nun alle VMs (elasearch-01/elasearch-02/elaquorum-01/elaquorum-02) neugestartet werden. Im Anschluss beginnt dann die Prüfung, ob die Dienste laufen.
Checkliste
Nun folgt die Checkliste :-)
- Keepalived
- Läuft keepalivd ?
- systemctl status keepalived
- Öffentliche IP Adresse (hier im Test 10.10.10.1) erreichbar?
- Wenn nicht -> Blockiert Firewall Kommunikation ?
- Syntax Fehler in der Konfiguration ?
- Elasticsearch
- Läuft der Prozess ? (ps ax | grep elastic)
- systemctl status elasticsearch
- Wird an den passenden Ports gelauscht (9200 (http) / 9300 (transport))
- Ist der Clusterstatus O.K?
$ curl -XGET 'http://localhost:9200/_cluster/health?pretty=true' { "cluster_name" : "mylog", "status" : "green", "timed_out" : false, "number_of_nodes" : 4, "number_of_data_nodes" : 4, "active_primary_shards" : 116, "active_shards" : 232, "relocating_shards" : 0, "initializing_shards" : 0, "unassigned_shards" : 0, "delayed_unassigned_shards" : 0, "number_of_pending_tasks" : 0, "number_of_in_flight_fetch" : 0 } |
- Logs in /var/log/elasticsearch/
- Logstash
- Läuft der Prozess
- systemctl status logstash
- Wird an den Ports gelauscht (5000tcp / 5500tcp / 5144tcp/udp)
- Ist die Syntax O.K -> /opt/logstash/bin/logstash --configtest -f /etc/logstash/conf.d/logstash.conf
- Wird korrekt von Port 514 auf 5144 umgeleitet?
- Kibana
- Läuft der Prozess ?
- systemctl status kibana4
- Wird am Port 5601 gelauscht? (netstat -tln |grep 5601)
- Nginx
- Läuft der Prozess?
- systemctl status nginx
- Wird an den Ports 80/443 gelauscht?
- Ist der Zugriff möglich und wird nach einem Username/Passwort gefragt?
Abschluss
Hat nun alles soweit funktioniert, sodass die Kibana Webseite aufgerufen werden kann, muss nur noch der passende Index (logstash-*") und "@timestamp" in der Konfiguration ausgewählt werden.
Danach müssen die Syslog Clients ihre Logs einfach nur noch an die konfigurierte, öffentliche Adresse (hier 10.10.10.1) senden und die Daten werden dann aufgenommen. Danach beginnt die eigentliche Arbeit, mit dem anpassen der Grok Filter :-)
Quellen
- Generelle Installation (CentOS) https://www.digitalocean.com/community/tutorials/how-to-install-elasticsearch-logstash-and-kibana-4-on-centos-7
- Grok Syslog https://gist.github.com/robinsmidsrod/019ef6d415dbc3f9e0f1
- Grok Postfix Patterns https://github.com/whyscream/postfix-grok-patterns
- Diverse Grok Patterns https://gist.github.com/mesimeris/bf6cd912d11b674c4a2b
- Syslog und Logstash http://kartar.net/2014/09/when-logstash-and-syslog-go-wrong/
- Eleasticsearch + Rest Installation unter CentOS https://www.digitalocean.com/community/tutorials/how-to-install-elasticsearch-logstash-and-kibana-4-on-centos-7
- Andere deutsche Anleitung http://www.diso.ch/2015/07/17/fachartikel-und-einfuehrung-elasticsearch-andreas-stotzer/?ModPagespeed=noscript
Spende
Wer mir etwas Gutes tun möchte :-) https://blockchain.info/de/address/1C9UE2nzandFrGHdMafWqYhuDVCx1tDrH8
--Denny (Diskussion) 12:43, 15. Okt. 2015 (CEST)