Graylog¶
Siehe auch
- Ansible-Rolle Graylog-Server:
Aktuell unterstützte Releases sowie deren End-of-Life (EOL) Datum findet man auf https://go2docs.graylog.org/current/setting_up_graylog/supported_versions.htm. In der Regel werden die letzten drei dot-Releases unterstützt, also z.B. 5.2, 5.1, 5.0. Dies kann sich je nach Versionsnummer mit Major Releases überschneiden (Beispiel 5.1., 5.0, 4.3). Etwa alle 4 bis 6 Monate erscheint ein neues dot-Release.
Es gibt keine Releases, die als besonders stabil oder instabil gelten. Graylog führt daher auch keine LTS-Versionen. Vor einer intensiven Fehleranalyse wird empfohlen, auf eine neuere Version zu aktualisieren.
Graylog Cloud für Europa wird von AWS in Frankfurt gehostet.
Features, die laut https://go2docs.graylog.org der Graylog Enterprise Edition vorbehalten sind:
Audit Log (für Graylog selbst)
Correlation Engine
Custom Themes and Notifications
Google Inputs, Microsoft Defender for Endpoint Input, CrowdStrike Input
Graylog Security inkl. Security Interface, Security Events, Anomaly Detection, Asset Enrichment, Investigations, Sigma Rules und Risk Scores
Log Ingestion Limit Notification, Cluster-to-Cluster Forwarder
OIDC :-(, On-Premise Okta Authentication
Routing und Enrichment: Data Warehouse, Indexer and Processing Failures Index, Restore an Archive, Enterprise Output Framework
Search Filters
Visualize: Reports
Installation¶
Bemerkung
Unbedingt die zu installierenden Versionen der abhängigen Software-Pakete beachten: https://go2docs.graylog.org/current/downloading_and_installing_graylog/installing_graylog.html
Graylog kann als Linux-Paket (deb, rpm) oder als Docker-Container (docker-compose, Kubernetes) installiert werden.
Minimum:
2x CPUs
6 GB RAM, besser 8 GB
8 GB Platz auf
/
Hier wird die Installation von Graylog 6.0.x beschrieben.
dnf --assumeyes install epel-release
dnf --assumeyes install dnf-plugin-versionlock
MongoDB 7.x (inkl. Pinning):
Installation siehe MongoDB
Nach der Installation ZWINGEND ausführen:
dnf versionlock add mongodb-org
OpenSearch 2.15.x (inkl. Pinning):
Installation siehe OpenSearch
Nach der Installation ZWINGEND ausführen:
dnf versionlock add opensearchOpenSearch für Graylog konfigurieren:
/etc/opensearch/opensearch.yml¶# for a minimum unsecured running state, single node cluster.name: graylog node.name: ${HOSTNAME} path.data: /var/lib/opensearch path.logs: /var/log/opensearch discovery.type: single-node network.host: 0.0.0.0 action.auto_create_index: false plugins.security.disabled: true indices.query.bool.max_clause_count: 32768
Die eigentliche Installation der Graylog Community Edition kann beginnen:
rpm --upgrade --verbose --hash https://packages.graylog2.org/repo/packages/graylog-6.0-repository_latest.rpm
dnf --assumeyes install graylog-server
dnf versionlock add graylog-server
Konfiguration - es müssen password_secret und root_password_sha2 generiert und konfiguriert werden.
password_secret(Passwort für alle Graylog-Nodes im Cluster):< /dev/urandom tr --delete --complement 'A-Za-z0-9' | head --bytes=96; echoroot_password_sha2:echo -n "Enter Password: " && head --lines=1 </dev/stdin | tr --delete '\n' | sha256sum | cut --delimiter=' ' --fields=1
Dann:
password_secret = 3JJgCxO...
root_username = graylog-admin
root_password_sha2 = 0621e81...
http_bind_address = 0.0.0.0:9000
elasticsearch_hosts = https://127.0.0.1:9200
elasticsearch_version_probe_attempts = 10
mongodb_version_probe_attempts = 10
SELinux:
setsebool --persistent httpd_can_network_connect=on
dnf --assumeyes install policycoreutils-python-utils
semanage port --add --type=mongod_port_t --proto=tcp 27017
systemctl daemon-reload
systemctl enable --now graylog-server.service
tail --follow /var/log/opensearch/opensearch.log
Nach der Installation verfügbare Ports:
9000 (tcp): Graylog-GUI und API-Browser per Swagger UI
9200 (tcp): Elasticsearch/OpenSearch
9300 (tcp): Elasticsearch/OpenSearch Node Communication
27017 (tcp): MongoDB
Port 9000 nach aussen öffnen.
Achtung
Wird Graylog das erste mal gestartet, findet sich der Link zum Login inkl. Initial-Passwort in /var/log/graylog-server/server.log.
Wer von Debian 11 auf Debian 12 aktualisiert, muss dafür sorgen, dass auch das openjdk-17-jre installiert ist, ansonsten kann sich der Graylog-Node nicht mehr am Cluster anmelden.
Konfiguration¶
- Index-Sets, Streams, Extractors
Neues Index-Set mit alternativen Retention Times / Retention Policies einrichten: System / Indices / Indices > Default Index Set > Edit; als Default Index Set einrichten.
Neuen Stream erstellen: Streams > Create stream, „Remove matches from ‚Default Stream‘“ setzen, neues Index-Set verwenden. Manage Rules > Add stream rule > Type: always match - so erhält der neue Stream alle Nachrichten in das neue Default Index-Set.
Extractors lassen sich unter System > Inputs > Extractors anlegen. GROK-Patterns orientieren sich an Oracles Java Pattern Class; ein Java-kompatibler Regex-Tester findet sich unter http://www.regexplanet.com/advanced/java/index.html.
- Config Ex- und Import
Export: System / Inputs > Content Packs: Create a content pack
Import: System / Inputs > Content Packs > Select content packs: Import content pack
- LDAP
Eine Gruppen-Synchronisation ist in Graylog Open nicht möglich (Enterprise-Feature). Eine bestimmte LDAP-Gruppe lässt sich aber per Search-Filter einschränken, beispielsweise
(&(&(uid={0})(objectClass=inetOrgPerson))(memberOf=cn=MYGROUP,cn=groups,cn=accounts,dc=example,dc=org))(im Beispiel heisst die GruppeMYGROUP).
Update¶
Vor dem Update sollte man sich die Upgrading, Release Notes und den Changelog anschauen (Achtung: richtige Version im Dropdown oben auswählen).
Achtung
MongoDB und self-managed OpenSearch muss immer vor dem Graylog Server aktualisiert werden. Der Graylog Datanode hingegen sollte nach dem Graylog Server aktualisiert werden.
Graylog empfiehlt kein Rolling Upgrade des Servers, es muss also eine Downtime geplant werden.
Graylog Server aktualisieren:
Alle Graylog Server stoppen:
systemctl stop graylog-server.serviceVersion im Repo-File aktualisieren:
$EDITOR /etc/yum.repos.d/graylog.repoGraylog Server Package aktualisieren:
dnf update graylog-serverConfig File prüfen, eventuell Änderungen anhand von den Release Notes und den Changelog durchführen:
$EDITOR /etc/graylog/server/server.confZuerst den „leader“ Graylog Server Node starten:
systemctl start graylog-server.serviceDanach alle anderen Graylog Server Nodes starten:
systemctl start graylog-server.service
Graylog Datanode aktualisieren:
Falls drei oder mehr Datanodes betrieben werden, kann ein Rolling Upgrade ohne jegliche Downtime ausgeführt werden:
Dies kann man im Graylog WebGUI unter System > Cluster Configuration > Data Node Upgrade starten
„Start Upgrade Process“ beim ersten Node anwählen, dann auf dem Node:
Graylog Datanode stoppen:
systemctl stop graylog-datanode.serviceVersion im Repo-File aktualisieren:
$EDITOR /etc/yum.repos.d/graylog.repoGraylog Datanode Package aktualisieren:
dnf update graylog-datanodeConfig File prüfen, eventuell Änderungen anhand von den Release Notes und den Changelog durchführen:
$EDITOR /etc/graylog/datanode/datanode.confGraylog Datanode starten:
systemctl start graylog-datanode.service
Nun kann man das Upgrade für den Node im WebGUI per „Confirm Upgrade“ bestätigen, und die Schritte für die weiteren Datanodes analog durchführen
Falls weniger als drei Datanodes betrieben werden, muss auch hier eine Downtime erwartet werden. Das Upgrade-Vorgehen auf den Nodes ist gleich wie beim Rolling Upgrade.
Input: Syslog¶
Soll Graylog Logdaten entgegennehmen, müssen die unter „System > Inputs“ konfiguriert werden.
Für das althergebrachte Syslog Port 1514 (udp) verwenden und lokale Firewall öffnen.
Bemerkung
Graylog kann nicht auf Port 514 hören, das führt zu einem „Permission denied, Failed to bind to: ip-address:514“, da es sich hier um einen privilegierten Port handelt. Daher wie in allen Beispielen Port 1514 verwenden. Um einen Bind auf jede IP-Adresse einzurichten, 0.0.0.0 verwenden, * funktioniert als Angabe nicht.
Nachrichtenformat¶
Welche Felder sind Standard und/oder Pflicht?
message: das einzige Pflichtfeld, muss gesetzt werden; ohne gesetzte „message“ wird Nachricht nicht angenommen.
Felder, welche automatisch gesetzt werden:
source(wenn nicht gesetzt, wird die IP des sendenden Hosts eingetragen (nicht die eines möglichen Docker-Containers))timestamp(wenn nicht gesetzt, wird aktueller Timestamp verwendet; überschreibbar mit UNIX-Timestamp; falls falsch überschrieben, wird die Nachricht verworfen)
Message-IDs sind UUIDs/GUIDs: ee1bdfe2-4c23-11e7-9f76-525400ce74cd.
Elasticsearch Index / Indizes¶
Ein Elasticsearch-„Index“ hat einen Namen, z.B. „graylog_0“.
Default Settings des „Default index set“:
Rotation strategy: 20000000
Retention strategy: Delete Index
Max number of indices: 20
Wer eigene Streams definiert, sollte darauf achten, den Haken „Remove matches from ‚All messages‘ stream“ zu setzen, damit Nachrichten nicht doppelt gespeichert werden.
Theoretisch kann man mit diesen curl-Aufrufen nach einer Änderung die Indices neu bauen (praktisch hat das bei uns nicht funktioniert - auch nach einem einfachen Reboot des Graylog-Servers waren die alten Indizes noch vorhanden):
# if Elastic is in read-only mode, switch it back to normal
curl --request PUT \
--header "Content-Type: application/json" \
--data '{"index.blocks.read_only_allow_delete": null}' \
http://elastic.example.com:9200/_all/_settings
# start retention job
curl --request POST http://graylog.example.com:9000/api/system/indices/ranges/rebuild
Indizes aus Elasticsearch auslesen:
curl 'http://elastic.example.com:9200/_cat/indices?v'
Indizes-Statistiken:
curl 'http://elastic.example.com:9200/_stats'
Indizes leeren:
curl --request DELETE 'http://elastic.example.com:9200/_all'
Logging testen¶
Wichtig
Taucht in einer JSON-Nachricht an einen Syslog-Input der Key „level“ auf, wird die Nachricht von Graylog verworfen, sobald der dazu gehörende Value nicht kompatibel mit Syslog ist. Beispiel: „level“:“FINE“ wird verworfen, „level“:“5“ dagegen akzeptiert.
Syslog per 1514/udp:
logger --server graylog.example.com --udp --port 1514 "Test Syslog 1514/udp on $(date)"
Um GELF zu testen, wird ncat benötigt.
dnf --assumeyes install nmap-ncat
GELF per 12201/UDP:
# shortest message possible
echo -e '{"message": "Test GELF 12201/udp on '$(date)'"}' | ncat --wait 1 --udp graylog.example.com 12201
# longer message, should split up into fields
echo -e '{
"version": "1.1",
"host": "example.org",
"short_message": "Test GELF 12201/udp on '$(date)'",
"full_message": "Backtrace here\nsome stuff\nmore stuff",
"level": 1,
"_user_id": 9001,
"some_info": "foo",
"some_env_var": "bar"
}' | ncat --wait 1 --udp graylog.example.com 12201
GELF per 12201/TCP:
echo -e '{
"version": "1.1",
"host": "example.org",
"short_message": "Test GELF 12201/tcp on '$(date)'",
"full_message": "Backtrace here\nsome stuff\nmore stuff",
"level": 1,
"_user_id": 9001,
"some_info": "foo",
"some_env_var": "bar"
}' | ncat --wait 1 graylog.example.com 12201
Tipp
Graylog bei der Arbeit zuschauen: tail --follow /var/log/graylog-server/server.log /var/log/opensearch/*log
Events und Alerts¶
„Alerts“ bedeutet: Man definiert einen Event (also einen Match auf bestimmte Log-Einträge), welcher eine Notification auslöst.
Beispiel: Sende eine Nachricht nach Rocket.Chat, sobald das Feld „operator_alert“ in einer Nachricht in einem bestimmten Stream vorkommt.
Graylog GUI > Alerts > Event Definitions > Create event definition
Event Details
Title: Operator Alert
Filter & Aggregation
Search Query:
_exists_:operator_alertStreams: Stream auswählen
Search within the last: 1 hours
Execute search every: 5 seconds
Notifications
Add notification
Title: operator_alert Notification
Notification Type: Custom HTTP Notification
URL: Rocket.Chat Webhook URL
Body Template:
{ "channel": "my channel", "text": ":service_crit: Graylog ${event_definition_title}: ${foreach backlog message}${message.message}${end}" }
Message Backlog: 1
Suche: Graylog Query Language¶
Beispiel für eine Suche in zwei Textfeldern und einem Integer-Feld:
NOT requestURI:"/billing/*" AND NOT requestURI:"/calendar/*" AND durationInMs:>500
Hosts ausschliessen:
NOT source:hostA and NOT source:hostB
Das Beispiel
source:host.example.* AND response-time:<30000
liefert auch Ergebnisse mit „response-time“ von 100’000 und mehr? Da drängt sich der Verdacht auf, dass es sich hier um eine Suche nach Strings und nicht nach Integern handelt.
So kann man überprüfen, wie Elasticsearch die Werte speichert - auf dem Log-Server:
curl 'http://localhost:9200/_mapping?pretty'
curl 'http://localhost:9200/_cat/indices?v'
curl 'localhost:9200/_cat/templates?v'
Client-Logging¶
rsyslog¶
Soll rsyslog Events an einen Graylog Server weiterleiten, empfiehlt sich das GELF Protokoll, da hier einfach zusätzliche Felder mitgeschickt werden können:
# send server's FQDN instead of its short hostname
$PreserveFQDN on
template(name="gelf" type="list") {
constant(value="{\"version\":\"1.1\",")
constant(value="\"host\":\"")
property(name="hostname")
constant(value="\",\"short_message\":\"")
property(name="msg" format="json")
constant(value="\",\"timestamp\":")
property(name="timegenerated" dateformat="unixtimestamp")
constant(value=",\"level\":\"")
property(name="syslogseverity")
constant(value="\"}")
}
# syslog forwarder via UDP
action(type="omfwd" target="graylog.example.com" port="12201" protocol="udp" template="gelf")
Damit ein Client sinnvolle Daten weiterleitet, kann folgende rsyslog-Konfiguration als Basis verwendet werden. So können die Events schon auf dem Client gefiltert werden, und dann per Syslog oder GELF weitergeleitet werden.
# rsyslog v7 filter conditions:
# contains isequal startswith regex ereregex
# http://www.rsyslog.com/doc/v7-stable/configuration/filters.html
if (
$msg startswith "GSSAPI client step " or
$msg startswith "GSSAPI server step " or
($programname == "kernel" and $msg startswith "RULE ") or
($programname == "systemd" and ($msg startswith "Created slice " or $msg startswith "Removed slice ")) or
($programname == "systemd" and ($msg startswith "Starting user-" or $msg startswith "Stopping user-")) or
($programname == "systemd" and ($msg startswith "Starting Session " or $msg startswith "Started Session ")) or
($programname == "systemd-logind" and ($msg startswith "New Session " or $msg startswith "Removed Session "))
)
then
# ignore, do not foward
continue
else
# Syslog
*.* @graylog.example.com:1514;RSYSLOG_SyslogProtocol23Format
# GELF (requires the template from above)
# action(type="omfwd" target="graylog.example.com" port="12201" protocol="udp" template="gelf")
Beispiel einer Weiterleitung per rsyslog für einen JBoss-Applikationsserver (alternativ WildFly):
module(load="imfile" PollingInterval="10")
input(
type="imfile"
File="/opt/jboss/standalone/log/server.json"
Tag="jboss-eap"
StateFile="statefile-to6nnu8DgDug4ImsaaJCpkAQt0zPKb"
)
# just forward, do not log again in /var/log/messages followed by the rules later on in /etc/rsyslog.conf
if $programname == 'jboss-eap' then {
action(
type="omfwd"
Target="graylog.example.com"
Port="1514"
Protocol="udp"
)
stop
}
Apache¶
Am besten so: https://www.lisenet.com/2016/send-apache-logs-to-graylog/
LogFormat: direkt GELF-kompatibles JSON schreiben
CustomLog mit
ncatdirekt an Graylog pipen
# GELF Log Format
LogFormat "{\n\
\"version\": \"1.1\",\n\
\"host\": \"%v\",\n\
\"short_message\": \"%r\",\n\
\"timestamp\": %{%s}t,\n\
\"level\": 6,\n\
\"_user_agent\": \"%{User-Agent}i\",\n\
\"_source_ip\": \"%{X-Forwarded-For}i\",\n\
\"_duration_usec\": %D,\n\
\"_duration_sec\": %T,\n\
\"_request_size_byte\": %O,\n\
\"_http_status_orig\": %s,\n\
\"_http_status\": %>s,\n\
\"_http_request_path\": \"%U\",\n\
\"_http_request\": \"%U%q\",\n\
\"_http_method\": \"%m\",\n\
\"_http_referer\": \"%{Referer}i\",\n\
\"_from_apache\": \"true\"\n\
}" gelf
CustomLog "|/usr/bin/ncat --udp graylog.example.com 12201" gelf
journalctl per GELF¶
GELF/udp: die halboffizielle Implementierung, uralt - https://github.com/systemd/journal2gelf
GELF/udp - verbessert: https://github.com/nailgun/journal2gelf
GELF/udp oder tcp: https://github.com/oboukili/journald-to-gelf
Hinweis: Nachrichten per TCP müssen mit einem „0“ beendet werden.
Wir empfehlen nailgun/journal2gelf. Zunächst EPEL-Repo aktivieren, dann:
dnf --assumeyes install git python-pip gcc python-devel systemd-devel
python3 -m pip install --user git+https://github.com/systemd/python-systemd.git#egg=systemd
python3 -m pip install --user gelfclient
git clone https://github.com/nailgun/journal2gelf.git
cd journal2gelf
python setup.py install
journal2gelf --help
Test (geht per GELF an Port 12201/udp):
journal2gelf graylog.example.com:12201
[Unit]
Description=Journald to GELF (graylog) log relay service
[Service]
ExecStart=/usr/bin/journal2gelf graylog.example.com:12201
Restart=on-failure
RestartSec=30
[Install]
WantedBy=multi-user.target
Fortinet, Java Application Server¶
Bei Fortinet-Geräten wird statt Syslog besser das Common Event Format (CEF) verwendet.
Alle Log-Daemons arbeiten nach dem Prinzip „Zeilenumbruch = neue Log-Message“, so auch Graylog. Damit Stacktraces aus einem Java Application Server nicht in dutzende Einzelnachrichten zerfallen, wird im Java-Applikationsserver ein GELF-Appender im nativen, vom Entwickler eingesetzten Java-Logging-Framework (Log4j, Logback etc.) konfiguriert. Viele dieser Appender bauen auf dem GELF Java Client (https://github.com/Graylog2/gelfclient) auf.
Windows¶
Soll ein Windows-Server Event-Logs senden, wird ein auf Windows zu installierender Agent benötigt. Graylog empfiehlt die Kombi aus WinLogBeat (der eigentliche Client) und Graylog Sidecar (ein Daemon zur Konfiguration des Clients durch den Graylog-Server). Siehe auch https://go2docs.graylog.org/current/getting_in_log_data/ingest_windows_eventlog.html
Auf dem Graylog Server:
Für den Sidecar-User einen API Key unter „System > Users and Teams“ erstellen.
Ausserdem muss ein Beats-Input erstellt werden.
Installation von Sidecar auf dem Windows Host:
Sidecar herunterladen: https://github.com/Graylog2/collector-sidecar/releases
Sidecar installieren: Während des Setups kann direkt die API-URL wie http://graylog.example.com:9000/api sowie der API Key eingegeben werden. Das Tool WinLogBeat wird automatisch mit installiert und konfiguriert.
Zurück auf dem Graylog Server sollte das zuvor installierte Sidecar unter „System > Sidecars“ zu sehen sein. Der Collector auf dem Client muss allerdings noch wissen, welche Daten er sammeln soll - das wird in einer Collector-Configuration festgelegt:
System > Sidecars > Configuration
Create Configuration
Name für die Konfiguration vergeben (z.B. „winlogbeat-default“)
Collector: winlogbeat on Windows
Tags: Wer den Collector pro Applikation (z.B. für das Sammeln von Apache httpd-logs) konfiguriert, vergibt hier den Tag für die Applikation (also z.B. „Apache httpd“). Für Windows-Systemlogs bietet sich „OS - Windows“ an.
Eine brauchbare Konfiguration wäre (siehe https://go2docs.graylog.org/current/getting_in_log_data/ingest_windows_eventlog.html):
fields_under_root: true
fields.collector_node_id: ${sidecar.nodeName}
fields.gl2_source_collector: ${sidecar.nodeId}
output.logstash:
# this refers to the Beats input on Graylog
hosts: ["192.0.2.74:5044"]
ssl:
enabled: true
verification_mode: full
winlogbeat.event_logs:
- name: Application
level: critical, error, warning
ignore_older: 48h
- name: Security
processors:
- drop_event.when.not.or:
- equals.event_id: 129
- equals.event_id: 141
- equals.event_id: 1102
- equals.event_id: 4648
- equals.event_id: 4657
- equals.event_id: 4688
- equals.event_id: 4697
- equals.event_id: 4698
- equals.event_id: 4720
- equals.event_id: 4738
- equals.event_id: 4767
- equals.event_id: 4728
- equals.event_id: 4732
- equals.event_id: 4634
- equals.event_id: 4735
- equals.event_id: 4740
- equals.event_id: 4756
level: critical, error, warning, information
ignore_older: 48h
- name: System
processors:
- drop_event.when.not.or:
- equals.event_id: 129
- equals.event_id: 1022
- equals.event_id: 1033
- equals.event_id: 1034
- equals.event_id: 4624
- equals.event_id: 4625
- equals.event_id: 4633
- equals.event_id: 4719
- equals.event_id: 4738
- equals.event_id: 7000
- equals.event_id: 7022
- equals.event_id: 7024
- equals.event_id: 7031
- equals.event_id: 7034-7036
- equals.event_id: 7040
- equals.event_id: 7045
level: critical, error, warning
ignore_older: 48h
Jetzt kann die Collector-Configuration dem Client zugewiesen werden:
System > Sidecars > Administration
winlogbeat aktivieren > Assign Configurations > „winlogbeat-default“ auswählen
Die Konfiguration wird auf dem Client in der Regel unter C:\Program Files\Graylog\sidecar\generated\<RANDOM>\winlogbeat.conf abgelegt, und kann per C:\Program Files\Graylog\sidecar\winlogbeat.exe test config --c generated\...\winlogbeat.conf getestet werden. Die zu Graylog Sidecar gehörenden Windows-Services heissen „Graylog collector sidecar .*“ und „Graylog Sidecar“, und sollten überwacht werden.
TLS¶
Graylog kann so konfiguriert werden, dass die Kommunikation der Logdaten der Clients TLS-verschlüsselt passiert.
- Server-Konfiguration
Auf dem Graylog-Server muss beim gewünschten Input
Enable TLSaktiviert und die Pfade für das TLS-Zertifikat und den Private-Key beiTLS cert fileundTLS private key filehinterlegt werden. Sind Zertifikat und Private-Key im gleichen File vorhanden, so kann auch nur einer der beiden Pfade gesetzt werden.Das Zertifikat muss den Hostnamen der Inputs entsprechen, d.h. meldet sich ein Client beim Graylog-Server
example.comso muss für eine erfolgreiche Kommunikation das konfigurierte Zertifikat entweder den Common Name (CN) oder ein Subject Alternative Name (subjectAltName) fürexample.comaufweisen.Sobald bei einem Input
Enable TLSaktiv ist, werden nur noch TLS-verschlüsselte Verbindungen akzeptiert. Wenn einige Clients TLS nicht unterstützen, so muss entweder TLS deaktiviert werden oder ein separater, unverschlüsselter Input auf einem anderen Port angelegt werden.- Client-Konfiguration
Clients müssen abhängig vom Nachrichten-Protokoll konfiguriert werden. Werden Graylog Sidecars verwendet, nutzen die Sidecars automatisch TLS.
Ist das Zertifikat nicht von einer Certificate Authority ausgestellt, die im Hostsystem installiert und trusted ist (z.B. self-signed Zertifikate), so kann in der Sidecar-Collector-Konfiguration die CA manuell mit
ssl.certificate_authoritiesgesetzt werden (die CA muss schon auf dem Client vorhanden sein; sie wird nicht per Sidecar verteilt):... output.logstash: hosts: ["example.com:5044"] ssl: certificate_authorities: ["/opt/my-example.com-ca.crt"] enabled: true verification_mode: full ...
Benutzer¶
Benutzer benötigt Decorator-Edit-Rechte? Sowas geht nur über das REST-API.
Verwendbare Berechtigungen abfragen:
curl --request GET \
--user admin:linuxfabrik \
'http://graylog.example.com:9000/api/system/permissions?pretty=true'
Ergebnis u.a.:
"decorators" : [ "create", "read", "edit" ]
Neue Rolle erstellen:
curl --request POST \
--user admin:linuxfabrik \
--header 'Content-Type:application/json' \
--data '{"read_only": false,"permissions": ["decorators:create:*", "decorators:read:*", "decorators:edit:*" ],"name": "Full Decorator Permissions","description": "Permission to create, read oder delete decorators."}'
'http://graylog.example.com:9000/api/roles'
Anschliessend kann die neue Rolle im GUI > Authentication Management ganz unten unter „Roles“ den Benutzern zugeteilt werden.
Berechtigungen für den Benutzer prüfen:
curl --request GET \
--user admin:linuxfabrik \
"http://graylog.example.com:9000/api/users/$USERNAME?pretty=true"
Pipelines¶
Unter System > Configuration > Message Processors Configuration die „Pipeline“ aktivieren und nach der „Message Filter Chain“ setzen, wenn man auf Felder prüfen möchte, die von Extraktoren gesetzt wurden.
Ablauf:
Pipeline anlegen
Stage anlegen
Rule anlegen
Rule zur Stage hinzufügen
Pipeline zu Stream connecten
Sinnfreies Beispiel für eine Rule mit Kommentaren, Abfrage auf einen Input und Wegwerfen einer Nachricht:
rule "unneeded if container_name contains _app_ or _cep_"
when
(
// to_string($message.gl2_source_input) == "5b16a9176e8bf60b6cf8bc6b" and
has_field("container_name") and
(contains(to_string($message.container_name), "_app_") or contains(to_string($message.container_name), "_cep_"))
)
then
set_field("unneeded_message", true);
drop_message();
end
Simulation:
GELF-Message: {
"version": "1.1",
"host": "example.org",
"short_message": "Short message",
"full_message": "Full message",
"level": 1,
"container_name": "my_container"
}
Wert nach Long konvertieren:
rule "Convert RT_FLOW to Numeric"
when
has_field("bytes-from-server" ) && $message.application_name == "RT_FLOW"
then
let serverre = to_long( $message.`bytes-from-server`);
let clientre = to_long( $message.`bytes-from-client`);
set_field("bytes-from-server_conv", serverre );
set_field("bytes-from-client_conv", clientre );
end
API, API-Browser¶
Alle Methoden auf einen Blick: http://graylog.example.com:9000/api/api-browser
Authentifizierung entweder mittels Username und Passwort, oder per Access Token (letztere ist aus Sicherheitsgründen die bevorzugte Methode).
Access Token erstellen:
Benutzer erstellen, Standard-Rolle „Reader“ notfalls anpassen
Token zuweisen
curl --user user:linuxfabrik \
--header 'Accept: application/json' \
--request GET \
'http://graylog.example.com:9000/api/...' | jq
Cluster-Informationen auslesen - mit Username und Passwort:
curl --user admin:linuxfabrik \
--header 'Accept: application/json' \
'http://graylog.example.com:9000/api/cluster?pretty=true'
Cluster-Informationen auslesen - mit Access Token (Token als Benutzername nutzen; Passwort ist hier immer „token“):
curl --user 1crgamba51dkdn8jsrltpek90m167p1dmteaa0gr7ehscnb3bpce:token \
--header 'Accept: application/json' \
'http://graylog.example.com:9000/api/cluster?pretty=true'
Log-Einträge auf Basis einer Query als CSV exportieren:
# urlencoded query
#q=*
q=syslog_identifier%3Asshd%20AND%20opened%20AND%20NOT%20root
range=300 # in seconds
# comma-separated list of fields (%2C)
curl --user admin:linuxfabrik \
--header 'Accept:text/csv' \
'http://graylog.example.com:9000/api/search/universal/relative/export?query=$q&range=$range&fields=timestamp%2Csource%2Cmessage' | gzip --best > export.csv
Streams und Stream Rules:
Stream Rule Type 1: match exactly
Stream Rule Type 2: match regular expression
Stream Rule Type 3: greater than
Stream Rule Type 4: smaller than
Stream Rule Type 5: field presence
Stream Rule Type 6: contain
Stream Rule Type 7: always match
Stream Rule Type 8: match input
curl --user user:linuxfabrik \
--header 'Accept: application/json' \
--header 'X-Requested-By: cli' \
--data '{
"title": "All messages",
"description": "All messages are routed here",
"matching_type": "AND",
"rules": [
{
"field": "",
"type": 7,
"inverted": false,
"value": ""
}
],
"content_pack": null
}' \
--request POST \
'http://graylog.example.com:9000/api/streams' | jq
Backup und Restore¶
Zu tun
Restore-Prozess beschreiben
Überarbeiten
https://go2docs.graylog.org/current/setting_up_graylog/backup_considerations.htm
Beim Backup- und Restore-Prozess sind folgende Komponenten zu berücksichtigen:
MongoDB (Siehe Backup und Restore)
Graylog Datanode: OpenSearch Snapshots
Graylog Server: Konfiguration
Darüber hinaus gilt es, die exakten Versionen von MongoDB sowie Graylog Datanode und Server festzuhalten, damit im Wiederherstellungsfall keine Probleme aufgrund von Versionsunterschieden entstehen.
Ablauf für den Graylog Datanode (dateisystem-basiertes Snapshot-Repository):
Repository-Pfad in
datanode.confkonfigurierenClient-Zertifikat von Graylog-Server beziehen
Snapshot-Repository via Datanode-API registrieren
Snapshot anlegen
Repository-Verzeichnis anlegen und Pfad auf Datanode konfigurieren:
snapshot_repo_path=/path/to/snapshot/repo
mkdir --parents $snapshot_repo_path
chown graylog-datanode:graylog-datanode $snapshot_repo_path
chmod 740 $snapshot_repo_path
datanode.conf¶path_repo = /path/to/snapshot/repo
systemctl restart graylog-datanode.service
Client-Zertifikat von Graylog-Server beziehen. Der Endpunkt POST /api/ca/clientcert erwartet je nach Graylog-Version leicht unterschiedliche Argumente: certificate_lifetime existiert seit 6.3, und password darf erst ab 7.0 null sein. Die drei folgenden Request-Bodies entsprechend passend auswählen.
graylog_admin_username=''
read -s graylog_admin_password
graylog_host='198.51.100.10'
clientcert_base_path='/tmp/graylog-clientcert'
clientcert_lifetime='P30Y' # 30 years
clientcert_principal='datanode01.example.com' # fqdn of datanode where cert will be stored
clientcert_role='manage_snapshots'
clientcert_path="$clientcert_base_path/$clientcert_principal"
mkdir --parents "$clientcert_path"
# NOTE: Graylog 6.1
clientcert_request="$(cat <<EOF
{
"password": "",
"principal": "$clientcert_principal",
"role": "$clientcert_role"
}
EOF
)"
# NOTE: Graylog 6.3
clientcert_request="$(cat <<EOF
{
"certificate_lifetime": "$clientcert_lifetime",
"password": "",
"principal": "$clientcert_principal",
"role": "$clientcert_role"
}
EOF
)"
# NOTE: Graylog 7.0
clientcert_request="$(cat <<EOF
{
"certificate_lifetime": "$clientcert_lifetime",
"password": null,
"principal": "$clientcert_principal",
"role": "$clientcert_role"
}
EOF
)"
clientcert_response="$(curl --silent \
--request POST "http://$graylog_host:9000/api/ca/clientcert" \
--header 'Content-Type: application/json' \
--header 'X-Requested-By: cli' \
--basic --user "$graylog_admin_username:$graylog_admin_password" \
--json "$clientcert_request")"
jq --raw-output '.ca_certificate' <<<"$clientcert_response" >"$clientcert_path/ca.crt"
jq --raw-output '.private_key' <<<"$clientcert_response" >"$clientcert_path/private.key"
jq --raw-output '.certificate' <<<"$clientcert_response" >"$clientcert_path/private.crt"
Snapshot-Repository auf Datanode registrieren:
datanode_host=''
client_ca_cert='/path/to/clientcert/ca.crt'
client_key='/path/to/clientcert/ca.key'
client_cert='/path/to/clientcert/private.crt'
# register filesystem-based snapshot repository
curl --silent \
--cacert "$clientcert_path/ca.crt" \
--key "$clientcert_path/private.key" \
--cert "$clientcert_path/private.crt" \
--header 'Content-Type: application/json' \
--request PUT "https://$datanode_host:9200/_snapshot/fs" \
--data '{
"type": "fs",
"settings": {
"location": "/path/to/snapshot/repo"
}
}' | jq
# list registered snapshot repositories
curl --silent \
--cacert "$clientcert_path/ca.crt" \
--key "$clientcert_path/private.key" \
--cert "$clientcert_path/private.crt" \
--header 'Content-Type: application/json' \
--request GET "https://$datanode_host:9200/_snapshot/_all" | jq
Snapshot von allen Indizes anlegen. Der Graylog-Server muss zuvor gestoppt werden.
systemctl stop graylog-server
# snapshot all indices
curl --silent \
--key "$client_key" \
--cert "$client_cert:$client_cert_pw" \
--cacert "$client_ca_cert" \
--request PUT "https://$datanode_host:9200/_snapshot/fs/snapshot-1?wait_for_completion=true" \
--header 'Content-Type: application/json' \
--data '{
"indices": "*",
"ignore_unavailable": true,
"include_global_state": false
}' | jq
Migration OpenSearch zu Graylog Data Nodes¶
Je nach Anforderungen an Downtime und Datenintegrität kommen drei Ansätze in Frage. Nur die In-Place-Migration ist offiziell dokumentiert, die beiden anderen sind pragmatische Vorgehen aus der Praxis.
- In-Place Migration (offiziell)
Der Data Node übernimmt das bestehende OpenSearch-Datenverzeichnis direkt, ohne Datentransfer. OpenSearch wird gestoppt, der Data Node startet auf demselben Pfad. Rollback ist nur auf Cluster-Ebene möglich, die OpenSearch-Binaries sollten bis zur Verifikation des neuen Clusters behalten werden. Die maximal zulässige OpenSearch-Version hängt von der Graylog-Version ab: Graylog 6.1 bis 6.3 unterstützt OpenSearch bis 2.15, Graylog 7.0 und neuer bis 2.19.
- Side-by-Side Migration
Ein neuer Data-Node-Cluster wird parallel zum bestehenden OpenSearch aufgebaut. Neue Index-Sets zeigen auf den Data Node, bestehende Daten verbleiben auf OpenSearch bis zum Ablauf der Retention. Rollback ist pro Index-Set möglich. Der Ansatz eignet sich, wenn Downtime vermieden werden soll und eine längere Übergangszeit akzeptabel ist.
- Snapshot/Restore
OpenSearch-Indices werden per Snapshot-Repository (NFS, S3, o.ä.) gesichert und in den Data-Node-Cluster zurückgespielt. OpenSearch bleibt so lange aktiv, bis alle Indices im Data-Node-Cluster vorhanden, abfragbar und von Graylog ansprechbar sind. Der Ansatz eignet sich bei Host-Migrationen. Die Lucene-Versionskompatibilität zwischen Quell- und Ziel-Cluster ist vor der Migration zu prüfen.
Troubleshooting¶
- „415 Unsupported Media Type“ bei Verwendung des APIs
The server is refusing to service the request because the entity of the request is in a format not supported by the requested resource for the requested method.
OpenSearchException[OpenSearch exception [type=illegal_argument_exception, reason=mapper [latency] cannot be changed from type [float] to [long]]]Die Mappings (OpenSearch / Elasticsearch Felder und deren Typ) werden dynamisch anhand der ersten Nachricht im jeweiligen Index bestimmt. Dies geschieht jedes Mal, wenn ein neuer Index begonnen wird, also auch, wenn der Index rotiert wurde. Das heisst, wenn der erste Eintrag
latency: 0ist, nimmt OpenSearch fälschlicherweise an, dass es sich um ein long handelt. Wenn man nun einen float-Wert schickt, wird dieser zwar im Graylog und in OpenSearch als float angezeigt, intern aber trotzdem als long behandelt (siehe https://xeraa.net/blog/2020_elasticsearch-coerce-float-to-integer-or-long/).Um dieses Problem zu beheben, kann man den Typ für das Feld
latencymanuell setzen:# show current mapping curl 'localhost:9200/lfops-default_4/_mappings?pretty' | grep latency -A1 # "latency" : { # "type" : "float" # create custom mapping, see https://go2docs.graylog.org/current/setting_up_graylog/elasticsearch.htm#CustomIndexMappings cat > lfops-latency-float.json << 'EOF' { "template": "lfops-default_*", "order": 10, "mappings": { "properties": { "latency": { "type": "float" } } } } EOF curl --request PUT --data @'lfops-latency-float.json' --header 'Content-Type: application/json' 'http://localhost:9200/_template/lfops-latency-float?pretty' # show current templates curl 'http://localhost:9200/_template?pretty'
Anschliessend muss im Graylog unter Indices der betroffene Index ausgewählt und über „Maintenance > Rotate active write index“ der aktuelle Index neu generiert werden.
- Datanodes werden bei der Installation nicht gefunden?
Prüfen, ob sie in der MongoDB eingetragen sind
mongosh use graylog db.datanodes.find()
- Zertifikats-Probleme mit einem Datanode Cluster?
Prüfen, ob sich alle Datanodes untereinander via DNS erreichen können (auch Firewall beachten). Besonders wichtig: Auch die
/etc/hostsprüfen -127.0.0.1bzw.::1dürfen ausschliesslich auf dielocalhost-Varianten zeigen. Falls zusätzlich der eigentliche Hostname angegeben wird, schlägt das Ausstellen der Zertifikate mit dem Fehlercertificate_unknownfehl.
Built on 2026-04-15