socklog UDP rsyslog Server einrichten

reinhard@finalmedia.de Thu 06 Jul 2023 11:48:09 AM CEST

# socklog ist ein minimalistischer, stabiler und performanter oldschool UDP syslog daemon von Gerrit Pape. Diese Anleitung beschreibt, wie socklog zusammen mit svlogd (aus dem runit paket) und den djb daemontools auf einem debian host einzurichten ist.

Ein UDP rsyslog daemon dient dazu, die Logeinträge von diversen Servern zu bündeln. Man kann also von diversen Remotehosts, Logeinträge sehr performant zusätzlich an eine zentrale Stelle übertragen, und dort die Logfiles dann rotiert und auswerten. remote syslog (egal ob via udp oder tcp) sollte nur in abgesicherter Umgebung zum Einsatz kommen. Beim Einsatz von UDP können natürlich Pakete verloren gehen, aber auch beim Einsatz von TCP ist DoS möglich ist. Empfohlen ist z.B. der gekapselte Einsatz innerhalb von wireguard. socklog selbst kann in den Betriebsmodi unix, inet und ucspi gestartet werden, also z.B. auch via tcpserver (via ucspi) dann tcp, im Anschluss auch in wireguard gemantelt werden. Alternativ (und wie in dieser Anleitung beschrieben) kann er aus Gründen der besseren Performance auch nativ und direkt via inet (also UDP Port 514) verwendet werden.

Die nachfolgene Anleitung beschreibt daher einen empfangenden UDP server an Port 514, der 254 "Slots" für entsprechende Client-Hosts zur Verfügung stellt. Alle Anfragen wiederum werden in "/var/log/udp/main/current" protokolliert. Für die zu empfangenden Server 10.0.0.1, 10.0.0.2, 10.0.0.3, ... 10.0.0.254 gibt es hingegen exklusive Log-Slots. In diesen Slots wiederum werden die Einträge nach 200 MB logfile automatisch rotiert und davon 80 Stück archiviert, bevor auch diese automatisch entfernt werden. Das genaue Verhalten ist für jeden einzelnen Slot in der config file einstellbar. Die configfile befindet sich dabei auch im entsprechenden log Ordner, z.B. /var/log/udp/10.0.0.1/config

Los gehts. Wir bauen gegen die musl-libc, um leichtgewichtigere Binaries zu erhalten, die wir zudem statisch linken.

Quellcode beziehen und Executables bauen

Zunächst brauchst du den Original Quellcode http://smarden.org/socklog/socklog-2.1.0.tar.gz von smarden Gerrit Pape veröffentlicht.

Oder hier als Mirror zum direkten Download: socklog-2.1.0.tar.gz

Sowie zusätzlich den Original Quellcode http://smarden.org/runit/runit-2.1.2.tar.gz.

Oder hier als Mirror zum direkten Download: runit-2.1.2.tar.gz

Folgende sha256sum solltest du prüfen:

6fd0160cb0cf1207de4e66754b6d39750cff14bb0aa66ab49490992c0c47ba18  runit-2.1.2.tar.gz
aa869a787ee004da4e5509b5a0031bcc17a4ab4ac650c2ce8d4e488123acb455  socklog-2.1.0.tar.gz

Wir bauen jetzt die Executables aus den Originalquellen auf deiner Workstation und ich nehme an, dass der upd rsyslog daemon auch dort mit daemontools an den Start gehen soll:


# vorbereitungen als root user
apt-get install daemontools daemontools-run musl-dev musl-tools musl make
systemctl enable daemontools

Nun geht es weiter als user mit eingeschränkten Rechten:


# quellverzeichnis erstellen, quellen herunterladen und dorthin entpacken
mkdir -p ~/src/runit/
mkdir -p ~/src/socklog/
curl http://smarden.org/runit/runit-2.1.2.tar.gz | tar -C ~/src/runit/ -x -v -z
curl http://smarden.org/socklog/socklog-2.1.0.tar.gz | tar -C ~/src/socklog/ -x -v -z

# build konfiguration runit vornehmen und bauen
cd ~/src/runit/admin/runit-2.1.2/src
echo "musl-gcc -O2 -include /usr/include/x86_64-linux-musl/errno.h -static" > conf-cc
echo "musl-gcc -s -static" > conf-ld
make

# build konfiguration socklog vornehmen und bauen
cd ~/src/socklog/admin/socklog-2.1.0/src
echo "musl-gcc -O2 -include /usr/include/x86_64-linux-musl/errno.h -static" > conf-cc
echo "musl-gcc -s -static" > conf-ld
make

Nun geht es wieder weiter als root user



# copy binary (als root!)
cd /home/vorheriger_sysuser_der_zum_bau_verwendet_wurde
cp ./src/socklog/admin/socklog-2.1.0/src/socklog /usr/bin/
cp ./src/runit/admin/runit-2.1.2/src/chpst /usr/bin/
cp ./src/runit/admin/runit-2.1.2/src/svlogd /usr/bin/


# daemontools verzeichnis erstellen
mkdir /srv/socklog
mkdir /srv/socklog/log

# runfile erstellen
cat << :::eof::: > /src/socklog/run && chmod +x /srv/socklog/run
#!/bin/sh
exec 2>&1
exec chpst -Unobody socklog inet 0 514
:::eof:::


# runfile fuer log erstellen
# den eigentlichen log dienst, der logfiles filtert und rotiert
# wir erstellen damit auch 254 log slots
# schaue im anschluss in die datei /srv/socklog/log/run um es zu verstehen!
# passe ggf. die default ip 10.0.0.x entsprechend an
base64 -d << :::eof::: > /srv/socklog/log/run && chmod +x /srv/socklog/log/run
IyEvYmluL3NoCgp1c2VyPSJub2JvZHkiCmdyb3VwPSJub2dyb3VwIgoKbG9nZGlyPSIvdmFyL2xv
Zy91ZHAiCm1rZGlyIC1wICIke2xvZ2Rpcn0vbWFpbiIgMj4vZGV2L251bGwKCmV4cG9ydCBtYXg9
MjU0CgpzZXEgMSAke21heH0gfCB3aGlsZSByZWFkIGkKZG8KY29uZmlnZGlyPSIvdmFyL2xvZy91
ZHAvcyR7aX0iCm1rZGlyIC1wICIke2NvbmZpZ2Rpcn0iIDI+L2Rldi9udWxsCmNvbmZpZ2ZpbGU9
IiR7Y29uZmlnZGlyfS9jb25maWciCmVjaG8gIm44MCIgPiAiJHtjb25maWdmaWxlfSIKZWNobyAi
czIwMDAwMDAwIiA+PiAiJHtjb25maWdmaWxlfSIKZWNobyAiTjQiID4+ICIke2NvbmZpZ2ZpbGV9
IgplY2hvICItKiIgPj4gIiR7Y29uZmlnZmlsZX0iCmVjaG8gIisxMC4wLjAuJHtpfSIgPj4gIiR7
Y29uZmlnZmlsZX0iCmRvbmUKCmNob3duIC1SICR7dXNlcn06JHtncm91cH0gIiR7bG9nZGlyfSIK
Y2QgIiR7bG9nZGlyfSIKCmxvZ2RpcmxpbmU9Im1haW4gJChzZXEgMSAke21heH0gfCBzZWQgInMv
Xi9zL2ciIHwgdHIgIlxuIiAiICIgfCB0ciAtZGMgIjAtOXMgIikiCmVjaG8gIiRsb2dkaXJsaW5l
IgpleGVjIHNldHVpZGdpZCAke3VzZXJ9IHN2bG9nZCAtcl8gLXQgJHtsb2dkaXJsaW5lfQoK
:::eof:::

# Services an den Start bringen
ln -s /srv/socklog /etc/service/


binaries (x86_64)

socklog.bin.tgz

Details zum Verständnis

Der log Service in daemontools (also nicht der empfangende, sondern der prozessierende Teil) nutzt svlogd, das auf stdin eingehende Logeinträge dann im Sinne von djb multilog prozessiert und auf die angegebenen Slots verteilt. Alle Slots sind auch Verzeichnisse, die wiederum dann auch ein current file enthalten, ein config file und dann - im Falle einer erfolgten Rotation auch die entsprechenden .s Dateien, deren Dateiname dem tai64 Zeitstempel der erfolgten Rotation entspricht. Multilog wird über die Cmdline parametrisiert, wohingegen svlogd mit config files pro Datei arbeitet, und damit flexibler ist:

#!/bin/sh
mkdir /var/log/udp
chown log:log /var/log/udp
cd /var/log/udp
uid=$(id log)
exec unshare -S${uid} -n svlogd -r_ -t main s1 s2 s4 s5 s6 s7 s8 s9 s10 s11 s12 s13 s14 s15 s16 s17 s18 s19 s20 s21 s22 s23 s24 s25 s26 s27 s28 s29 s30 s31 s32 s33 s34 s35 s36 s37 s38 s39 .... s254

in den logverzeichnissen gibt es je eine configfile, die bestimmt, was dort gelogged werden soll, wann und wie oft rotiert wird, etc. In diesem Fall erhalten wir 80 rotierte Dateien und löschen rst danach. Wir rotieren current, beim Erreichen einer Speichergröße von 20000000 bytes. Zudem loggen wir nichts, außer Einträge die von der genannten Host IP stammen

s1/config
n80
s20000000
N4
-*
+10.0.0.1:*


s2/config
n80
s20000000
N4
-*
+10.0.0.2:*

...

s254/config
n80
s20000000
N4
-*
+10.0.0.254:*

Man kann analog zu multilog auch den svlog mittels Signalen dazu bringen, manuell zu rotieren und vorallem auch geänderte configfiles neu zu lesen. Das geht mittels

pkill -HUP pid_of_svlog um svlog dazu zubringen config files neu zu lesen

oder mit daemontools via

svc -h /srv/socklog/log

svc
       -p     Pause. Send the service a STOP signal.
       -c     Continue. Send the service a CONT signal.
       -h     Hangup. Send the service a HUP signal.
       -a     Alarm. Send the service an ALRM signal.
       -i     Interrupt. Send the service an INT signal.
       -t     Terminate. Send the service a TERM signal.
       -k     Kill. Send the service a KILL signal.

## Signals

If svlogd is sent a HUP signal, it closes and reopens all logs, and updates their configuration according to log/config.
If svlogd has trouble opening a log directory, it prints a warning, and discards this log directory.
If svlogd is unable to open all log directories given at the command line, it exits with an error.
If svlogd is sent a TERM signal, or if it sees end-of-file on standard input, it stops reading standard input, processes the data in the buffer, waits for all processor subprocesses to finish if any, and exits 0 as soon as possible.
If svlogd is sent an ALRM signal, it forces log file rotation for all logs with a non empty current log file.


Komprimierung von Logfiles

Wenn gewünscht ist, dass Logfiles automatisch beim Rotieren komprimiert werden, so ist in der der jeweiligen config Datei zusätzlich ein entsprechender Prozessor zu nennen. Ein Prozessor wird mit einem Ausrufezeichen beginnen angegeben. In diesem Fall möchten wir mit gzip komprimieren:

!gzip

Damit wird beim Rotieren zunächst eine .t Datei erstellt, von gzip komprimiert, und danach im Erfolgsfall zur .s Datei. (.s ist in dann komprimiert und trägt nicht die Endung .gz). Sollte es während der Prozesses zu einer Downtime kommen, wird die .t Datei automatisch beim nächsten Start erneut komprimiert. Weitere Details dazu sind auch auf der Webseite zu socklog und svlogd (runit) und in den passenden Manuals ersichtlich.

Wie kann man den Service nun mit Daten füttern?

Nehmen wir an, du hast einen anderen debian host (nennen wir ihn 192.168.55.123) und möchtest dessen Logs hier auf dem neuen zentralen UDP rsyslog Server 192.168.55.1 protokollieren.

Dazu bearbeitest du auf dem entfernten Rechner die Datei /etc/rsyslog.conf und ergänzt dabei einfach um diese Zeile:

*.*	@192.168.55.1

*.* steht für alle Logfiles, gefolgt von einem tabulator, dann dem @-Zeichen und der IP des zentralen UDP rsyslog Logging-Servers.

Starte dann dort auf deinem entfernten Debian Host den rsyslog einfach neu:

service rsyslog restart

Es werden nun die Logs in deinem neuen Server in /var/log/udp/main/current auflaufen. Wenn du main noch entsprechend konfigurieren willst, dann erstelle dort auch eine config Datei und zwinge den svlogd dazu, diese zu evaluieren. Das machst du dann mittels:

svc -h /srv/socklog/log

Testdaten senden/empfangen

Testen kannst du jederzeit mit netcat auf dem UDP Port 514:

echo Testnachricht | nc -q0 -u 192.168.55.1 514

oder auch mittels pure bash und den pseudo-network-devices:

echo Testnachricht > /dev/udp/192.168.55.1/514