Files
docker-wazuh/README.md
T
2026-10-07 10:47:30 +02:00

8.9 KiB
Raw Blame History

Wazuh in Docker – Daten per SSH abholen

Wazuh 4.14 (Manager, Indexer, Dashboard) als Single-Node in Docker. Die überwachten Hosts brauchen keinen Agent und keine eingehende Verbindung zum Server. Alles läuft über SSH, das der Server zu den Hosts aufbaut.

                       ┌──────────────────────── Docker ───────────────────────────┐
  Host web01 ◄──ssh──┐ │  sshpull.collector ──► /remote-logs/<host>/*.log ──┐      │
  Host db01  ◄──ssh──┼─┤   (journalctl -f / tail -F, Reconnect + Resume)    │      │
  Host ...   ◄──ssh──┤ │                                                    ▼      │
                     │ │  wazuh.manager  ◄── <localfile>  (Decoder/Regeln)         │
                     └─┤   wazuh-agentlessd: FIM + Befehls-Diffs per ssh           │
                       │        │ filebeat                                         │
                       │        ▼                                                  │
                       │  wazuh.indexer ◄── wazuh.dashboard  :443                  │
                       └───────────────────────────────────────────────────────────┘

Was pro Host abgeholt wird

Baustein Wie Ergebnis in Wazuh
logs: journal journalctl -o json -f über eine dauerhafte SSH-Verbindung. Nach einem Abbruch geht es per Journal-Cursor lückenlos weiter. Alle Standard-Decoder/-Regeln (sshd, sudo, PAM, Kernel, …), z. B. Brute-Force-Erkennung
logs: file tail -F auf eine Datei. Nach einem Abbruch geht es über Inode und Byte-Offset weiter. Wie oben, format wählbar (syslog, apache, json, audit, …)
integrity Agentless: Größe, Rechte, Besitzer und SHA256 aller Dateien unter den Pfaden, periodisch. Der Vergleich läuft gegen eine eigene Baseline pro Host. Alarme bei neuen, geänderten oder gelöschten Dateien (siehe Regeln unten)
commands Agentless: Befehle ausführen und die Ausgabe mit dem letzten Lauf vergleichen. Alarm „agentless: Change detected“ mit Diff (z. B. neuer offener Port, neuer Benutzer)
agent_tunnel Optional: Reverse-Tunnel ssh -R 1514/1515. Ein echter Wazuh-Agent auf dem Host verbindet sich mit 127.0.0.1. Voller Agent-Umfang (SCA, Schwachstellen, Inventar, Echtzeit-FIM)

Die Agentless-Skripte (manager/agentless/sshpull_*) sind eigene Versionen ohne expect. Sie nutzen Schlüssel-Login und optional sudo -n. Bei den mitgelieferten Wazuh-Skripten wirkt die use_sudo-Option nicht.

Der Integritätscheck nutzt bewusst nicht das FIM-Protokoll von Wazuh. Damit landen alle Agentless-Hosts in der FIM-Datenbank des Managers, nur nach Pfad geordnet. /etc/passwd von Host A, Host B und vom Manager würde sich gegenseitig überschreiben, und der erste Lauf erzeugt pro Datei einen „File added“-Alarm. Hier gilt stattdessen: Der erste Lauf legt nur die Baseline an (ein Alarm), danach werden nur echte Änderungen gemeldet.

Eigene Regeln (manager/rules/sshpull_rules.xml)

ID Level Bedeutung
100501 3 FIM-Baseline für einen Host angelegt
100502 5 Datei hinzugefügt
100503 7 Datei geändert (Inhalt, Größe, Rechte oder Besitzer)
100504 7 Datei gelöscht
100505 10 Mehr als 200 Änderungen in einem Lauf: nur eine Zusammenfassung (Update oder Kompromittierung?)
100506 10 Sicherheitskritische Datei (passwd, shadow, sudoers, sshd_config, pam.d, cron, authorized_keys, ld.so.preload)
100507 10 Neue oder geänderte Datei mit SUID/SGID-Bit
100511 7 SSH-Abholung gestört (Log-Stream, Tunnel oder Agentless-Check). Wird nur beim Zustandswechsel gemeldet.
100512 3 SSH-Abholung wieder verbunden

Befehls-Diffs kommen über die Wazuh-Standardregel 555 („Integrity checksum for agentless device changed“), mit dem Diff im Alarmtext.

Installation

Voraussetzungen: Docker und docker-compose, ca. 8 GB RAM frei, ca. 10 GB Platz für Images und Daten. Für den Indexer:

echo 'vm.max_map_count=262144' | sudo tee /etc/sysctl.d/99-wazuh.conf && sudo sysctl --system
./setup.sh                 # Passwörter (.env), TLS-Zertifikate, SSH-Key ssh/id_ed25519, Images bauen
nano hosts.yml             # Hosts eintragen (siehe hosts.yml.example)

Zielhosts vorbereiten

Auf jedem Host wird ein Benutzer wazuh-pull angelegt. Er bekommt die Gruppen systemd-journal und adm (Leserechte auf Logs) und den öffentlichen Schlüssel mit restrict (kein PTY, keine Weiterleitungen):

./setup.sh host-script | ssh admin@web01 sudo sh
# Optionen:  --sudo    NOPASSWD-sudo (nur nötig für root-only Dateien, z.B. /etc/shadow im FIM)
#            --tunnel  erlaubt Reverse-Forwarding auf 127.0.0.1:1514/1515 (für agent_tunnel)

Das Skript erst ansehen, dann ausführen: ./setup.sh host-script

Host-Keys, Test, Start

./setup.sh keyscan         # Host-Keys -> ssh/known_hosts, Fingerprints mit den Hosts vergleichen!
./setup.sh test            # prüft Login, Gruppen, Journal-/Datei-Leserechte
docker-compose up -d
./setup.sh passwords       # Login fürs Dashboard: https://<server>/  (admin / ...)

Der erste Start dauert 1–3 Minuten, bis der Indexer bereit ist.

Hosts ändern

hosts.yml bearbeiten, dann ./setup.sh apply. Damit werden Manager und Collector neu erzeugt. Der Manager schreibt seine Agentless- und Localfile-Konfiguration beim Start aus hosts.yml neu (manager/generate.py).

Wo finde ich die Daten im Dashboard?

Per SSH geholte Logs und Agentless-Ergebnisse laufen über den Manager. Im Dashboard erscheinen sie deshalb beim Agent 000 (wazuh.manager). Unterscheiden lassen sich die Hosts so:

  • Logs: location: /remote-logs/web01/journal.log oder predecoder.hostname: web01
  • FIM: data.sshpull_fim.host: web01, Befehls-Diffs: location enthält wazuh-pull@web01
  • Verbindungsstatus: rule.groups: sshpull_status

Beispiel-Filter in Threat Hunting: rule.groups: sshpull oder location:*web01*

Hinweis: Rohlogs ohne Regeltreffer werden (wie bei Wazuh üblich) nicht indexiert, nur Alerts. Alles archivieren: in config/wazuh_cluster/wazuh_manager.conf <logall_json>yes</logall_json> setzen und in Filebeat das Archiv aktivieren (siehe Wazuh-Doku „archives“).

Optional: voller Agent über SSH-Tunnel

Wenn auf einem Host ein Wazuh-Agent installiert werden darf, er aber den Server nicht erreicht:

  1. In hosts.yml beim Host agent_tunnel: true setzen. Host mit --tunnel vorbereiten.
  2. Agent auf dem Host installieren (Paket von packages.wazuh.com, gleiche Version wie der Manager) mit WAZUH_MANAGER=127.0.0.1, bzw. in ossec.conf <address>127.0.0.1</address>.
  3. ./setup.sh apply. Der Collector hält den Tunnel offen, der Agent registriert sich über 127.0.0.1:1515 und erscheint als eigener Agent im Dashboard.

Ports 1514 und 1515 sind nicht nach außen veröffentlicht. Nur der Collector erreicht sie.

Dateien

Pfad Zweck
hosts.yml Die einzige Stelle für Hosts und Optionen
docker-compose.yml Stack. Nach außen geht nur das Dashboard (DASHBOARD_PORT)
.env Version, Zeitzone, Passwörter (von setup.sh erzeugt, nicht committen)
ssh/ id_ed25519 (privater Schlüssel, nicht committen), known_hosts
common/sshpull_hosts.py Laden und Prüfen von hosts.yml, SSH-Config erzeugen (Manager und Collector)
collector/ Log-Streaming-Dienst
manager/ Manager-Image: openssh-client, Agentless-Skripte, Config-Generator
config/ Wazuh-Konfiguration (Basis: wazuh/wazuh-docker single-node)

Fehlersuche

docker-compose logs -f sshpull.collector                     # Verbindungen/Reconnects pro Host
docker-compose exec wazuh.manager grep -i agentless /var/ossec/logs/ossec.log
docker-compose exec wazuh.manager ls -la /remote-logs/web01/  # kommen Logs an?
  • journal=WARNUNG:nur-eigene-Logs… bei ./setup.sh test: Der Benutzer ist nicht in der Gruppe systemd-journal. Danach neu einloggen bzw. den Collector neu starten.
  • Host key verification failed: ./setup.sh keyscan ausführen, oder in hosts.yml ssh.host_key_checking: accept-new setzen.
  • Agentless-Checks laufen das erste Mal kurz nach dem Start, danach alle interval Sekunden. Der erste Lauf legt nur die Baseline an, Alarme gibt es erst bei Änderungen. Die Checks laufen nacheinander. Bei vielen Hosts mit großen Pfaden (/usr) das interval großzügig wählen.
  • Baseline eines Hosts neu anlegen (z. B. nach einem gewollten Update): docker-compose exec wazuh.manager rm /var/ossec/agentless/.sshpull/web01.json
  • Ohne sudo sind root-only Dateien (z. B. /etc/shadow, Host-Keys) nur über Größe, Rechte und Besitzer überwacht, nicht über den Inhalt.