Benutzer-Werkzeuge

Webseiten-Werkzeuge


wiki:logger

Protokollierung von Benutzeraktionen mit Username in Syslog

Bevorzugte Lösung

Diese Lösung wird von mir bevorzugt. Sie verwendet `auditd` zur Erfassung der Befehle, ein eigenes Formatter-Skript zum Zusammenführen und Aufbereiten der Audit-Datensätze sowie `rsyslogd` zum Schreiben der fertigen Meldung nach `/var/log/syslog`.

Standardlösung: rohe Audit-Meldungen

Die übliche Standardlösung leitet die Audit-Meldungen lediglich weiter und schreibt sie beispielsweise nach `/var/log/user-audit.log`. Dort stehen die einzelnen Audit-Datensätze (`SYSCALL`, `EXECVE` und `EOE`) jedoch getrennt und im technischen Rohformat. Ein einzelnes Ereignis verteilt sich dadurch auf mehrere schwer lesbare Logzeilen; Username und Befehlsargumente sind nicht übersichtlich in einer Meldung zusammengefasst.

Die Datei kann beispielsweise mit `ausearch` ausgewertet werden:

sudo ausearch -k user_commands

Diese Standardlösung ist für die nachträgliche technische Analyse geeignet, erzeugt aber keine kompakte Meldung der Form „Zeit, eingeloggter Benutzer, ausführender Benutzer, Befehl“. Deshalb wird in diesem Beitrag die oben beschriebene Formatter-Lösung bevorzugt.

Ziel

Diese Konfiguration protokolliert ausgeführte Befehle mit folgenden Informationen:

  • Zeitpunkt der Ausführung
  • ursprünglich eingeloggter Benutzer (Audit-ID, AUID)
  • tatsächlich ausführender Benutzer (UID)
  • ausgeführter Befehl einschließlich Argumenten

Der Datenfluss ist:

auditd -> Audit-Formatter -> rsyslogd -> /var/log/syslog

Hinweis: Eine reine rsyslogd-Regel kann die getrennten Audit-Datensätze (SYSCALL und EXECVE) nicht zuverlässig zu einem vollständigen Ereignis zusammenführen. Diese Aufgabe übernimmt der Formatter. rsyslogd schreibt anschließend die fertige Meldung in die Syslog-Datei.

Voraussetzungen

Debian/Ubuntu:

sudo apt update
sudo apt install auditd audispd-plugins rsyslog

Das Formatter-Skript aus dem Projekt ist:

audit-format-syslog.py

1. Audit-Regeln einrichten

Datei `/etc/audit/rules.d/user-commands.rules` anlegen oder bearbeiten:

-a always,exit -F arch=b64 -S execve,execveat -F auid>=1000 -F auid!=unset -k user_commands
-a always,exit -F arch=b32 -S execve,execveat -F auid>=1000 -F auid!=unset -k user_commands

Die Regeln überwachen die Ausführung von Programmen durch angemeldete Benutzer. Der Schlüssel `user_commands` erleichtert die spätere Suche mit `ausearch`.

Regeln laden:

sudo augenrules --load
sudo auditctl -l

2. Audit-Formatter installieren

Das Skript installieren:

sudo install -m 0755 \
  /path/to/audit-format-syslog.py \
  /usr/local/sbin/audit-format-syslog.py

Der Formatter liest die Audit-Meldungen über die Standardeingabe. Er sammelt die zusammengehörigen `SYSCALL`, `EXECVE` und `EOE`-Datensätze, löst die UID-Nummern in Benutzernamen auf und schreibt anschließend eine formatierte Syslog-Meldung.

Der vollständige Quelltext des Formatters:

#!/usr/bin/env python3
 
import binascii
import pwd
import re
import shlex
import sys
import syslog
import time
from functools import lru_cache
 
 
EVENT_RE = re.compile(r"msg=audit\(([^:]+):(\d+)\)")
FIELD_RE = re.compile(r'([A-Za-z_][A-Za-z0-9_]*)=("[^"]*"|[^ ]+)')
 
 
def fields(line):
  return {key: value.strip('"') for key, value in FIELD_RE.findall(line)}
 
 
@lru_cache(maxsize=1024)
def username(value):
  if value in (None, "unset", "4294967295"):
    return "-"
  try:
    return pwd.getpwuid(int(value)).pw_name
  except (KeyError, ValueError):
    return value
 
 
def argument(value):
  if value is None:
    return ""
  if value.startswith('"') and value.endswith('"'):
    value = value[1:-1]
  if re.fullmatch(r"[0-9A-Fa-f]+", value) and len(value) % 2 == 0:
    try:
      return binascii.unhexlify(value).decode("utf-8", "replace")
    except (binascii.Error, UnicodeError):
      pass
  return value
 
 
def emit(event):
  syscall = event.get("syscall")
  execve = event.get("execve")
  if not syscall or not execve or syscall.get("key") != "user_commands":
    return
 
  try:
    timestamp = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(float(event["epoch"])))
  except (KeyError, ValueError, OverflowError):
    timestamp = "-"
 
  args = [argument(execve.get(f"a{index}")) for index in range(int(execve.get("argc", 0)))]
  command = " ".join(shlex.quote(value) for value in args)
  command = command.replace("\r", "\\r").replace("\n", "\\n")
  login_user = username(syscall.get("auid") or syscall.get("AUID"))
  executing_user = username(syscall.get("uid") or syscall.get("UID"))
  syslog.syslog(syslog.LOG_INFO, f"user-audit: {timestamp}, {login_user}, {executing_user}, {command}")
 
 
current = {}
EVENT_TIMEOUT = 30
syslog.openlog("audit-format", syslog.LOG_PID, syslog.LOG_LOCAL6)
 
for line in sys.stdin:
  match = EVENT_RE.search(line)
  if not match:
    continue
  epoch, serial = match.groups()
  event = current.setdefault(serial, {"epoch": epoch})
  if line.startswith("type=SYSCALL"):
    event["syscall"] = fields(line)
  elif line.startswith("type=EXECVE"):
    event["execve"] = fields(line)
  elif line.startswith("type=EOE"):
    emit(event)
    current.pop(serial, None)
 
  now = time.time()
  expired = [
    key for key, pending in current.items()
    if now - float(pending["epoch"]) > EVENT_TIMEOUT
  ]
  for key in expired:
    current.pop(key, None)

Die erzeugte Meldung hat dieses Format:

user-audit: 2026-09-09 14:30:01, alice, root, 'apt' 'update'

Die Reihenfolge ist:

Zeit, eingeloggter Benutzer, ausführender Benutzer, Befehl

3. Audit-Plugin konfigurieren

Datei `/etc/audit/plugins.d/audit-format.conf` anlegen:

active = yes
direction = out
path = /usr/local/sbin/audit-format-syslog.py
type = always
format = string

Auch bei neueren Debian- und Ubuntu-Versionen ist `audispd` in `auditd` integriert; die Plugin-Konfiguration bleibt dabei versionsabhängig. Die Werte müssen zur installierten `auditd`-Version passen. Das Skript muss ausführbar sein (`chmod 0755`). Wenn AppArmor oder SELinux aktiv ist, müssen zusätzlich der Zugriff auf den Skriptpfad und der passende Sicherheitskontext geprüft werden.

Das Skript verwendet die Syslog-Facility `local6` und den Programmnamen `audit-format`.

4. rsyslogd konfigurieren

Datei `/etc/rsyslog.d/30-audit-format.conf` anlegen:

module(load="imuxsock")
 
template(
    name="AuditSyslogFormat"
    type="string"
    string="%timegenerated% %HOSTNAME% %syslogtag%%msg:::drop-last-lf%\n"
)
 
if ($programname == "audit-format" and
    $syslogfacility-text == "local6") then {
    action(
        type="omfile"
        file="/var/log/syslog"
        template="AuditSyslogFormat"
        createMode="0640"
    )
    stop
}

Dadurch werden nur die vom Formatter erzeugten Audit-Meldungen nach `/var/log/syslog` geschrieben.

`imuxsock` ist erforderlich, weil die Python-Syslog-Bibliothek die Meldung an `/dev/log` sendet. Auf Systemen, die zusätzlich oder hauptsächlich `imjournal` verwenden, sollte geprüft werden, dass `imuxsock` geladen ist und keine doppelte Verarbeitung über `journald` entsteht.

Beispiel:

Sep  9 14:30:01 server audit-format[1234]: user-audit: 2026-09-09 14:30:01, alice, root, 'apt' 'update'

Der erste Zeitstempel wird von rsyslogd ergänzt. Der zweite Zeitstempel stammt aus dem Audit-Ereignis.

5. Dienste neu starten

Zuerst die rsyslogd-Konfiguration prüfen:

sudo rsyslogd -N1

Bei erfolgreicher Prüfung Dienste neu starten:

sudo systemctl restart rsyslog
sudo service auditd restart

Auf manchen Distributionen wird ein direkter Neustart von `auditd` über `systemctl` aus Sicherheitsgründen abgelehnt. Verwende dann `service auditd restart` oder lade nach einer Regeländerung zunächst mit `sudo augenrules –load` die Audit-Regeln neu.

Status prüfen:

sudo systemctl status rsyslog
sudo systemctl status auditd

6. Funktion testen

Einen Befehl ausführen und Syslog beobachten:

id
ls -la /tmp
sudo tail -f /var/log/syslog

Bei einem Aufruf über `sudo` kann die Ausgabe beispielsweise so aussehen:

Sep  9 14:35:12 server audit-format[1234]: user-audit: 2026-09-09 14:35:12, alice, root, 'id'

Dabei bedeutet:

  • `alice`: ursprünglich eingeloggter Benutzer (`auid`)
  • `root`: Benutzer, unter dem der Prozess tatsächlich ausgeführt wurde (`uid`)
  • `'id'`: ausgeführter Befehl

7. Fehlerdiagnose

Audit-Regeln prüfen:

sudo auditctl -l
sudo ausearch -k user_commands

Dienste und Fehlermeldungen prüfen:

sudo journalctl -u auditd -n 50
sudo journalctl -u rsyslog -n 50

Prüfen, ob das Log geschrieben wird:

sudo grep audit-format /var/log/syslog

Sicherheit und Betrieb

Die Audit-Regeln können viele Meldungen erzeugen. Die Datei `/var/log/syslog` sollte deshalb regelmäßig rotiert und vor unbefugtem Zugriff geschützt werden.

Bei produktivem Betrieb sollte geprüft werden, ob die vorhandene Logrotate-Konfiguration für `/var/log/syslog` aktiv ist. Zusätzlich sollten die Berechtigungen der Logdatei und des Verzeichnisses kontrolliert werden.

Die Audit-Daten sind sicherheitsrelevant. Benutzer mit Root-Rechten können lokale Logdateien grundsätzlich verändern. Für manipulationsgeschützte Protokollierung ist eine Weiterleitung an einen zentralen Logserver erforderlich.

Stichworte

Linux, auditd, Audit, Benutzeraktionen, execve, sudo, rsyslog, syslog, audispd, Systemprotokoll, Sicherheitsprotokoll, Logdatei

wiki/logger.txt · Zuletzt geändert: von 127.0.0.1