Files
docker-wazuh/README.md
T
duffyduckandClaude Opus 5.5 61232af61c Setup erkennt Docker oder Podman und deployt entsprechend
- setup.sh erkennt Engine (Docker, Podman, podman-docker-Wrapper) und
  Compose-Werkzeug (docker compose, docker-compose, podman-compose, podman compose)
- Rootless Podman wird mit Hinweis abgelehnt (Ulimits, Port 443, Zertifikatsrechte)
- Als root: vm.max_map_count, firewalld-Port und podman-restart.service setzen
- Neue Befehle: up, down, ps, logs, info; WAZUH_SKIP_SYSCTL und CONTAINER_ENGINE
- Images voll qualifiziert (docker.io/..., localhost/...) wegen Podman-Short-Name-Policy
- Bind-Mounts mit :z fuer SELinux (RHEL)
- README: Abschnitt Red Hat / Podman, Befehle ueber setup.sh

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-07 12:21:32 +02:00

193 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 **oder** Podman, ca. 8 GB RAM frei, ca. 10 GB Platz für Images und Daten.
`setup.sh` erkennt die Umgebung selbst (`./setup.sh info` zeigt, was erkannt wurde):
| Erkannt | Verwendet |
|---|---|
| Docker | `docker compose` oder `docker-compose` |
| Podman (z. B. RHEL, auch mit podman-docker-Wrapper) | `podman-compose` oder `podman compose` |
| SELinux aktiv | Alle Bind-Mounts haben `:z`. Ohne SELinux wirkt das nicht. |
Als root (`sudo ./setup.sh ...`) passt das Skript das System zusätzlich an:
- `vm.max_map_count=262144` (dauerhaft in `/etc/sysctl.d/99-wazuh.conf`)
- firewalld: Port für das Dashboard freigeben
- Podman: `podman-restart.service` aktivieren, damit der Stack nach einem Reboot startet
Ohne root gibt es dafür nur Hinweise. Mit `WAZUH_SKIP_SYSCTL=1` bleibt der Kernel-Parameter
unangetastet. Mit `CONTAINER_ENGINE=docker|podman` lässt sich die Erkennung übersteuern.
```bash
./setup.sh # Passwörter (.env), TLS-Zertifikate, SSH-Key ssh/id_ed25519, Images bauen
nano hosts.yml # Hosts eintragen (siehe hosts.yml.example)
```
### Red Hat / Podman
```bash
sudo dnf install -y podman openssh-clients
sudo dnf install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-9.noarch.rpm # RHEL 9
sudo dnf install -y podman-compose
sudo ./setup.sh # Podman bitte als root, alle weiteren Befehle ebenfalls mit sudo
```
Podman muss als root laufen. Rootless scheitert an den Ulimits der Wazuh-Container (memlock,
nofile), an Port 443 und an den Zertifikatsrechten. `setup.sh` bricht in diesem Fall mit einem
Hinweis ab.
### 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):
```bash
./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
```bash
./setup.sh keyscan # Host-Keys -> ssh/known_hosts, Fingerprints mit den Hosts vergleichen!
./setup.sh test # prüft Login, Gruppen, Journal-/Datei-Leserechte
./setup.sh up # starten (down, ps, logs [dienst] analog)
./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
```bash
./setup.sh logs sshpull.collector # Verbindungen/Reconnects pro Host
./setup.sh logs wazuh.manager | grep -i agentless
```
Für `exec` die passende Engine nehmen (`docker` oder `sudo podman`). Die Containernamen zeigt
`./setup.sh ps`, z. B.:
`sudo podman exec wazuh_wazuh.manager_1 ls -la /remote-logs/web01/`
- `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.
- Podman: Hängt `./setup.sh up` bei „podman wait“, konnte ein Container nicht angelegt werden.
Die Ursache zeigt `sudo podman-compose --verbose up -d 2>&1 | grep -i error`.
- `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|podman> exec wazuh_wazuh.manager_1 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.