Security

Work in Progress

Ein Kubernetes Cluster ist aufgrund seiner Vielseitigkeit und der dort vorzufindenden Konzentration an Services ein interessantes Angriffsziel. Aus diesem Grund darf es hier keine Kompromisse in der Sicherheit geben. Kubernetes selbst verfügt zwar über einige Zero Trust Ansätze, allerdings ist das nur ein Schutz für die Managementebene in Kubernetes. Mit Role based Access Lists, Policies und Namespaces kann man zwar einen gewissen Schutz der Anwendungen untereinander schaffen, aber der ist nur innerhalb von Kubernetes wirksam und bietet letztlich nur die Funktionen von iptables.

Namespaces sind in Verbindung mit Policies eine sinnvolle Lösung, um eine Segmentierung zwischen den Anwendungen bis auf Pod Ebene herbeizuführen. Ingress/Egress sind quasi die iptables Filter Äquivalente zu INPUT und OUTPUT.

Kubernetes Architektur

Kubernetes implementiert im Grundsatz schon eine Zero Trust Architektur. Der Zugang zu dem Managemant API erfolgt über Client Zertifikate mit TLS. Dennoch gibt es einige Punkte, die beachtet werden müssen, damit die Kubernetes Installation sicher bleibt.

In einem ersten Schritt sollte man sich vertraut damit machen, welche Ports überhaupt auf einem Kubernetes Node sichtbar sind:

x1-kubic:~ # lsof -i -P -n | grep LISTEN | grep -v 127.0.0.1
sshd 1180 root 3u IPv4 21256 0t0 TCP *:22 (LISTEN)
sshd 1180 root 4u IPv6 21266 0t0 TCP *:22 (LISTEN)
salt-mast 1387 salt 20u IPv4 21850 0t0 TCP *:4505 (LISTEN)
salt-mast 1393 salt 37u IPv4 21466 0t0 TCP *:4506 (LISTEN)
kube-apis 2556 root 7u IPv6 43919 0t0 TCP *:6443 (LISTEN)
etcd-3.4. 2562 root 3u IPv4 43908 0t0 TCP 192.168.47.16:2380 (LISTEN)
etcd-3.4. 2562 root 6u IPv4 43913 0t0 TCP 192.168.47.16:2379 (LISTEN)
kubelet1. 2759 root 21u IPv6 45852 0t0 TCP *:10250 (LISTEN)
weave-npc 2969 root 12u IPv6 46324 0t0 TCP *:6781 (LISTEN)
kube-prox 3057 root 11u IPv4 86267 0t0 TCP *:31806 (LISTEN)
kube-prox 3057 root 14u IPv4 86268 0t0 TCP *:32718 (LISTEN)
kube-prox 3057 root 15u IPv6 47379 0t0 TCP *:10256 (LISTEN)
weaver 3298 root 17u IPv6 48398 0t0 TCP *:6783 (LISTEN)
weaver 3298 root 19u IPv6 49954 0t0 TCP *:6782 (LISTEN)
speaker 4225 root 6u IPv4 55049 0t0 TCP 192.168.47.16:7946 (LISTEN)
speaker 4225 root 10u IPv4 55055 0t0 TCP 192.168.47.16:7472 (LISTEN)

Services, die auf localhost lauschen, sind hier uninteressant. Mit Ausnahme vom sshd werden alle anderen Services von Kubernetes bereitgestellt.

  • Das gesamte Kubernetes Netz sollte in einem eigenen VLAN laufen. Die Kommunikation von und nach außen sollte über eine Firewall laufen.
  • Auf die hier sichtbaren Ports können grundsätzlich auch Pods zugreifen.
  • Der SSH Server sollte zumindest auf eine private/public Authentifizierung beschränkt werden.

In einem ersten Schritt sollte ein Pod generiert werden, der den lokalen Host auf offene Ports prüft. Vom Pod aus sollte kein Port erreichbar sein. Sinnvollerweise sollte dieser Scan im Rahmen des Monitorings permanent erfolgen. Ist ein Port auf dem Host vom Pod aus erreichbar, dann stimmt etwas nicht.

Beispiel

Einen schnellen Test kann man z.B. mit kubectl run --namespace=default access --rm -ti --image busybox /bin/sh machen. Der folgende Screendump spricht sicherlich für sich:

/ # ip route
default via 10.32.0.1 dev eth0
10.32.0.0/12 dev eth0 scope link src 10.32.0.16
/ # telnet 10.32.0.1 22
Connected to 10.32.0.1
SSH-2.0-OpenSSH_8.3
^]quit

Offensichtlich ist hier der sshd des Hosts sichtbar. Wenn jetzt noch Password- oder Challenge-Authentifizierung erlaubt ist, dann ist es fast schon passiert: Der Ausbruch von einem Pod auf den Host.

Kubernetes aus Sicht des Entwicklers

Kubernetes liefert zusammen mit Policy Modulen eine durchaus ernstzunehmende Security Architektur auch für Pods. Im Vergleich zu dem alten Perimeter Konzept, das auf festen IP-Netzen und Ports basiert, basieren die Kubernetes Policies letztlich auf Namespaces oder ggf. Pod-/Servicenamen. Die Pods haben ebenso wie im Perimeteransatz normalerweise keinen Einfluss auf die Policies. Der wesentliche Unterschied liegt im Deployment, dort können entsprechend dem "Infrastructure as Code" Ansatz die Policies im Deployment Prozess zumindest ausgewählt werden. Grundsätzlich stellen sich daher folgende Fragen:

  • Will der Entwickler Kubernetes Policies nutzen?
  • Passen die verfügbaren Policy Sets zur Anwendung?
  • Wie können Policies angepasst werden?
  • Benötigt der Pod erweiterte Privilegien?
  • Passt das verwendete Kubernetes Policy Framework zu der Anwendung?

Für den Kubernetes Betrieb kann es vorteilhafter sein, die Sicherheitsthemen komplett auf die Anwendung zu delegieren und lediglich Policies für Anwendungsklassen bereitzustellen und die Anwendungen über Namespaces zu trennen. Tatsächlich sollten Anwendungen in Kubernetes eine Zero Trust Architektur verwenden. Das Security Modell der Anwendungen ist dann völlig unabhängig von Kubernetes. Ein Zero Trust Architekurmodell auf der Anwendungsebene hat auch den Vorteil, dass die Anwendung und deren Services auch noch sicher bleibt, falls darunterliegende Security Konzepte versagen.

Kubernetes aus Sicht des Administrators

Für den Admin laufen auf der Kubernetes Instanz irgendwelche Pods, über die im Zweifelsfall nichts bekannt ist. Es werden Policy-Sets bereitgestellt, die nach den Spezifikationen der Anwendung erstellt wurden. So lange die Pods keinen Zugriff auf die Infrastruktur bekommen, ist für den Admin erst einmal alles ok. Kritisch wird es jedoch, wenn ein Pods Komponenten der Infrastruktur beschädigen können. Es lohnt sich daher, für administrative Funktionen eine getrennte Kubernetes-Instanz zu erstellen. Dort können Services wie z.B. eine Image Registry, Git und Monitoring laufen. Der Zugang von außen erfolgt auch hier über eine Firewall.

Die ganzen Kubernetes Config Files sollten mit Git verwaltet werden, damit hat man neben einer Versionierung auch die Möglichkeit, etwas zurückzurollen, wenn ein Fehler passiert ist. Es kann auch nicht schaden, die Commits zu signieren.

Außer den Administratoren sollte niemand einen SSH Zugang auf die Hosts haben. Auf das API sollten nur die Control-Plane Server Zugriff haben.

Anatomie eines sicheren Containers

Der Entwickler eines Images sollte immer davon ausgehen, dass sein Container völlig ungeschützt im Internet läuft, d.h. das Netzwerk lässt im Internet Zugriffe von 0.0.0.0/0 bzw. ::/0 auf alle Ports zu. Was bedeutet das für den Container?

  • Der Zugriff darf nur über verschlüsselte Verbindungen erfolgen.
  • Jeder Request muss authentifiziert werden. Dazu eignen sich z.B. X.509 Client Zertifikate sehr gut.
  • Jeder Request muss autorisiert werden. Da eine Authentifizierung bereits stattfindet muss nur noch überprüft werden, ob der Benutzer die angeforderte Operation auch ausführen darf.
  • Jeder Request muss validiert werden. Alle Eingabedaten sind zumindest auf syntaktische Korrektheit zu prüfen.
  • Erst jetzt darf im Erfolgsfall der vorangegangen Prüfungen mit der Verarbeitung der Payload begonnen werden.
  • Der Container speichert keine persistenten Daten lokal, diese werden ausschließlich in externen Storageprovidern, wie z.B. SQL, Nosql, S3, Ceph etc. gespeichert. Diese Daten sollten verschlüsselt gespeichert werden, als Private/Public Keys eignen sich auch dafür X.509 Zertifikate sehr gut.
  • Der Container authentifiziert sich selbst an anderen Services, auch hier sind X.509 Client Zertifikate sehr gut geeignet.
  • Im Rahmen der CI/CD Pipeline werden Patches täglich automatisiert getestet und installiert.
  • Secrets, die der Container nutzt, werden ausschließlich in Kubernetes Secrets gespeichert.

Je nach Anwendungsfall sind auch Protokolle, wie z.B. OpenID Connect für die Authentifizierung/Autorisierung gut geeignet. Wer eine All-In-One Lösung haben will, sollte sich Hashicorp Vault ansehen.

Patchen

Für einen sicheren Betrieb von Kubernetes ist tägliches Patchen ein Pflichtprogramm. Da ein Kubernetes Host immer nur ein absolutes Minimalsystem für sein sollte, ist die Angriffsfläche auch sehr klein und das Patchen hat normalerweise keine oder nur wenige Nebenwirkungen.

Policies

Für den Einstieg sollte unbedingt https://kubernetes.io/docs/concepts/security/ konsultiert werden. Grundsätzlich sollten Pods niemals als privileged laufen. Am besten sollte immer die Policy Restricted verwendet werden. Auf der Seite Namespaces gibt es Hinweise, wie man Namespaces erstellen und mit Network Policies verknüpfen sollte.

Netzdiagramm

Über eine (rendundante) Firewall wird zunächst geregelt, was in den Kubernetes Cluster rein oder raus darf.

 

 

Der (MetalLB) Load-Balancer bestimmt über BGP4, welche internen LB IP-Adressen die Firewall sieht. Mit dieser Architektur ist zumindest sichergestellt, dass keine unerwünschten Ports nach außen sichtbar sind.