Kubernetes-Security, Teil 3: Im Spannungsfeld von Komplexität und Sicherheit

Teil 3 der Serie behandelt die besonderen Ansprüche an die Sicherheit von Kubernetes, die sich aus der Komplexität von Rechenzentren ergeben.

In Pocket speichern vorlesen Druckansicht 3 Kommentare lesen
Kubernetes-Security, Teil 3: Im Spannungsfeld von Komplexität und Sicherheit

(Bild: Illus_man/Shutterstock.com)

Lesezeit: 16 Min.
Von
  • Thomas Fricke
Inhaltsverzeichnis

Kubernetes hat die Komplexität eines Rechenzentrums, allerdings sind Sicherheit und Komplexität widersprüchliche Anforderungen. In dem Zusammenhang zitieren Entwickler gerne den Sicherheitsexperten Bruce Schneier mit "Komplexität ist der schlimmste Feind der Sicherheit". In dem Interview mit der Computerworld Hong Kong 2012 sagte er allerdings auch, dass "wir Komplexität lieben".

Ähnlich sehen das Jeremy Ramsden und Paata Kervalishvili in ihrem Buch "Complexity and Security": Darin betrachten die beiden Autoren Komplexität als eine Konsequenz der Zivilisation.

Kubernetes-Security - die Serie

In der Sicherheitsarchitektur von Kubernetes sind zahlreiche Elemente miteinander verwoben, die die Beiträge dieser Artikelstrecke jeweils vorstellen:

Diese Diskussionen lassen sich technisch nicht entscheiden, sondern haben eine philosophische, wenn nicht sogar religiöse Dimension. In dem Spannungsfeld gilt es, mit minimalen Rechten, jedoch ohne Abstriche im Funktionsumfang Applikationen in Kubernetes zu gestalten.

Aus dem Grunde soll hier die Definition des Prinzips des geringsten Privilegs (Principle of Least Privilege) aus dem Gestaltungsprinzip von Jerome H. Saltzer zugrunde liegen: "Jedes Programm und jeder privilegierte Benutzer des Systems sollte mit so wenig Privilegien wie möglich arbeiten, um Aufgaben zu erledigen."

Der Ansatz erinnert an eine Definition bei Antoine de Saint-Exupéry: "Perfektion ist nicht dann erreicht, wenn es nichts mehr gibt, was hinzugefügt werden muss, sondern wenn es nichts gibt, was noch entfernt werden kann." [1]

Nach diesen grundlegenden Gedanken geht es an den praktischen Teil, um anhand von Beispielen Architekturen und Service-Accounts zu definieren.

Abbildung 1 zeigt eine Installation für eine Elasticsearch-Anwendung und deren integrierten Lifecycle.

Integrierter Lifecyle einer typischen Datenbank-Applikation mit Init-Containern (Abb. 1)

Elasticsearch ist in Java geschrieben und benötigt zu keiner Zeit Root-Rechte.

Das Beispiel zeigt, wie man Elasticsearch durch einen Satz Pods mit eindeutigen, dauerhaften Identitäten und stabilem Hostnamen (StatefulSet) mit drei Init-Containern installiert, die privilegiert sind und mit Root-Rechten laufen. Dieses Beispiel ist typisch für viele Anwendungen, die unter Verletzung des Prinzips der geringsten Rechte im Internet kursieren und unnötige Privilegien verwenden, die Angreifer eskalieren können.

. . .
initContainers:
- name: fix-permissions
image: busybox
command: ["sh", "-c", "chown -R 1000:1000 /usr/share/elasticsearch/data"]
securityContext:
privileged: true
volumeMounts:
- name: data
mountPath: /usr/share/elasticsearch/data
- name: increase-vm-max-map
image: busybox
command: ["sysctl", "-w", "vm.max_map_count=262144"]
securityContext:
privileged: true
- name: increase-fd-ulimit
image: busybox
command: ["sh", "-c", "ulimit -n 65536"]
securityContext:
privileged: true

Der Init-Container mit dem Namen increase-vm-max-map ändert eine Hosteinstellung vm.max_map_count=262144. Eine Überprüfung mit einem Skript wie

kubectl get pods --all-namespaces -o go-template \
--template="{{range .items}}{{.metadata.namespace}}/{{.metadata.name}}:{{println}}{{range .spec.initContainers}} {{.image}}:{{.securityContext}}

{{end}}{{end}}"

würde die Einstellung in einem Cluster sofort sichtbar machen. Tatsächlich lassen sich alle sicherheitsrelevanten Einstellungen auf diese Weise überprüfen, der Autor schätzt die Anzahl solcher Überprüfungen jedoch im niedrigen dreistelligen Bereich. Deshalb dürften sich hier Tools anbieten, die im Augenblick in großer Anzahl entstehen, wie Neuvector, Octarine, Alcide, Aqua Security und Sysdig.

Erst beim genaueren Hinsehen (zum Beispiel in einem Audit-Log) ist zu erkennen, dass die Init-Container nur kleinere Änderungen vornehmen. Wenn Entwickler Einfachheit in der Praxis als Auditierbarkeit interpretieren, um in diesem Fall nicht jeden Container analysieren zu müssen, ist das offenbar der falsche Ansatz.