
Docker-Container sind die beliebteste Containerisierungstechnologie. Ursprünglich wurde es hauptsächlich für Entwicklungs- und Testumgebungen verwendet und im Laufe der Zeit auf Produktion umgestellt. Docker-Container begannen sich in der Produktionsumgebung zu vermehren, wie Pilze nach dem Regen. Allerdings haben nur wenige, die diese Technologie verwenden, darüber nachgedacht, wie Docker-Container sicher veröffentlicht werden können.
Basierend auf
OWASP haben wir eine Liste von Regeln erstellt, deren Implementierung Ihre Umgebung erheblich schützt und auf Docker-Containern basiert.
Regel 0
Der Hostcomputer und Docker müssen alle aktuellen Updates enthalten.
Zum Schutz vor bekannten Schwachstellen, die dazu führen, dass die Containerumgebung auf das Hostsystem übertragen wird, was normalerweise zu einer Eskalation der Berechtigungen auf dem Hostsystem führt, ist die Installation aller Patches für das Host-Betriebssystem, die Docker Engine und den Docker-Computer äußerst wichtig.
Darüber hinaus verwenden Container (im Gegensatz zu virtuellen Maschinen) den Kernel in Verbindung mit dem Host, sodass der im Container ausgeführte Kernel-Exploit direkt im Host-Kernel ausgeführt wird. Beispielsweise führt ein Exploit zur Eskalation von Kernel-Berechtigungen (z. B. Dirty COW), der in einem gut isolierten Container ausgeführt wird, zum Root-Zugriff auf den Host.
Regel 1
Geben Sie keinen Zugriff auf den Socket des Docker-Daemons
Der Docker-Dienst (Daemon) verwendet den UNIX-Socket /var/run/docker.sock für eingehende API-Verbindungen.
Der Eigentümer dieser Ressource muss der Root-Benutzer sein. Und kein anderer Weg. Das Ändern der Zugriffsrechte auf diesen Socket entspricht im Wesentlichen dem Gewähren des Root-Zugriffs auf das Hostsystem.
Außerdem sollten Sie den Socket /var/run/docker.sock nicht mit Containern fummeln, wo Sie darauf verzichten können, da in diesem Fall eine Beeinträchtigung des Dienstes im Container zu einer vollständigen Kontrolle über das Hostsystem führt. Wenn Sie Container haben, die so etwas verwenden:
-v /var/run/docker.sock://var/run/docker.sock
oder für Docker-Compose:
volumes: - "/var/run/docker.sock:/var/run/docker.sock"
dringende Notwendigkeit, dies zu ändern.
Und das letzte - hören Sie
niemals den Docker TCP-Socket ohne die absolute Gewissheit, dass Sie ihn benötigen, insbesondere ohne die Verwendung zusätzlicher Schutzmethoden (zumindest Autorisierung). Standardmäßig öffnet der Docker-TCP-Socket den Port an der externen Schnittstelle 0.0.0.0:2375 (2376 bei HTTPs) und ermöglicht Ihnen die vollständige Steuerung der Container und damit des potenziellen Hostsystems.
Regel 2
Konfigurieren Sie einen nicht privilegierten Benutzer im Container
Das Konfigurieren eines Containers für die Verwendung eines nicht privilegierten Benutzers ist der beste Weg, um einen Angriff auf die Eskalation von Berechtigungen zu vermeiden. Dies kann auf verschiedene Arten erfolgen:
1. Verwenden Sie die Option "-u" des Befehls "Docker ausführen":
docker run -u 4000 alpine
2. Während der Image-Erstellung:
FROM alpine RUN groupadd -r myuser && useradd -r -g myuser myuser < root-, , > USER myuser
3. Aktivieren Sie die Unterstützung für "Benutzernamensraum" (Benutzerumgebung) im Docker-Daemon:
--userns-remap=default
Lesen Sie mehr dazu in der
offiziellen Dokumentation .
In Kubernetes wird letzteres im
Sicherheitskontext über die Option runAsNonRoot konfiguriert:
kind: ... apiVersion: ... metadata: name: ... spec: ... containers: - name: ... image: .... securityContext: ... runAsNonRoot: true ...
Regel 3
Begrenzen Sie die Containerfunktionen
Unter Linux gibt es ab Kernel 2.2 eine Möglichkeit, die Funktionen privilegierter Prozesse zu steuern, die als
Linux-Kernel-Funktionen bezeichnet werden (Details siehe Link).
Docker verwendet standardmäßig einen vordefinierten Satz dieser Kernelfunktionen. Und Sie können dieses Set mit den folgenden Befehlen ändern:
--cap-drop — --cap-add —
Die beste Sicherheitseinstellung besteht darin, zuerst alle Funktionen zu deaktivieren (--cap-drop all) und dann nur die erforderlichen zu verbinden. Zum Beispiel so:
docker run --cap-drop all --cap-add CHOWN alpine
Und das Wichtigste (!): Vermeiden Sie es, Container mit der Flagge –privileged auszuführen !!!
In Kubernetes wird die Einschränkung der Linux-Kernel-Funktionen im Sicherheitskontext über die Option "Funktionen" konfiguriert:
kind: ... apiVersion: ... metadata: name: ... spec: ... containers: - name: ... image: .... securityContext: ... capabilities: drop: - all add: - CHOWN ...
Regel 4
Verwenden Sie das Flag "Keine neuen Berechtigungen"
Beim Starten eines Containers ist es hilfreich, das Flag --security-opt = no-new-privileges zu verwenden, um die Eskalation von Berechtigungen innerhalb des Containers zu verhindern.
In Kubernetes wird die Einschränkung der Linux-Kernelfunktionen im Sicherheitskontext über die Option allowPrivilegeEscalation konfiguriert:
kind: ... apiVersion: ... metadata: name: ... spec: ... containers: - name: ... image: .... securityContext: ... allowPrivilegeEscalation: false ...
Regel 5
Deaktivieren Sie die Kommunikation zwischen Containern
Standardmäßig ist die Kommunikation zwischen Containern in Docker aktiviert. Dies bedeutet, dass alle Container miteinander kommunizieren können (über das Docker0-Netzwerk). Diese Funktion kann deaktiviert werden, indem der Docker-Dienst mit dem Flag –icc = false ausgeführt wird.
Regel 6
Verwenden Sie Linux-Sicherheitsmodule (Linux-Sicherheitsmodul - seccomp, AppArmor, SELinux)
Standardmäßig verwendet Docker bereits Profile für Linux-Sicherheitsmodule.
Deaktivieren Sie daher
niemals Sicherheitsprofile! Das Maximum, das mit ihnen erreicht werden kann, besteht darin, die Regeln zu verschärfen.
Das Standardprofil für seccomp finden Sie
hier .
Docker verwendet AppArmor auch zum Schutz, und die Docker Engine selbst generiert beim Start des Containers ein Standardprofil für AppArmor. Mit anderen Worten, anstatt:
$ docker run --rm -it hello-world
startet:
$ docker run --rm -it --security-opt apparmor=docker-default hello-world
Die
Dokumentation enthält auch ein Beispiel für ein AppArmor-Profil für Nginx, das durchaus möglich (erforderlich!) Ist.
Regel 7
Begrenzen Sie die Containerressourcen
Diese Regel ist recht einfach: Um zu verhindern, dass Container beim nächsten DoS / DDoS-Angriff alle Serverressourcen verschlingen, können wir für jeden Container einzeln Speicherbeschränkungen festlegen. Sie können Folgendes begrenzen: Speicherplatz, CPU, Anzahl der Neustarts des Containers.
Also lass uns in Ordnung gehen.
Die ErinnerungDie Option -m oder --memoryDie maximale Speichermenge, die ein Container verwenden kann. Der Mindestwert beträgt 4 m (4 Megabyte).
Option - SpeicherwechselOption zum Konfigurieren von Swap (Swap-Datei). Listig konfiguriert:
- Wenn --memory-swap> 0 ist, muss auch das Flag –memory gesetzt werden. In diesem Fall zeigt Memory-Swap an, wie viel Gesamtspeicher dem Container zusammen mit Swap zur Verfügung steht.
- Ein einfacheres Beispiel. Wenn --memory = "300m" und --memory-swap = "1 g", kann der Container 300 MB Speicher und 700 MB Swap (1 g - 300 m) verwenden.
- Wenn --memory-swap = 0 ist, wird die Einstellung ignoriert.
- Wenn --memory-swap auf den gleichen Wert wie --memory gesetzt ist, hat der Container keinen Swap.
- Wenn --memory-swap nicht angegeben ist, aber --memory angegeben ist, entspricht die Anzahl der Auslagerungen dem doppelten angegebenen Speicherplatz. Wenn beispielsweise --memory = "300m" und --memory-swap nicht festgelegt ist, verwendet der Container 300 MB Speicher und 600 MB Swap.
- Wenn --memory-swap = -1 ist, verwendet der Container den gesamten auf dem Hostsystem möglichen Swap.
Hinweis für die Hostess: Das im Container gestartete kostenlose Dienstprogramm zeigt nicht den tatsächlichen Wert des verfügbaren Swaps für den Container an, sondern die Anzahl der Host-Swaps.
Option --oom-kill-disableErmöglicht das Aktivieren oder Deaktivieren des OOM-Killers (Out of Memory).
Achtung! Sie können OOM Killer nur mit der angegebenen Option --memory deaktivieren. Andernfalls kann es vorkommen, dass der Kernel bei zu wenig Speicher im Container die Prozesse des Hostsystems beendet.
Andere Konfigurationsoptionen für die Speicherverwaltung, wie z. B. --memory-swappiness, --memory-reservation und --kernel-memory, dienen eher zur Optimierung der Leistung des Containers.
CPUOption --cpusDie Option legt fest, wie viele verfügbare Prozessorressourcen der Container verwenden kann. Wenn wir beispielsweise einen Host mit zwei CPUs haben und --cpus = "1.5" setzen, verwendet der Container garantiert eineinhalb Prozessoren.
Option --cpuset-cpusKonfiguriert die Verwendung bestimmter Kerne oder CPUs. Der Wert kann mit einem Bindestrich oder einem Komma angegeben werden. Im ersten Fall wird der Bereich der zulässigen Kerne angegeben, in den zweiten spezifischen Kernen.
Anzahl der Neustarts des Containers --restart=on-failure:<number_of_restarts>
Diese Einstellung legt fest, wie oft Docker versucht, den Container neu zu starten, wenn er unerwartet abstürzt. Der Zähler wird zurückgesetzt, wenn sich der Status des Containers in "Laufen" geändert hat.
Es wird empfohlen, eine kleine positive Zahl festzulegen, z. B. 5, um endlose Neustarts eines nicht funktionierenden Dienstes zu vermeiden.
Regel 8
Verwenden Sie schreibgeschützte Dateisysteme und Volumes
Wenn der Container irgendwo nichts schreiben soll, müssen Sie das schreibgeschützte Dateisystem so oft wie möglich verwenden. Dies wird das Leben eines potenziellen Eindringlings erheblich verkomplizieren.
Ein Beispiel für das Starten eines Containers mit einem schreibgeschützten Dateisystem:
docker run --read-only alpine
Ein Beispiel für das Anschließen des Volumes im schreibgeschützten Modus:
docker run -v volume-name:/path/in/container:ro alpine
Regel 9
Verwenden Sie Tools zur Analyse der Containersicherheit
Tools müssen verwendet werden, um Container mit bekannten Schwachstellen zu erkennen. Es gibt noch nicht sehr viele von ihnen, aber sie sind:
• Kostenlos:
• Kommerziell:
Und für Kubernetes gibt es Tools zum Erkennen von Konfigurationsfehlern: