Blog

Kubernetes und OpenShift Security 1 – Attack Surface

Kubernetes ist ein komplexes Gebilde aus vielen beweglichen Teilen. es ist hinter Linux das aktivste Projekt auf Github. Das Ökosystem mit 3rd Party Produkten, Plugins, Erweiterungen, Anbietern ist gewaltig. Hinzu kommt, dass selbst die Core features ständigen Änderungen unterworfen sind. Das sieht man allein an den API Versionen und Gruppen wie v1alpha1, v2beta3 usw. Leider erwächst aus dieser Komplexität eine gewisse Gefahr was das Thema Security angeht. Man ist froh, dass der Cluster aufgesetzt ist und funktioniert und die Entwickler schon erste Pods deployen und arbeiten können. Doch aus meiner Sicht ist das ein Problem. Denn ist der Cluster einmal aufgesetzt und im Betrieb, sind gewisse Änderungen nicht mehr oder sehr aufwändig zu bewerkstelligen. Komplexität ist kein Grund oder Entschuldigung die Security zu vernachlässigen. Und ich kann versichern, dass das Thema Security an sich ein komplexes Thema innerhalb des Kubernetes (und auch OpenShift) Universums ist. Von daher möchte ich eine Security Artikel Reihe starten die die verschiedenen Angriffs Vektoren und Security Maßnahmen beleuchtet.

Meine Empfehlung für das Thema Security ist es im Projekt a) zu verstehen was der Kubernetes Attack Surface ist (also die verschiedenen Angriffs Punkte) und b) mit den Low-Hanging-Fruits anzufangen, also die Maßnahmen, die mit relativ wenig Aufwand zu bewerkstelligen sind aber schon ein großes Maß an Sicherheit bringen.

Low-Hanging-Fruits in Kubernetes Security

Der Attack Surface

Der Attack Surface ist die gesamte Oberfläche eines Systems welches Angriffspunkte für einen Hacker bietet. Die Oberste Maxime bei Security ist es diese Oberfläche so stark wie möglich zu minimieren. Dazu sollte man natürlich verstehen welches diese Angriffspunkte sind. Wir werden im Laufe der Artikelserie auch sehen wie man diese Punkte angreift und sich Zugang zum Cluster verschafft. Selbstverständlich nur zu Lernzwecken.

Attack Surface Kubernetes / OpenShift

(1) Master Nodes

Der Kubernetes Master ist verantwortlich für die Aufrechterhaltung des gewünschten Zustands für das Cluster. Wenn man z.B. mit Kubernetes über das kubectl-Befehlszeilenkommando interagiert, dann kommuniziert man mit dem Master. Master bezieht sich hierbei auf eine Sammlung von einigen Prozessen, die gemeinsam den Clusterzustand verwalten. Typischerweise laufen diese Prozesse auf einen einzigen Knoten, sodass man zu diesem Knoten (Node) auch Master sagt. Aus Gründen der Hochverfügbarkeit und Redundanz kann es mehrere dieser Master geben.
Alle Master-Nodes beherbergen folgende Komponenten, die gemeinsam die sogenannte Kubernetes Control Plane bilden:

  • kube-apiserver
  • kube-scheduler
  • kube-controller-manager-manager
  • und möglicherweise ein Cloud-Controller-Manager

Ein Angreifer kann also eines der Masternodes direkt angreifen und sich Zugang verschaffen. Damit kommt er an alle Control Plane Komponenten. Da es sich bei den Master Nodes um normale bare metal Maschinen oder VMs handelt ist es wichtig hier ein Server Hardening zu betreiben. Unnötig offene Ports schliessen, ssh mit Zertifikats Authentifizierung, nur bekannte IPs per Firewall, etc.

(2) etcd

etcd ist ein verteilter, zuverlässiger Key-Value-Speicher für
die kritischsten Daten eines verteilten Systems mit Fokus auf:

  • Einfach: Gut definierte, benutzerfreundliche API (gRPC)
  • Sicher: Automatisches TLS mit optionalem Client Zertifikat
    Authentifizierung
  • Schnell: Benchmarking von 10.000 Schreibvorgängen/Sekunde
  • Zuverlässig: Verteilt mit Raft Konsens Protokoll

etcd speichert den gesamten Zustand eines Clusters. Der Verlust des Konsens (also der Zustand wo etcd nicht mehr zu einer Entscheidung kommt, was eigentlich der Zustand des Clusters ist) führt zu sehr viel Aufwand bis hin zur Nicht-Operabilität des Clusters. Daten aus einem Secret oder Config Map werden z.B. hier gespeichert, per Default sogar unverschlüsselt (ja, richtig gelesen, Secret Daten sind per Default nicht verschlüsselt in etcd). Ein Angreifer kann hier also Daten auslesen und den Zustand des Clusters beliebig ändern. Etcd wird über eine REST Api angesprochen. Auch hier ist es wichtig die Keys regelmäßig zu rotieren und eine Client Zertifikats Authentifizierung einzuführen. Secrets sind standarmäßig nicht verschlüsselt in etcd gespeichert. Hier sollte man unbedingt die symmetrische Verschlüsselung einführen (Securing data at rest).

(3) Kube API Server

Der Kubernetes API-Server validiert und konfiguriert Daten für die API-Objekte: Pods, Services, Replicationcontroller und andere.
Der API-Server bedient REST-Operationen und stellt das Frontend für den gemeinsamen Zustand des Clusters zur Verfügung, durch die alle anderen Komponenten interagieren.
Es gibt eine lange Liste von kube-apiserver Optionen, die beim Starten des Dienstes mitgegeben werden können. Viele dieser Optionen sind der Schlüssel zur Sicherung eines erfolgreichen Kubernetes-Cluster. Ein Zugriff auf den API Server ermöglicht es somit dem Angreifer den kompletten Cluster lahmzulegen. Normalerweise ist das kubectl Kommandozeilen Programm die häufigste Art mit dem API Server zu kommunizieren. Viele 3rd Party Dienste und Komponenten nutzen aber die REST Api, um mit dem Server zu kommunizieren. Auf jeden Fall sollte also eine TLS Verschlüsslung und TLS Client Authentifizierung erfolgen.

(4) Control Plane

Diese Kontrollebene weiss über alle Kubernetes Objekte im System Bescheid und führt einen kontinuierlichem Event-Loop zur Verwaltung dieser Objekte aus. Es reagiert auf Veränderungen im Cluster und arbeitet ständig daran den Ist-Zustand dem gewünschten Soll-Zustand anzupassen. Wenn man z.B. ein neues Deployment ausführen oder die Replica Anzahl der pods erhöhen möchte, dann ist das eine gewünschte Änderung die man dem System erstmal nur mitteilt. Eine Kette an Events wird dadurch aufgelöst und bestimmte Prozesse (Controller Manager) reagieren auf diese Events. Der Scheduler, welches auch Teil der Control Plane ist, sorgt dafür, dass Pods auf Nodes verteilt werden. Hierbei berücksichtigt der Prozess eine Menge an Parameter.

Angreifer können durch Inter Process Communication (IPC) Mechanismen den Datenverkehr zwischen den Kubernetes Control Plane Komponenten anzapfen, um z.B. Secrets oder andere Daten zu stehlen. Es ist wichtig diese Kommunikation durch TLS abzusichern und darüber hinaus die Keys und Zertifikate für die TLS Verschlüsselung regelmäßig zu rotieren.

Darüber hinaus können Angreifer die sich der Masternodes bemächtigen Original Komponenten durch „veränderte“ Komponenten ersetzen. Dadurch fallen Angriffe nicht mal auf. Es ist also wichtig, regelmäßige Patches und Upgrades einzuspielen und Passwörter zu rotieren.

(5) Kubelet API

Ein Kubelet ist ein Agent, der auf jedem Knoten des Clusters ausgeführt wird. Es stellt sicher, dass die Container in Pods ausgeführt werden. Das Kubelet stellt hierfür eine API bereit und kommuniziert seinerseits direkt mit der Container Runtime, z.B. Docker. Über die API nimmt es sogegannte PodSpecs entgegen und stellt sicher, dass die dort definierten Container zur Ausführung gebracht werden. Das Kubelet managed keine Container die nicht über Kubernetes erstellt wurden. Man kann sich vorstellen, dass über den direkten Zugriff auf die Kubelet Api beliebige Container und Kommandos innerhalb von Containern gestartet werden können. Z.B:

curl -k -XPOST "https://k8s-node-1:10250/run/kube-system/node-exporter-iuwg7/node-exporter" -d "cmd=ls -la /"
total 12
drwxr-xr-x   13 root     root           148 Aug 26 11:31 .
drwxr-xr-x   13 root     root           148 Aug 26 11:31 ..
-rwxr-xr-x    1 root     root             0 Aug 26 11:31 .dockerenv
drwxr-xr-x    2 root     root          8192 May  5 22:22 bin
drwxr-xr-x    5 root     root           380 Aug 26 11:31 dev
drwxr-xr-x    3 root     root           135 Aug 26 11:31 etc
drwxr-xr-x    2 nobody   nogroup          6 Mar 18 16:38 home
drwxr-xr-x    2 root     root             6 Apr 23 11:17 lib
dr-xr-xr-x  353 root     root             0 Aug 26 07:14 proc
drwxr-xr-x    2 root     root             6 Mar 18 16:38 root
dr-xr-xr-x   13 root     root             0 Aug 26 15:12 sys
drwxrwxrwt    2 root     root             6 Mar 18 16:38 tmp
drwxr-xr-x    4 root     root            31 Apr 23 11:17 usr
drwxr-xr-x    5 root     root            41 Aug 26 11:31 var

Das Kubelet ist eines der wichtigsten Komponenten dessen Api nur im internen, privaten Netz erreichbar ist. Es sollte auf jeden fall per TLS geschützt sein. Das Autoscaling von Kubernetes Nodes war in der Vergangenheit recht schwierig, da man ein TLS Key für jeden Node benötigt. Oft hat man diese Keys in das Vm Image gepackt was eine schlechte Idee ist. Durch das Kubelet TLS Bootstrapping wird während dem Bootvorgang ein CSR erstellt, welches dann dynamsich für neue Nodes ausgestellt wird.

(6) Container Runtime

Die Container-Runtime ist die Software, die für den Betrieb von Containern verantwortlich ist. Kubernetes unterstützt mehrere Laufzeiten: Docker, rkt, runc und jede OCI (Open Container Initiative) kompatible Implementierung.
Um also die Runtime zu sichern muss man z.B. Docker relevante Massnahmen ergreifen. Die Container Runtime hat ein eigenes Security Level, welches unabhängig vom Cluster ist. Bevor Container Images zur Ausführung gebracht werden, sollte das Image auf Schwachstellen gescanned werden. Hierzu gibt es eine Reihe von Anbietern und Tools (wie z.B. OWASP). Man kann Kubernetes so konfigurieren, dass das Pullen von Images nur von sicheren und vertrauenswürdigen Registries erlaubt ist. ein Angriffsvektor ist z.B. dass ein Angreifer ein Image welches schon geladen wurde und lokal auf einem Node liegt kompromittiert. Von daher sollte sichergestellt werden, dass Images „immer“ aus dem Repository geladen werden (Stichwort: imagePullPolicy: Always).

(7) Applikationen

Anwendungen und Container Workloads verändern sich je mehr Unternehmen anfangen ihre monolithische software in Microservices zu überführen. Elastische Umgebungen wie in der Cloud können Anwendungen dynamisch Kapazität zuweisen oder wieder wegnehmen. Ausfälle werden in einer Umgebung wie Kubernetes aufgefangen, in dem der Container auf einem anderen Node wieder gestartet wird. D.h. die Art und Weise wie diese Applikationen geschrieben sind und wie sie in Docker Containern gepackt werden stellt ein wesentliches Aspekt der Security dar. Malware in Applikationen sind so etwas wie das trojanische Pferd mit dem sich ein Angreifer Zugang zum System verschaffen kann. Um das Cluster zu sichern, muss gewährleistet sein, dass Applikationen genügend von einander isoliert sind. Sie sollten nicht unter root laufen. Ferner muss die Container Runtime so konfiguriert sein, dass eine Eskalation der Rechtestufen innerhalb der Anwendungscontainer verhindert wird. Ports, die von dem Applikations Container geöffnet werden sollten limitiert sein. Daten, die die Anwendung schreibt sollten gescanned werden auf Viren und Malware.

(8) Container zu Host Ausbruch

Ein Ausbruch aus dem Applikations Container zu dem Host ist abhängig von einigen Faktoren mehr oder weniger schwierig.

  • Kernel Vulnerabilities: Container die auf einem Host laufen teilen sich den Kernel des Hosts. D.h. wenn im Kernel ein Bug ist, welches ausgenutzt werden kann, so kann auch innerhalb des Containers dieser Schwachpunkt genutzt werden.
  • Wenn ein Container mit dem –privileged flag läuft, ist ein Ausbruch aus dem Container möglich.
  • Wenn ein Container ein Filesystem des Hosts als Laufwerk mounted, dann kann es unter Umständen möglich sein durch Filesystem Berechtigungen Zugang zum Host zu erhalten.
  • Das mounten des docker daemon Netzwerk Sockets in den Container macht es trivial aus dem Container auszubrechen

Fazit

In diesem Artikel haben wir einen Überblick über den gesamten Attack Surface von Kubernetes (und OpenShift, welches ja auf Kubernetes aufsetzt) gewonnen. In den nächsten Artikeln gehen wir auf konkrete Maßnahmen ein und werden auch einige Hacking Beispiele sehen.

Masiar IghaniKubernetes und OpenShift Security 1 – Attack Surface