Fragestellung
Auch kleine und mittlere Unternehmen sind Ziel von Angriffen, haben aber oft weder Budget noch Personal für kommerzielle SIEM-Systeme. Als lizenzkostenfreie Alternative wird häufig Wazuh genannt. Ich wollte wissen, wie gut das in der Praxis funktioniert, und habe es mit Kubernetes getestet, dem De-facto-Standard für Container-Orchestrierung. Wie ein Cluster aufgebaut ist, erkläre ich im Artikel Kubernetes verständlich erklärt.
Meine Frage war: Wie zuverlässig erkennt Wazuh Angriffe auf die Kubernetes Control Plane, und was ist nötig, um vom Auslieferungszustand zu einer wirksamen Erkennung zu kommen?
Ich gehe von einem Angreifer aus, der bereits kompromittierte administrative Zugangsdaten für die Kubernetes-API besitzt, also für die Programmierschnittstelle des Clusters. Für Kubernetes sieht er aus wie ein legitimer Administrator und ist nur an seinen Aktionen zu erkennen. Angriffe, die den kube-apiserver umgehen, habe ich bewusst ausgeklammert.
Wazuh in Kürze
Wazuh ist eine Open-Source-Plattform, ursprünglich eine Abspaltung (Fork) des Host-Überwachungssystems OSSEC. Sie vereint Überwachung direkt auf dem Rechner (HIDS, Host-based Intrusion Detection, und EDR, Endpoint Detection and Response) mit zentraler Log-Auswertung (SIEM) und automatischer Reaktion. Vier Bausteine arbeiten zusammen: Der Agent sammelt auf jedem überwachten System Logs, der Server (Manager) wertet sie aus, der Indexer speichert die Ergebnisse, und das Dashboard dient zur Analyse und Verwaltung.
Wie aus einem Logeintrag ein Alarm wird: Ein Decoder zerlegt den Eintrag in strukturierte Felder. Das Kubernetes-Audit-Log liegt bereits als JSON vor, einem verbreiteten Textformat für strukturierte Daten; der eingebaute JSON-Decoder macht daraus Felder wie objectRef.resource. Dann gleicht der Manager die Felder mit Regeln ab. Jede Regel hat eine eindeutige ID und eine Stufe von 0 bis 16; Stufe 0 erzeugt keinen Alarm. Über <if_sid> wird eine Regel nur geprüft, wenn zuvor eine übergeordnete Regel zugetroffen hat:
Kubernetes-Regelwerk · Auszug<rule id="110001" level="0">
<field name="apiVersion">audit</field>
</rule>
<rule id="110002" level="10">
<if_sid>110001</if_sid>
<regex type="pcre2">requestURI":"\/api\/v1\/secrets…</regex>
<mitre><id>T1552</id></mitre>
</rule>
Regel 110001 wählt nur Kubernetes-Audit-Ereignisse aus. Erst die Kindregel 110002 schlägt Alarm, wenn jemand alle Secrets des Clusters auflistet. Die Kennung T1552 stammt aus MITRE ATT&CK, einem öffentlichen Katalog von Angriffstechniken, wie reale Angreifer sie einsetzen. Ordnet man jedem Alarm eine Technik zu, sieht man, was erkannt wird und wo Lücken bleiben.
Für Docker bringt Wazuh eine eigene Anbindung mit, für die Steuerungsebene von Kubernetes nicht. Das Kubernetes-Audit-Log läuft über die normale Log-Erfassung und braucht passende Regeln.
Testumgebung und Messung
Die gesamte Infrastruktur ist als Code mit Terraform beschrieben und jederzeit identisch reproduzierbar: vier virtuelle Maschinen in zwei getrennten Subnetzen auf einer OpenStack-Umgebung, einer offenen Cloud-Plattform. Ein Angreifer-Knoten mit der administrativen kubeconfig bildet die gestohlenen Zugangsdaten ab, zwei Knoten (Nodes) bilden den Cluster mit K3s, einer schlanken Kubernetes-Distribution, und ein Knoten trägt Wazuh. Auf eine Firewall dazwischen habe ich bewusst verzichtet, damit nur die Erkennung von Wazuh gemessen wird; aus dem öffentlichen Internet ist das Netz nicht erreichbar. Alle Versionen sind fixiert, unter anderem K3s v1.35.5+k3s1, Wazuh 4.14.5 und Stratus Red Team 2.33.0. Das ist der Stand meiner Messung; inzwischen gibt es neuere Versionen.
Die Datenquelle: das Audit-Log
Jeder Zugriff auf den Cluster läuft über den kube-apiserver. Er protokolliert jede Anfrage im Audit-Log: wer, was, auf welche Ressource, mit welchem Ergebnis. Das ist die einzige Datenquelle des Tests. Ein Wazuh-Agent läuft als DaemonSet auf jedem Cluster-Knoten, liest das Log und schickt es an den Manager.
Wie viel darin steht, legt die Audit-Policy fest. Auf der Stufe Metadata steht nur, wer was getan hat, aber nicht der Inhalt. Erst die Stufe Request protokolliert zusätzlich den Inhalt der Anfrage, und nur dort stecken Details wie privileged: true oder ein eingehängtes Host-Verzeichnis. Ich habe die Referenz-Policy des Herstellers übernommen: Verändernde Pod-Operationen landen auf der Stufe Request, alles Übrige als Metadata. Stünden sicherheitskritische Ressourcen nur auf Metadata, könnten Regeln wie 110008 und 110010 nie anschlagen, ohne dass etwas auf den Ausfall hindeutete.
Angriffe und Messung
Als Angriffswerkzeug habe ich Stratus Red Team gewählt. Es ist auf die Kubernetes-API ausgerichtet und führt jeden Test in drei Schritten aus: warmup bereitet vor, detonate greift an, cleanup räumt auf. Von den acht Kubernetes-Techniken im Katalog ließen sich sieben im Cluster ausführen; alle sieben habe ich geprüft.
Gemessen habe ich in zwei Phasen, zwischen denen sich nur das Regelwerk ändert: Phase 1 mit dem Standard-Regelwerk (ein Lauf je Technik), Phase 2 zusätzlich mit dem Referenz-Regelwerk des Herstellers, den Regeln 110001 bis 110016 (drei Läufe je Technik). Ein eigenes Python-Skript startet die Angriffe, holt Audit-Logs und Alarme ab und misst die Erkennungslatenz: die Zeit vom Eingang der Anfrage beim API-Server bis zum geschriebenen Alarm. Damit die Zeitstempel verschiedener Maschinen vergleichbar sind, gleicht chrony alle Uhren per NTP (Network Time Protocol) ab; der Versatz lag unter 0,1 ms. Außerdem habe ich auf dem Manager die ungefilterte Archivierung aktiviert. So lässt sich belegen, ob ein fehlender Alarm an fehlenden Daten oder an fehlenden Regeln liegt.
Ergebnisse
Ausgewertet habe ich 28 Messläufe: sieben in Phase 1 und 21 in Phase 2. Keine der laufbegleitenden Gültigkeitsprüfungen schlug fehl.
0 von 7: Alle Daten kommen an, keine Regel schlägt an
Mit dem Standard-Regelwerk löste Wazuh bei keiner der sieben Techniken einen angriffsspezifischen Alarm aus. Gleichzeitig zeigt der Abgleich über die auditID im Archiv: Jedes relevante Audit-Ereignis hat den Manager erreicht und wurde verarbeitet, aber keines passte auf eine Regel.
In Phase 2 schlug in allen 21 Läufen die erwartete Regel an, bei der Zertifikatstechnik jedes Mal die komplette Kette 110011–110015 (5/5). Die Erkennung auf Taktik-Ebene stieg von 0/3 auf 3/3 (Credential Access, Persistence und Privilege Escalation nach MITRE ATT&CK).
| Technik | Audit-Ereignisse beim Manager | Phase 1 | Phase 2 | Regel |
|---|---|---|---|---|
dump-secrets T1552 · alle Secrets auslesen | 3/3 (100 %) | nicht erkannt | erkannt | 110002 |
steal-serviceaccount-token T1528 · Token aus einem Pod lesen | 3/3 (100 %) | nicht erkannt | erkannt | 110003 |
create-client-certificate T1649 · Client-Zertifikat ausstellen | 6/6 (100 %) | nicht erkannt | erkannt | 110011–110015 |
create-token T1098 · Token mit 30 Jahren Gültigkeit | 3/3 (100 %) | nicht erkannt | erkannt | 110016 |
hostpath-volume T1611 · Host-Dateisystem einhängen | 3/3 (100 %) | nicht erkannt | erkannt | 110008 |
nodes-proxy T1068 · direkt zum Kubelet | 5/5 (100 %) | nicht erkannt | erkannt | 110009 |
privileged-pod T1611 · privilegierter Container | 3/3 (100 %) | nicht erkannt | erkannt | 110010 |
Erkennungslatenz
Die Latenz lag über alle 21 Messungen zwischen 0,055 s und 1,917 s, im Mittel bei 1,041 s und damit weit unter dem Beobachtungsfenster von 20 Sekunden. Am schnellsten war nodes-proxy (Ø 0,510 s), am langsamsten steal-serviceaccount-token (Ø 1,577 s). Drei Läufe je Technik ergeben nur eine grobe Bandbreite, für eine belastbare Statistik reichen sie nicht.
- dump-secrets1,23 s
- steal-sa-token1,58 s
- client-certificate0,94 s
- create-token1,16 s
- hostpath-volume0,69 s
- nodes-proxy0,51 s
- privileged-pod1,17 s
Signal und Rauschen
Schon im Pilotlauf fiel das Rauschen auf: Im Beobachtungsfenster verzeichnete der Manager 43 Roh-Alarme mit Referenz-Regelwerk und 22 ohne. Der weitaus größte Teil stammte aus der Selbstüberwachung des Managers, nämlich Anmeldungen, Sitzungen und sudo-Aufrufe (Befehle mit Administratorrechten), ausgelöst durch die SSH-Zugriffe meines eigenen Skripts. Erst ein Filter auf die Herkunft (Feld location) ließ genau einen relevanten Angriffsalarm übrig. Im echten Betrieb wächst dieses Rauschen mit jedem Dienst. Wer nicht von Anfang an filtert und priorisiert, gewöhnt sich an die Alarme und übersieht irgendwann den, auf den es ankommt.
Grenzen
Ein anderer Befehl umgeht die Regel
Ich wollte auch wissen, ob die Regeln den Angriff erkennen oder nur die konkrete Schreibweise des Testwerkzeugs. Regel 110008 erkennt den hostPath-Ausbruch nur, wenn der Angreifer exakt cat /host/etc/passwd ausführt. Mit dem gleichwertigen Befehl head -n 5 /host/etc/passwd las der Pod die Host-Datei genauso aus, die Telemetrie kam vollständig an, trotzdem blieb der Alarm aus. Erst als ich die Regel auf den strukturellen Kern reduziert hatte, das Einhängen des kompletten Host-Dateisystems (hostPath.*"path":"\/"), schlug sie auch bei der Variante an. Ein so allgemeines Muster kann allerdings Fehlalarme erzeugen, weil auch legitime Dienste wie Monitoring-Agenten ähnliche Mounts nutzen. Diese Abwägung kann kein Hersteller für Deine Umgebung vorab treffen.
Fehlalarme blieben weitgehend ungeprüft
7/7 beschreibt die Erkennungsquote (Recall). Über Fehlalarme im normalen Betrieb sagt das nichts, denn die Umgebung hatte keinen nennenswerten legitimen Verkehr. Erste Hinweise gab es trotzdem schon im Labor: Regel 110005 schlägt bei jeder ServiceAccount-Anlage an, auch beim default-Account, den Kubernetes für jeden neuen Namespace anlegt. Die Korrelationsregel 110007 löste bei einer legitimen, per Terraform ausgeführten Rechtevergabe aus, weil Automatisierung für die Regel genauso aussieht wie ein Angriff.
Weitere Einschränkungen: Die achte Technik, create-admin-clusterrole, brach nach 60 s ab, weil sie ein Token-Secret erwartet, das Kubernetes seit Version 1.24 nicht mehr automatisch anlegt. Das Audit-Log zeigt nur, dass ein Container gestartet wird, nicht, was er danach tut. Außerdem habe ich nur eine einzige Konfiguration unter Laborbedingungen getestet; die Ergebnisse lassen sich nicht ohne Weiteres übertragen.
Lehren aus dem Test
Das Regelwerk entscheidet
Die Telemetrie war von Anfang an vollständig. Ob ein Angriff sichtbar wurde, hing allein an den Regeln. Mit dem Standard-Regelwerk erkannte Wazuh keinen der Angriffe.
Mit echten Techniken und Varianten testen
Erst ein kontrollierter Angriff zeigt, ob ein Alarm wirklich kommt. Wiederhole ihn anders formuliert: Bleibt der Alarm aus, ist die Regel zu eng.
Regeln am zwingenden Kern ansetzen
Einen frei wählbaren Befehl kann ein Angreifer umformulieren, die Einstellung privileged in Regel 110010 nicht.
Policy und Regeln gemeinsam planen
Ohne Stufe Request für sicherheitskritische Ressourcen fehlt den Regeln die Grundlage, ohne dass es jemand bemerkt.
Härtung vor Erkennung
Verbietet die Cluster-Konfiguration hostPath-Mounts und privilegierte Container, fehlt den getesteten Ausbruchstechniken von vornherein die Grundlage.
Was das für Unternehmen bedeutet
Für Unternehmen ohne zentrale Angriffserkennung und mit knappem Sicherheitsbudget ist Wazuh ein realistischer Einstieg: Mit dem passenden Regelwerk meldete es in meinem Test alle sieben Angriffe auf die Kubernetes Control Plane, im Mittel nach gut einer Sekunde. Lizenzkosten fallen keine an, Aufwand aber schon: Regeln müssen ergänzt, gegen Varianten getestet und gepflegt werden, Fehlalarme gehören laufend in den Blick, und der Betrieb selbst braucht Überwachung, damit keine Ereignisse unbemerkt verloren gehen. Wazuh ist eine Schicht in einem mehrstufigen Sicherheitskonzept und ersetzt keine vorbeugenden Schutzmaßnahmen. Mein Rat: klein anfangen, mit wenigen wichtigen Logquellen und einem kontrollierten Test, ob Alarme wirklich kommen.
Mir hat das Projekt vor allem gezeigt, wie ein sauberer Aufbau aussieht: reproduzierbare Infrastruktur mit Terraform, Kubernetes und ein Monitoring, dessen Messkette nachweislich funktioniert. Diese Erfahrung nutze ich heute in meinen Cloud-Projekten. Für Penetrationstests oder ein Sicherheitsaudit sind spezialisierte Security-Dienstleister die richtige Adresse.
Tech-Stack
- Wazuh 4.14
- Kubernetes
- K3s
- Terraform
- OpenStack
- Rocky Linux
- Stratus Red Team
- MITRE ATT&CK
- Kubernetes Audit-Logging
- PCRE2 (reguläre Ausdrücke)
- kubectl
- Python
- chrony / NTP (Zeitabgleich)
- SIEM