Docker/Buch/18 Sicherheit

Aus Foxwiki
Version vom 7. November 2026, 10:29 Uhr von Dirkwagner (Diskussion | Beiträge) (Die Seite wurde neu angelegt: „<noinclude> <!-- ---- {{Navigation|<zurück>|<nachste>}} {{Navigation|BSI/200-3|BSI/200-3/Einleitung/Beispiele}} ---- --> '''{{BASEPAGENAME}}''' </noinclude> == Beschreibung == Sicherheit Abgesehen von den Vorteilen bei der Applikationsentwicklung und beim Deploy- ment bieten Container bei korrekter Verwendung einen besseren Schutz gegen Angriffe als Anwendungen, die nicht im Container laufen: Zum einen sind standardmäßig je nach Plattform bzw. Distr…“)
(Unterschied) ← Nächstältere Version | Aktuelle Version (Unterschied) | Nächstjüngere Version → (Unterschied)
Wechseln zu:Navigation, Suche

Docker/Buch/18 Sicherheit


Beschreibung

Sicherheit

Abgesehen von den Vorteilen bei der Applikationsentwicklung und beim Deploy- ment bieten Container bei korrekter Verwendung einen besseren Schutz gegen Angriffe als Anwendungen, die nicht im Container laufen:

Zum einen sind standardmäßig je nach Plattform bzw. Distribution Sicherheits- maßnahmen aktiv, die bei der Ausführung von Containern gewisse Angriffe unter- binden. Lesen Sie dazu mehr in Abschnitt 18.7, »Secure Computing Mode«, und in Abschnitt 18.8, »AppArmor-Sicherheitsprofile«. Zum anderen sind Container gegenüber dem Betriebssystem durch sogenannte Namespaces abgegrenzt. Diese Abschottung kann durch User Namespaces noch verbessert werden (siehe Abschnitt 18.5). Da Docker den Bereich von Betriebssystemen bis Applikationen betrifft, können wir in diesem Kapitel nur an der Oberfläche kratzen. Wir möchten Ihnen aber die prin- zipiellen Sicherheitsmechanismen von Docker vorstellen und Ihnen ein paar Best Practices vermitteln. Dabei konzentrieren wir uns auf Linux als Docker-Host, weil Linux im Deployment die am weitesten verbreitete Plattform ist (ganz unabhängig davon, unter welchem Betriebssystem Sie die Entwicklung durchführen).

Weiterführende Informationen Wenn Sie sich tiefgehender mit Container-Sicherheit auseinandersetzen möchten, empfehlen wir Ihnen den Blog von Jessie Frazelle, https://blog.jessfraz.com. Sie war maßgeblich an der Einführung des Secure Computing Mode und der AppArmor- Unterstützung als Standardsicherheitsmaßnahmen in Docker beteiligt.

18.1 Softwareinstallation Unabhängig von Docker möchten wir zuvor noch ein Wort zur Installation von exter- nen Programmen verlieren, da wir in diesem Buch mehrfach solche Installationen beschreiben. Im Container-Umfeld erfreut sich die Programmiersprache Go großer


18 Sicherheit

Beliebtheit. Programme in dieser Sprache lassen sich leicht für verschiedene Plattfor- men übersetzen und als ein statisch gelinktes Binärprogramm vertreiben. kubectl, helm und hcloud sind solche Beispiele. Zur Installation reicht es, das Programm mit curl herunterzuladen, es ausführbar zu machen (unter Linux und macOS) und es in den Suchpfad zu kopieren. Anders als bei der Installation von Programmen mit dem Paketmanager Ihres

Betriebssystems gibt es keine Prüfung einer digitalen Signatur. Sie können also nicht
erkennen, ob die Binärdatei auf dem Server von einem Angreifer ausgetauscht wurde.
Ihr Vertrauen in das Programm basiert auf der Identität des Webservers, von dem
Sie das Programm mit curl herunterladen. Diese Identität wird durch das SSL-Zerti-
fikat bestätigt. Sie sollten bei einem solchen Download also nie die Option -k oder

--insecure von curl verwenden, da sie die Überprüfung des Zertifikats umgeht.

Das Gleiche gilt für die Installation von Programmen mit diesem Kommando:

  1. potentie l l gef ä hrlich !

curl -fsSL get . docker . com | sudo sh

Die Seite https://get.docker.com liefert ein Shell-Script, das die Docker-Installation für unterschiedliche Betriebssysteme durchführt. Dieser Aufruf ist in mehrerlei Hinsicht problematisch: Zum einen verbinden Sie sich nicht explizit mit dem SSL-gesicherten Server, sondern unverschlüsselt auf Port 80. Der Parameter -L von curl ermöglicht eine automatische Weiterleitung, was in diesem Fall wirklich auf die verschlüsselte Seite https://get.docker.com und damit zu dem gewünschten Ergebnis führt. Ein Man-in-the-Middle-Angriff wäre hier aber sehr einfach durchzuführen, da die erste Verbindung unverschlüsselt erfolgt.

Ein weiteres Risiko entsteht durch das gleichzeitige Herunterladen und Ausführen des Scripts. Eine Störung in der Netzwerkverbindung während des Downloads könnte zu einer sehr unangenehmen Situation führen. Denken Sie nur an ein Konstrukt in dieser Form:

TEMPDIR =" delete_m e " rm -rf $HOME / $TEMPDIR

Würde die Netzwerkverbindung nach dem / abbrechen, stünde als Kommando nur noch rm -rf $HOME/ da, was nicht zu dem gewünschten Ergebnis führt. Zugegeben, das ist ein etwas konstruiertes Beispiel, aber Sie erkennen die Problematik. Mit ein wenig mehr Tipparbeit lässt sich das Problem aber deutlich entschärfen:

curl https :// get . docker . com / -o docker - install . sh

  1. ü berpr ü fen , ob es wirklich das Installations - Script ist :

vi docker - install . sh chmod + x docker - install . sh ./ docker - install . sh

18.2 Herkunft der Docker-Images Alle Docker-Images, die Sie in diesem Buch sehen, leiten sich von anderen Images ab. Das erspart Ihnen eine Menge Arbeit. Außerdem werden die Images in den meisten Fällen von den Softwareentwicklern selbst betreut und sind deshalb für die jeweilige Software optimiert. Abgesehen von Kapitel 16, »GitLab«, verwenden wir in diesem Buch immer das offi- zielle Docker-Image-Repository, den Docker Hub. Die Firma Docker Inc., stellt diesen Service für öffentliche Images kostenlos zur Verfügung. Jeder registrierte Benutzer kann Images hochladen, die anschließend allen Docker- Usern unter dem Kürzel <Benutzername>/<image> zur Verfügung stehen. Für diese Images gibt es keine Garantie. Sollte ein Dockerfile öffentlich sichtbar sein, ist es eine gute Idee, einen Blick darauf zu werfen. Ohne Zugriff auf ein Dockerfile haben Sie die Adresse zu dem Image hoffentlich aus einer sicheren Quelle erhalten. Als registrierter Benutzer im Docker Hub mit einem bezahlten Abo-Modell hat man die Möglichkeit, eigene Images automatisch auf bekannte Sicherheitslücken zu scan- nen. Docker hatte dieses Geschäft an die Firma Snyk ausgelagert (https://snyk.io), seit Februar 2023 ist es aber integrierter Bestandteil von Docker und läuft unter dem Namen Basic Vulnerability Scanning. Das neueste Konzept von Docker, das Ende Juli 2023 noch unter Early Access einge- stuft war, heißt Docker Scout. Es kann einerseits über eine Weboberfläche bedient werden (https://scout.docker.com, siehe Abbildung 18.1) oder auch als Plugin für das Docker-Kommandozeilenprogramm verwendet werden.

Leider konnten wir noch nicht viel Erfahrungen mit dem neuen Werkzeug machen; unsere ersten Versuche waren aber vielversprechend. Das Tool weist auf bekannte Common Vulnerabilities and Exposures (CVEs) hin und greift dabei auf öffentliche CVE- Datenbanken zurück. Im Juli 2023 konnten wir keine konkreten Angaben dazu finden, ob die offiziellen Images im Docker Hub automatisch auf Sicherheitsprobleme untersucht werden. Offizielle Images sind auf der Website von Docker als Official Repository gekennzeich- net, und ihnen ist kein Benutzername vorangestellt. Auf der Docker-Hub-Website erkennen Sie solche Images daran, dass ihnen in der URL ein Unterstrich vorange- stellt ist; die URL für das offizielle Node.js-Image lautet zum Beispiel: https://hub.docker.com/_/node


18 Sicherheit

Abbildung 18.1 Das Ergebnis des Docker-Scout-Sicherheits-Scans für das Hello-World-Node-Image

Externe Registries Große IT-Dienstleister wie Google, Microsoft und Amazon bieten ebenfalls Container- Registries in ihrem Cloud-Portfolio an. Wenn Sie sich für eine dieser Plattformen entscheiden, um dort Ihre Container laufen zu lassen, ist der Griff zu der jeweiligen Registry sicher sinnvoll. Die Images haben kurze Übertragungszeiten und werden mit dem vorhandenen Konto abgerechnet. Die Sicherheitskontrollen sind dort noch nicht so stark integriert, wie es im Docker Hub für die offiziellen Images der Fall ist. Bei Azure können Sie den kostenpflichtigen Microsoft Defender for Cloud aktivieren, der neben anderen Diensten auch das Scan- nen von Container-Images übernimmt. Google hat einen integrierten Dienst, der nach Sicherheitsproblemen in Images suchen kann, die auf der hauseigenen Artifact Registry (vormals Container Regis- try) hochgeladen wurden. In der Elastic Container Registry von Amazon haben Sie ebenfalls die Möglichkeit, Docker-Images automatisch scannen zu lassen. Amazon verwendet dazu den Open-Source-Scanner Clair, den Sie auf GitHub finden: https:// github.com/quay/clair.

Ein weiterer kommerzieller Anbieter einer Container-Registry ist Quay (https://quay. io). In der Enterprise Edition werden auch hier Ihre Images automatisch nach Sicher- heitsproblemen durchsucht und die Resultate in der Weboberfläche dargestellt. Der Scanner hält sogar Lösungsvorschläge durch Paket-Updates der Distribution bereit (siehe Abbildung 18.2). Quay wurde als Registry für das containeroptimierte Betriebs- system CoreOS entwickelt, das Anfang 2018 vom Linux-Distributor Red Hat übernom- men wurde.

Abbildung 18.2 Der Sicherheits-Scan für das »coreos/awscli«-Image im Quay-Repository

Wo Sie Ihre Images auch speichern, wichtig ist, dass Sie allen Schichten in Ihrem Image vertrauen können. Ein automatisches Scannen in der Registry erhöht auf jeden Fall die Image-Sicherheit.


18 Sicherheit

18.3 »root« in Docker-Images Der Administrator-Zugang (root) zu Unix-Systemen war in früheren Zeiten sehr streng geregelt. Normale Benutzer arbeiteten immer mit eingeschränkten Rechten, und Änderungen am System mussten beim Administrator beantragt werden. Aus die- ser Zeit stammt die Regel, dass Netzwerkports unter 1024 nur vom root-User geöffnet werden dürfen. Benutzer, die sich mit dem Server über einen dieser Ports verbanden, wussten, dass der Administrator die Applikation kontrolliert hatte. Die Standardports aller gängigen Server (Mail, Web, FTP . . . ) liegen unter dieser Grenze. In der Softwareentwicklung war immer schon klar, dass ein Serverdienst, der unter der root-Benutzerkennung läuft, sicherheitstechnisch problematisch ist. Deshalb wurden Funktionen in den Quellcode eingebaut, die nach der Verbindung mit dem privilegierten Port die root-Rechte abgeben und unter einer anderen Benutzerken- nung weiterlaufen. Sie können das sehr einfach in einem Docker-Container überprüfen. Starten Sie dazu den Apache Webserver in einem Container, und lassen Sie sich die Prozesse mit der dazugehörenden Benutzerkennung ausgeben:

docker run -d --name apache httpd : alpine docker exec apache ps xau

PID USER TIME COMMAND

1 root        0:00   httpd -DFOREGROU N D
8 daemon      0:00   httpd -DFOREGROU N D
9 daemon      0:00   httpd -DFOREGROU N D

10 daemon 0:00 httpd -DFOREGROU N D 97 root 0:00 ps xau

Wie Sie sehen, wird der Prozess mit der Prozess-ID 1 als root-Benutzer ausgeführt, die weiteren httpd-Prozesse als Benutzer daemon.

Nginx-Webserver ohne »root«-Rechte Auch der Nginx-Webserver verwendet diese Technik:

docker run -d --name nginx nginx : alpine docker exec nginx ps xau

PID USER TIME COMMAND 1 root 0:00 nginx : master process nginx -g daemon off ; 6 nginx 0:00 nginx : worker process 7 root 0:00 ps xau

Auch hier sehen Sie den Benutzerwechsel: Der Master-Prozess läuft als root mit der Prozess-ID 1, und der Worker-Prozess läuft unter der Benutzerkennung nginx. Wenn

Sie versuchen, den Container als Benutzer nginx zu starten, so bekommen Sie die Feh- lermeldung Permission denied, weil der Benutzer keine Schreibrechte im Verzeichnis /var/cache/nginx hat:

docker run -d --user = nginx --name nginx nginx : alpine docker logs nginx

2023/07/ 2 5 12:31:00 [ emerg ] 1#1: mkdir () "/ var / cache / nginx / client_t em p " failed (13: Permissio n denied ) nginx : [ emerg ] mkdir () "/ var /cache /nginx /client_t e m p " failed ...

Das ist aber nicht das einzige Problem mit Schreibrechten am System. Beim Server- start wird eine Datei mit der Prozess-ID im Ordner /var/run angelegt. Eine einfache Lösung für diese Probleme ist, dass Sie die Datei und den Ordner in Ihrem Dockerfile als root anlegen und anschließend die Rechte so ändern, dass die Datei dem Benutzer nginx gehört. Das Dockerfile kann dann so aussehen:

FROM nginx : alpine RUN touch / var / run /nginx .pid \ && chown -R nginx : nginx / var /run / nginx . pid \ && chown -R nginx : nginx / var /cache /nginx

In früheren Auflagen dieses Buches folgte hier eine Beschreibung des Problems, dass Standardbenutzer nicht auf die privilegierten Ports eines Systems (alle unter 1024) Schreibzugriff haben. Damit wäre es nicht möglich, den Webserver auf Port 80 oder 443 im Container zu starten. Mit der Version 20.10 der Docker Engine wurde diese Beschränkung aufgehoben, indem der Docker-Dämon beim Start einen entsprechen- den Kernel-Parameter ändert (net.ipv4.ip_unprivileged_port_start=0). Sie merken schon: Ganz ohne Tricks funktionieren traditionelle Unix-Server ohne root-Rechte nicht im Container. Bei anderen Servern werden Sie weitere Anpassun- gen vornehmen müssen (oft sind es Schreibrechte in Unterordnern von /var).

18.4 Der Docker-Dämon Wenn Sie das docker-Programm auf der Kommandozeile starten, nimmt es Kon- takt mit einem Docker-Dämon auf. Standardmäßig wird die Kommunikation über den Unix-Socket /var/run/docker.sock abgewickelt; mit der Umgebungsvariablen DOCKER_HOST können Sie auch auf einen über das Netzwerk erreichbaren Docker- Dämon zugreifen. Das Problem mit dem Docker-Dämon ist, dass er mit root-Rechten laufen muss. Und hier schrillen natürlich die Alarmglocken: Ein Bug im Code des Docker-Dämons kann dazu führen, dass ein Angreifer root-Rechte auf dem Host- System erhält.


18 Sicherheit

Ein weiteres Problem, das sich aus dieser Situation ergibt, ist, dass Benutzer, die Zugriff auf den Docker-Dämon haben (also solche, die Docker verwenden dürfen), quasi root-Rechte auf dem Host-System haben. Wir wollen das mit einem einfachen Beispiel demonstrieren. Die Datei /etc/shadow enthält auf einem Linux-System die verschlüsselten Passwörter der lokalen Benutzeraccounts. Sie ist aus Sicherheitsgrün- den für normale Benutzer nicht lesbar:

cat / etc / shadow

cat : /etc / shadow : Permissi o n denied

Mit einem Docker-Container kann der gleiche unprivilegierte Benutzer die Datei lesen:

docker run -it --rm -v /:/ host alpine cat /host / etc / shadow

root :!:17779: 0 : 9 99 9 9 : 7 :: : daemon : * :17779 : 0 :9 9 9 9 9 :7 : : : bin : * :17779 :0 : 9 9 99 9 : 7 : :: [...]

Sie binden das Wurzelverzeichnis des Host-Computers einfach in den Container ein und haben dadurch root-Zugriff auf das gesamte Dateisystem. Sie hätten auch ein rm -rf /host ausführen können, aber dann wäre Ihr Computer in kürzester Zeit nicht mehr funktionsfähig gewesen. Natürlich kann ein Angreifer mit diesem Trick nicht nur Ihr System ausspionieren, er kann auch ein Programm durch eine korrumpierte Version ersetzen oder Ihre Festplatte verschlüsseln. Wie wir schon in Abschnitt 6.7, »Docker-Interna«, beschrieben haben, ist es eine gän- gige Praxis, das eigene Benutzerkonto der Gruppe docker hinzuzufügen. Sie können das docker-Programm dann ohne den sudo-Aufruf starten, was bei häufigen Auf- rufen sehr praktisch ist. Sicherheitstechnisch ist das aber nicht empfehlenswert und bestenfalls für Entwicklungsrechner akzeptabel: Ein Angreifer, der Ihnen ein Stück ausführbaren Code unterschieben will, braucht dann aber auch kein Passwort, um root auf Ihrem System zu werden!

Rootless Docker Dem Problem, dass ein Dienst vollen Zugriff auf das ganze System hat, haben sich die Entwickler von Docker nun angenommen. Schließlich war es einer der großen Kritik- punkte an Docker und sorgte wohl unter anderem für die Entwicklung von Podman. Seit der Version 20.10 von Docker gilt der Rootless Mode als stabil und kann sehr ein- fach installiert werden (mehr dazu in Kapitel 2, »Installation«). Wenn Sie sich für die genaue Funktionsweise dieser Technik interessieren, lesen Sie im nächsten Abschnitt mehr dazu.

18.5 User Namespaces Die Funktionsweise von Namespaces, also der Technik, die Container voneinander und vom Host abgrenzt, haben wir ebenfalls in Abschnitt 6.7, »Docker-Interna«, skiz- ziert. Die in diesem Abschnitt vorgestellten User Namespaces gehen noch einen Schritt weiter. User Namespaces sind vor allem dann empfehlenswert, wenn Sie in Ihren Containern als root-Benutzer arbeiten müssen. Wir haben in Abschnitt 18.3, »root in Docker- Images«, ja schon darauf hingewiesen, wie Sie durch die USER-Anweisung vermeiden können, dass der Prozess im Container mit root-Rechten läuft. Allerdings ist diese Vorgehensweise nicht immer möglich. In solchen Fällen können Sie dank User Name- spaces weiterhin mit root im Container arbeiten; diese Benutzerkennung wird aber nicht auf root auf dem Host umgesetzt. Rootless Docker macht sich genau diese Funktion zunutze und bildet so den root-Benutzer im Container auf einen unprivi- legierten Benutzer am System ab.

Funktionsweise Mit User Namespaces bietet der Linux-Kernel Ihnen die Möglichkeit, Benutzer-IDs (also die numerische Kennung eines Benutzerkontos) in einem Namespace unabhän- gig vom Host-Computer zu verwalten. Innerhalb des Namespace (bei Docker also innerhalb des Containers) ändert sich dadurch nichts: root behält die UID 0. Greift der root-Benutzer im Container aber auf eine vom Host eingebundene Datei zu, so gelten für ihn die Zugriffsrechte eines unbekannten Benutzers. Wenn Sie Rootless Docker verwenden, brauchen Sie sich um die weiteren Einstel- lungen nicht zu kümmern, denn der unprivilegierte Docker-Dämon regelt diese Einstellungen für Sie. Möchten Sie eine systemweite Docker-Installation auf User Namespaces umstellen, haben Sie unterschiedliche Möglichkeiten. Wenn Sie Docker unter Ubuntu Linux 22.04 mit dem Installations-Script von https://get.docker.com installiert haben, können Sie einfach die Datei /etc/docker/daemon.json mit folgen- dem Inhalt anlegen:

{ " userns - remap ": "default " }

Starten Sie anschließend den Docker-Server mit systemctl restart docker neu. Docker hat bei dem Neustart den Benutzer dockremap auf dem Host angelegt. Für die- sen Benutzer befindet sich auch ein Eintrag in der Datei /etc/subuid:

cat / etc / subuid

lxd :100000: 65 5 3 6 root :100000:6 5 5 3 6


18 Sicherheit

dockerbu c h :165536:6 5 5 3 6 dockrema p :231072:6 5 5 3 6

Die Datei enthält den Benutzernamen, die Start-ID für Benutzerkennungen in einem Container und die Anzahl der möglichen Benutzer im Container. Das bedeutet, dass root mit der Benutzer-ID 0 im Container auf die Benutzer-ID 231072 auf dem Host abgebildet wird. Ein Benutzer im Container mit der UID 1001 bekommt auf dem Host die UID 232073. Wir haben uns anschließend als Benutzer dockerbuch am Host ange- meldet und das Programm top in einem Container mit Alpine Linux gestartet:

docker run -it --rm -v /:/ host alpine top

Die folgende Auflistung der Prozesse auf dem Host zeigt die Benutzerkennung, die Prozess-ID und das ausgeführte Kommando:

USER PID COMMAND root 998 / usr / bin / containe r d root 23615 / usr / bin / containerd -shim - runc - v2 --namespac e ... 231072 23642 \_ top [...] dockerb + 21998 \_ bash dockerb + 23582 \ _ sudo docker run -it --rm -v /:/ ho ...

Wie Sie sehen, laufen die bash und das docker run-Kommando unter der Benutzerken- nung dockerbuch . Der Benutzer bei dem top-Kommando im Container wird nur mit der numerischen UID 231072 angezeigt, weil es hier keine Entsprechung auf dem Host gibt (genau genommen in /etc/passwd ). Die UID errechnet sich (wie oben beschrie- ben) aus dem Eintrag in der Datei /etc/subuid und der UID des Container-Benutzers. In diesem Fall lautet sie 0, weil das Programm top als root-Benutzer gestartet wurde. Der root-Benutzer innerhalb des Containers kann nun keine Dateien mehr im Host- System schreiben oder verändern:

docker run -it --rm -v /:/ host alpine touch / host / abc . txt

/ host /abc . txt : Permissio n denied

Einschränkungen Die Docker-Dokumentation bezeichnet User Namespaces als fortgeschrittene Funk- tion und deutet damit wohl an, dass noch nicht alle Funktionen bis ins letzte Detail mit dieser Konfiguration getestet wurden. So werden zum Beispiel Treiber für externe Speichermedien erwähnt, die mit User Namespaces Probleme bereiten können. Außerdem funktioniert der Netzwerkmodus --network=host nicht. Weitere Konfigurationsmöglichkeiten für User Namespaces finden Sie hier: https://docs.docker.com/engine/security/userns-remap

18.6 cgroups Control Groups, kurz cgroups, sind schon viele Jahre fester Bestandteil des Linux- Kernels. Sie ermöglichen es, den Ressourcenverbrauch von Prozessen einzuschrän- ken. Der Sicherheitsaspekt besteht dabei darin, einen möglichen Denial-of-Service- Angriff zu unterbinden: Da ein Container standardmäßig vollen Zugriff auf den Speicher und die CPU(s) des Host-Computers hat, kann ein einziger Container den Computer auch zu 100 % auslasten.

Abbildung 18.3 Die CPU-Auslastung bei einem Stress-Test im Container mit cgroups- Einschränkung

Wie einfach cgroups mit Docker funktionieren, wollen wir durch ein kurzes Beispiel demonstrieren. Verwenden Sie dazu die zwei Linux-Programme stress und htop, und installieren Sie sie in einem Docker-Image:

  1. Datei : security / cgroups / Dockerfi l e

FROM debian : bookworm RUN apt -get update && apt - get install -y \ stress \ htop \ && rm -rf / var / lib / apt /lists / * CMD [ " stress " ]

Mit dem Programm stress können Sie sehr einfach Last auf Ihrem System erzeugen, egal, ob für CPU, I/O oder Speicher. Erzeugen Sie das Image, und starten Sie es mit dem Parameter für die CPU-Last:

docker build -t docbuc / stress . docker run --rm docbuc / stress stress -t 10 s --cpu 8


18 Sicherheit

Der Stress-Test dauert 10 Sekunden und belastet alle 8 CPUs in unserem Testgerät zu 100 %. Öffnen Sie ein zweites Konsolenfenster, und starten Sie das Programm htop, das die Auslastung Ihres Computers anzeigt:

docker run -it --rm docbuc / stress htop

Da htop auch in einem Container läuft, wird nur ein Prozess angezeigt, es wird aber korrekt die CPU-Auslastung von allen CPUs dargestellt. Starten Sie nun den Stress-Container mit der cgroups-Einschränkung auf 2,5 CPUs (--cpus=2.5), und Sie werden sehen, dass die Auslastung auf allen CPUs etwa auf ein Drittel ansteigt (siehe Abbildung 18.3).

macOS, Windows und Cloud Wie in Abschnitt 6.7, »Docker-Interna«, beschrieben, können Sie unter Windows und macOS außerdem die Gesamtleistung der Docker Engine limitieren. Wenn Sie Ihre Container in der Cloud ausführen, ist der Server üblicherweise virtua- lisiert. Damit können Sie die Ressourcen dynamisch anpassen (siehe Abschnitt 19.2, »Docker Swarm in der Hetzner Cloud«, und Kapitel 20, »Kubernetes«).

18.7 Secure Computing Mode Eine weitere Linux-Kernel-Funktion zur Einschränkung von Prozessen ist der Secure Computing Mode (kurz seccomp). Diese Technik kann die Ausführung von ausgewähl- ten Systemaufrufen im Kernel verhindern. Wahlloses Blockieren führt aber natürlich nicht zum Ziel: Bevor Sie einen der vielen Aufrufe blockieren, müssen Sie seine genaue Aufgabe verstehen. Jeder Docker-Container wird mit einer Standardliste an seccomp-Einstellungen ge- startet. Dadurch werden etwa 44 von über 300 möglichen Systemaufrufen blockiert. Die Standardliste für Container finden Sie auf GitHub: https://github.com/moby/moby/blob/master/profiles/seccomp/default.json Mit dem Parameter --security-opt seccomp=my_profile.json können Sie beim docker run-Aufruf Ihre eigene seccomp-Liste übergeben. Das Erstellen und das damit verbun- dene Debugging einer solchen Liste können aber sehr zeit- und nervenraubend sein, wie Jessie Frazelle in ihrem Blog dokumentiert hat: https://blog.jessfraz.com/post/how-to-use-new-docker-seccomp-profiles Ohne tiefgreifendes Kernel-Know-how können Sie sich an diesem Punkt nur auf die Expertise der Docker-Entwicklerinnen und -Entwickler verlassen.

18.8 AppArmor-Sicherheitsprofile AppArmor ist eine weitere Sicherheitsfunktion des Linux-Kernels, die sich zur Ein- schränkung oder auch nur zum Aufzeichnen von Aktionen eines Prozesses eignet. Gängige Aktionen sind Datei- und Netzwerkzugriffe.

AppArmor-Alternative SELinux Leider steht AppArmor nur unter wenigen Linux-Distributionen zur Verfügung, insbe- sondere unter Ubuntu und (open)SUSE. Linux-Distributionen aus dem Red-Hat-Umfeld, insbesondere also RHEL, Fedora, Oracle Linux und Co., vertrauen dagegen mit SELinux auf eine andere Sicherheitstech- nik. Hintergrundinformationen zum Zusammenspiel von SELinux und Docker finden Sie hier: https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux_atomic_ host/7/html/container_security_guide/docker_selinux_security_policy

AppArmor-Profil für Docker Zwar sind Konfigurationsdateien für AppArmor nicht ganz so komplex wie die zuvor erwähnten seccomp-Profile, aber die Erstellung eines vollständigen AppArmor-Profils ist gewiss auch kein Kinderspiel. AppArmor-Einstellungen gelten bei Docker für die laufenden Container, nicht für die Docker Engine. Unter Ubuntu wird für jeden Container beim Start dynamisch ein Standardprofil erzeugt, das im Wesentlichen das Schreiben unter /proc und /sys sowie die Verwendung von mount unterbindet. Hier folgt ein Auszug aus diesem Profil:

  1. docker - default apparmor - policy ( Auszug )

deny mount , deny /sys /[^ f ] * / ** wklx , deny /sys / f [^ s ] * / ** wklx , deny /sys / fs /[^ c ] * / ** wklx , deny /sys / fs / c [^ g] * / ** wklx , deny /sys / fs / cg [^ r ] * / ** wklx , deny /sys / firmware / ** rwklx , deny /sys / kernel /security / ** rwklx ,

Mehr zur Syntax von AppArmor-Profilen finden Sie im AppArmor-Wiki: https://gitlab.com/apparmor/apparmor/wikis/QuickProfileLanguage


18 Sicherheit

Eigene AppArmor-Regeln Abschließend möchten wir Ihnen anhand eines kurzen Beispiels die Verwendung eines eigenen AppArmor-Profils demonstrieren. Das Profil soll alle Schreibzugrif- fe unterhalb des Verzeichnisses /usr unterbinden und protokollieren. Alle anderen Schreibzugriffe im Container sollen ebenfalls protokolliert werden. Legen Sie eine Datei mit folgendem Inhalt an:

  1. Datei security / apparmor / ro - usr

profile ro - usr flags =( attach_disconne ct ed , mediate_d e l e te d ) { file , audit deny /usr / ** w , audit / ** w , }

Das Profil mit dem Namen ro-usr enthält nur wenige Zeilen. Die flags-Anweisung muss für Container so gesetzt werden. Anschließend werden die Regeln für die Pfade /usr/** und /** festgelegt. Erzeugen Sie das Profil mit diesem Kommando:

sudo apparmor _p a r s er -r -W ro - usr

Starten Sie nun einen Container mit dem Profil, und versuchen Sie, im Container eine Datei unter /usr mit dem Kommando touch zu erstellen:

docker run --security - opt " apparmor = ro - usr " -it alpine

touch /123 ( OK )

touch / usr /123 touch : / usr /123: Permissi o n denied

Während das Erzeugen der Datei unter dem Wurzelverzeichnis funktioniert, scheitert der zweite Aufruf mit der Fehlermeldung Permission denied. Sie finden die Protokolle in der Ausgabe von dmesg auf dem Host (hier etwas gekürzt):

apparmor =" AUDIT " operation =" open " profile =" ro - usr " name ="/ root /. ash_hist o ry " pid =3117 comm =" sh " requeste d _ m as k =" ac " fsuid =0 ouid =0 apparmor =" AUDIT " operation =" file_per m " profile =" ro - usr " name ="/ root /. ash_hist o ry " pid =3117 comm =" sh " requeste d _ m as k =" w" fsuid =0 ouid =0 apparmor =" DENIED " operation =" mknod " profile =" ro - usr " name ="/ usr /123" pid =3278 comm =" touch " requeste d_ m a s k =" c " denied_m a s k =" c " fsuid =0 ouid =0

Beachten Sie aber, dass Sie mit diesem Minimalprofil die sinnvollen Vorgaben des Standard-Docker-Profils verlieren!



Anhang

Siehe auch



Dokumentation

Projekt