Skip to main content

Kubernetes is a complex structure with many moving parts. It is the most active project on Github after Linux. The ecosystem with 3rd party products, plugins, extensions, providers is huge. In addition, even the core features are subject to constant changes. You can see this just from the API versions and groups such as v1alpha1, v2beta3, etc. Unfortunately, this complexity creates a certain risk when it comes to security. You are happy that the cluster is set up and working and that the developers can already deploy the first pods and work. But from my point of view, this is a problem. Because once the cluster is set up and in operation, certain changes can no longer be made or are very difficult to make. Complexity is no reason or excuse to neglect security. And I can assure you that the topic of security in itself is a complex topic within the Kubernetes (and also OpenShift) universe. I would therefore like to start a security article series that highlights the various attack vectors and security measures.

My recommendation for the topic of security in the project is to a) understand what the Kubernetes attack surface is (i.e. the various attack points) and b) start with the low-hanging fruit, i.e. the measures that can be implemented with relatively little effort but already provide a high level of security.

Low-hanging fruit in Kubernetes security

The Attack Surface

The attack surface is the entire surface of a system that offers attack points for a hacker. The most important thing in security is to minimize this surface as much as possible. To do this, you should of course understand what these attack points are. In the course of the series of articles, we will also see how to attack these points and gain access to the cluster. Of course, this is for learning purposes only.

Attack Surface Kubernetes / OpenShift

(1) Master Nodes

The Kubernetes master is responsible for maintaining the desired state for the cluster. For example, when you interact with Kubernetes using the kubectl command line, you are communicating with the master. Master refers to a collection of a few processes that collectively manage the cluster state. Typically, these processes run on a single node, so this node is also called the master. For reasons of high availability and redundancy, there can be several of these masters.
All master nodes host the following components, which together form the so-called Kubernetes Control Plane:

  • kube-apiserver
  • kube-scheduler
  • kube-controller-manager-manager
  • and possibly a cloud controller manager

An attacker can therefore attack one of the master nodes directly and gain access. This gives him access to all control plane components. Since the master nodes are normal bare metal machines or VMs, it is important to carry out server hardening here. Close unnecessarily open ports, ssh with certificate authentication, only known IPs via firewall, etc.

(2) etc.

etcd is a distributed, reliable key-value store for
the most critical data of a distributed system with a focus on:

  • Simple: Well-defined, user-friendly API (gRPC)
  • Secure: Automatic TLS with optional client certificate
    authentication
  • Fast: Benchmarking 10,000 writes/second
  • Reliable: Distributed with Raft consensus protocol

etcd stores the entire state of a cluster. The loss of consensus (i.e. the state where etcd can no longer decide what the actual state of the cluster is) leads to a lot of work and can even make the cluster inoperable. Data from a secret or config map, for example, is stored here, even unencrypted by default (yes, you read that correctly, secret data is not encrypted in etcd by default). An attacker can therefore read data here and change the state of the cluster at will. Etcd is accessed via a REST API. Here, too, it is important to rotate the keys regularly and to introduce client certificate authentication. Secrets are not encrypted by default when stored in etcd. Symmetric encryption should definitely be introduced here (securing data at rest).

(3) Kube API Server

The Kubernetes API server validates and configures data for the API objects: pods, services, replication controllers, and others.
The API server serves REST operations and provides the frontend for the shared state of the cluster through which all other components interact.
There is a long list of kube-apiserver options that can be specified when starting the service. Many of these options are key to securing a successful Kubernetes cluster. Access to the API server thus allows the attacker to bring down the entire cluster. Usually, the kubectl command line program is the most common way to communicate with the API server. However, many 3rd party services and components use the REST API to communicate with the server. In any case, TLS encryption and TLS client authentication should be used.

(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 this article, we have gained an overview of the entire attack surface of Kubernetes (and OpenShift, which is based on Kubernetes). In the next articles, we will go into concrete measures and also see some hacking examples.