Update SecCheck
SecCheck funktioniert!
Wir investieren schon seit längerer Zeit viel Arbeit in den Logger für unsere Sandboxes.
Jetzt können wir endlich verkünden, dass unsere aktuelle Entwicklung funktioniert!
Wir befinden uns nun in der Testphase. Wir wollen herausfinden, was bereits funktioniert und wo noch Feinschliff nötig ist.
Das ist für NDM besonders wichtig, denn wir wollen unseren Nutzern ein gutes und funktionierendes Produkt bieten.
Update SecCheck
Nach unseren bisherigen Versuchen mit Tetragon und Falco haben wir uns dazu entschieden, die in gVisor integrierte SecCheck-Funktionalität genauer zu untersuchen.
Und endlich hat sich die Arbeit ausgezahlt!
Wir haben jetzt einen funktionierenden Aufbau, mit dem wir Events aus unseren gVisor-Sandboxes erfassen und an einen externen Receiver weiterleiten können.
Aber was genau haben wir bisher erreicht?
Was funktioniert jetzt?
Der größte Meilenstein war es, die Kommunikation zwischen gVisor und unserem externen Receiver zum Laufen zu bringen.
Dafür haben wir gVisor so konfiguriert, dass der sogenannte Remote-SecCheck-Sink verwendet wird. Dieser überträgt Trace-Events an einen externen Monitoring-Prozess. Die Kommunikation läuft über einen Unix Domain Socket, während die Events mithilfe von Protocol Buffers übertragen werden.
Unser Receiver kann eingehende Verbindungen annehmen und die empfangenen Events verarbeiten. Damit versuchen wir nicht mehr nur, die Vorgänge innerhalb der Sandbox von außen zu beobachten. Wir erhalten die Events jetzt direkt von gVisor.
Wir konnten bereits verschiedene Arten von Events erfolgreich empfangen und verarbeiten:
- OPEN: Öffnen von Dateien.
- READ: Lesen von Dateien oder File Descriptors.
- WRITE: Schreiben in Dateien oder File Descriptors.
- EXECVE: Ausführen von Programmen, beispielsweise
/bin/shund Node.js. - CONNECT: Events zu Netzwerkverbindungen.
Außerdem können wir die gesammelten Events anhand der verfügbaren Containerinformationen ihrer jeweiligen Sandbox zuordnen.
Ein weiteres wichtiges Detail ist, dass die Events nicht nur in der Konsole ausgegeben werden. Wir können sie auch im JSONL-Format speichern. Dadurch erhalten wir ein strukturiertes Event-Log, das wir später weiterverarbeiten können.
Bei unseren bisherigen Testläufen hat der Receiver außerdem dropped_count: 0 gemeldet.
Bei diesen Testläufen hat der Receiver keine verlorenen Events gemeldet. Das ist ein gutes Ergebnis, allerdings keine Garantie dafür, dass unter anderen Bedingungen oder bei höherer Auslastung niemals Events verloren gehen.
Die Testphase
Nachdem die grundlegende Kommunikation und Event-Erfassung jetzt funktionieren, können wir uns endlich auf das eigentliche Testen des Loggers konzentrieren.
Bisher bestand ein großer Teil unserer Arbeit darin, überhaupt erst die notwendige Infrastruktur zum Laufen zu bringen. Wir mussten herausfinden, wie gVisor seine Events bereitstellt, wie wir diese empfangen und wie wir die eingehenden Daten verarbeiten können.
Jetzt können wir uns auf die eigentlich interessante Frage konzentrieren: Erfasst unser Logger wirklich die Aktivitäten, die wir erkennen möchten?
Dabei beschäftigen wir uns aktuell mit mehreren Punkten:
- Event-Abdeckung: Werden alle relevanten Datei-, Prozess- und Netzwerkaktivitäten erfasst?
- Zuordnung: Können wir jedes Event zuverlässig der richtigen Sandbox zuordnen?
- Event-Metadaten: Erhalten wir genügend Informationen, um nachvollziehen zu können, was passiert ist?
- Zuverlässigkeit: Gehen während der Ausführung Events verloren, insbesondere wenn mehrere Sandboxes gleichzeitig laufen?
Dabei gibt es noch einen wichtigen Unterschied: Eine Operation zu beobachten bedeutet nicht automatisch, dass wir auch ihr Ergebnis richtig interpretieren können. Beispielsweise müssen wir sicherstellen, dass unser Logger sowohl erfolgreiche als auch fehlgeschlagene Systemaufrufe korrekt verarbeitet.
Wir wollen schließlich nicht einfach davon ausgehen, dass alles funktioniert, nur weil einige Events in unseren Logs auftauchen.
Ein Logger, der Events erzeugt, ist nicht automatisch eine gute Lösung für die Sicherheitsüberwachung.
Wir müssen sicherstellen, dass die Events ausreichend vollständig sind, korrekt zugeordnet werden können und für die spätere Analyse tatsächlich nützlich sind.
Wie geht es weiter?
Bis wir den Logger als fertig betrachten können, stehen noch einige wichtige Schritte an.
Zunächst wollen wir unsere aktuellen Tests abschließen und die Event-Verarbeitung dort verbessern, wo es noch notwendig ist.
Danach konzentrieren wir uns darauf, den Logger vollständig in das NDM-Backend zu integrieren.
Unser Ziel ist es, den Receiver gemeinsam mit unserem bestehenden Django-Backend zu betreiben und mehrere Analysen gleichzeitig zu unterstützen. Dabei muss jede Sandbox ihren eigenen, korrekt zugeordneten Event-Stream erhalten.
Die gesammelten Events bilden anschließend die Grundlage für den nächsten Entwicklungsschritt von NDM: die Analyse des Verhaltens von npm-Paketen.
Wir wollen die Events nicht einfach nur sammeln, sondern sie langfristig nutzen, um verdächtiges Verhalten zu erkennen und hilfreiche Informationen darüber bereitzustellen, was ein Paket während seiner Ausführung tatsächlich macht.
Außerdem wollen wir den Logger nicht nur mit kontrollierten Testoperationen, sondern auch mit echten npm-Paketen testen.
Unser Ziel ist es nicht, einfach nur ein weiteres Logging-Tool zu entwickeln.
Wir wollen verstehen, was ein npm-Paket während seiner Ausführung macht, diese Informationen unabhängig vom Paket selbst erfassen und damit die Runtime-Analyse von NDM aussagekräftiger machen.
Endlich Fortschritte!
Nach einigen Anläufen und einer Menge Debugging haben wir endlich eine funktionierende Grundlage für unseren Runtime-Logger geschaffen.
Es liegt noch einiges an Arbeit vor uns, insbesondere beim Testen, bei der Zuverlässigkeit und bei der Integration in unser Backend. Trotzdem haben wir einen wichtigen Meilenstein erreicht.
SecCheck funktioniert und wir können endlich mit dem nächsten Entwicklungsschritt weitermachen!