Absichern der Konfiguration von Kubernetes-Cluster-Komponenten

In 10 Schritten digital – bitkom
Autor: Frank Maenz
  • Beitrag vom: 16.05.2019
  • Views: 1.070

Die Sicherheit muss ein integraler Bestandteil des Lebenszyklus in der Software-Entwicklung sein, der bei jedem Schritt des Prozesses berücksichtigt wird. Dies ist der zweite Teil der Artikelreihe „Absicherung von Kubernetes für native Cloud-Anwendungen“. Puja Abbassi, Developer Advocate & Product Owner bei Giant Swarm, beleuchtet darin die wichtigsten Sicherheitsaspekte einer Kubernetes-Plattform auf Cluster-Ebene.

Kubernetes ist ein komplexes System. Das folgende Diagramm  zeigt die vielen verschiedenen Bestandteile, aus denen ein Cluster besteht. Jede dieser Komponenten muss sorgfältig abgesichert sein, um die Gesamtintegrität des Clusters zu wahren.

Wir werden in diesem Artikel nicht jeden Sicherheitsaspekt auf Cluster-Ebene abdecken können. Trotzdem werden wir versuchen, die wichtigeren Punkte zu behandeln. Wie wir weiter unten sehen werden, kann die breite Öffentlichkeit auf Hilfestellungen zurückgreifen, was die Best-Practice-Sicherheit für Kubernetes-Cluster und das Tooling angeht, um die Einhaltung dieser Best-Practice-Methode zu messen.

Cluster-Installer

Wir sollten mit einer kurzen Bemerkung zu den vielen verschiedenen Tools beginnen, die zur Installation der Cluster-Komponenten verwendet werden können.

Einige der standardmäßigen Konfigurationsparameter für die Komponenten des Kubernetes-Clusters sind aus Sicherheitsperspektive suboptimal und müssen richtig gesetzt werden, um einen sicheren Cluster zu gewährleisten. Sollten Sie sich nicht für einen Kubernetes-Cluster entscheiden, bei dem der gesamte Cluster betrieben wird (wie etwa von Giant Swarm), so wird dieses Problem durch die vielen verschiedenen verfügbaren Cluster-Installationswerkzeuge noch verschärft, denn jedes dieser Tools verwendet eine ganz eigene Konfiguration. Obwohl die meisten Installer vernünftige Standardeinstellungen aufweisen, sollten wir niemals davon ausgehen, dass sie wirklich sicher sind, insbesondere wenn es sich um die Anforderungen eines Großunternehmens handelt. Stattdessen sollten wir uns vornehmen sicherzustellen, dass der von uns gewählte Installationsmechanismus so eingestellt ist, dass er den Cluster gemäß unseren Anforderungen absichert.

Betrachten wir als erstes einige der wichtigen Sicherheitsaspekte für die Steuerungsebene von Kubernetes.

API-Server

Der API-Server steht innerhalb des Clusters im Mittelpunkt der gesamten Kommunikation. Auf ihm wird der Großteil der Sicherheitskonfiguration des Clusters angewendet. Der API-Server ist die einzige Komponente der Steuerungsebene des Clusters, der direkt mit dem Datenspeicher des Clusters interagieren kann. Benutzer, die den Cluster, weitere Komponenten der Steuerungsebene und manchmal auch die Cluster-Workloads benutzen, interagieren alle über die HTTP-basierte REST-API des Servers mit dem Cluster.

Wegen seiner zentralen Rolle bei der Steuerung des Clusters ist eine sorgfältige Zugriffsverwaltung für den API-Server von entscheidender Bedeutung für die Sicherheit. Sollte jemand oder etwas unerbeten Zugriff auf die API erhalten, so kann er alle Arten von sensiblen Informationen abrufen und die Kontrolle über den Cluster selbst übernehmen. Daher sollte der Client-Zugriff auf die Kubernetes-API verschlüsselt, authentifiziert und autorisiert erfolgen.

Sicherstellen einer Kommunikation mit TLS

Um Man-in-the-Middle-Angriffe zu verhindern, sollte die Kommunikation zwischen jedem einzelnen Client und dem API-Server mit TLS verschlüsselt werden. Dazu muss der API-Server mit einem privaten Schlüssel und einem X.509-Zertifikat konfiguriert werden.

Das X.509-Zertifikat für die Root-Zertifizierungsstelle (CA), die das Zertifikat des API-Servers ausgestellt hat, muss allen Clients zur Verfügung stehen, die sich im Rahmen eines TLS-Handshakes am API-Server authentifizieren müssen. Dieser Punkt führt uns zur Frage der Zertifizierungsstellen für den Cluster im Allgemeinen. Wie wir gleich sehen werden, haben die Clients zahlreiche Möglichkeiten, sich am API-Server zu authentifizieren. Eine davon ist über X.509-Zertifikate. Falls diese Art der Client-Authentifizierung verwendet wird – was in den meisten Fällen (zumindest für Cluster-Komponenten) wahrscheinlich zutrifft –, so sollte jede Cluster-Komponente ein eigenes Zertifikat erhalten. Es ist sehr sinnvoll, eine Cluster-weite Public Key Infrastruktur (PKI) Fähigkeit einzurichten.

Es gibt zahlreiche Möglichkeiten, eine PKI-Fähigkeit für einen Cluster zu erstellen. Dabei ist kein Weg besser als der andere. Diese Funktion kann von Hand, mit Unterstützung des von Ihnen gewählten Installers oder auch auf andere Weise konfiguriert werden. Tatsächlich kann der Cluster so konfiguriert werden, dass er über eine eigene eingebaute CA verfügt, um als Reaktion auf die über den API-Server gesendeten Anforderungen zur Zertifikatsunterzeichnung Zertifikate ausstellen zu können. Wir von Giant Swarm setzen auf einen Operator namens cert-operator in Verbindung mit Hashicorps Vault.

Während wir die sichere Kommunikation mit dem API-Server erörtern, sollten Sie unbedingt den unsicheren Port (bis Kubernetes 1.13) deaktivieren, mit dem die API über Plain HTTP (–insecure-port=0) angesteuert wird!

Authentifizierung, Autorisierung und Zugriffskontrolle

Nun wollen wir unsere Aufmerksamkeit auf die Kontrollmöglichkeiten richten, mit denen wir die erlaubten Operationen der Clients auf bestimmten Cluster-Ressourcen einschränken können. Wir werden hier nicht allzu sehr ins Detail gehen, da dies ein Thema für einen weiteren Artikel ist. Wichtig ist aber, dass die Komponenten der Steuerungsebene so konfiguriert werden, dass sie die zugrunde liegenden Zugriffskontrollen bereitstellen.

Wenn auf dem API-Server eine API-Anfrage eingeht, so wird eine Reihe von Prüfungen durchgeführt, um festzustellen, ob dieser Anfrage entsprochen werden soll oder nicht. Sind die Anforderungen erfüllt, so wird geprüft, ob das Ressourcenobjekt gemäß der definierten Richtlinie validiert oder verändert werden muss. Die Ausführungskette (Authentifizierung –> Autorisierung –> Zugangskontrolle) ist im nachstehenden Diagramm dargestellt.

Kubernetes unterstützt viele verschiedene Authentifizierungsschemata, die fast immer Cluster-extern implementiert sind. Dazu gehören X.509-Zertifikate, Basic Auth, Bearer Token, OpenID Connect (OIDC) zur Authentifizierung über einen vertrauenswürdigen Identitätsanbieter usw. Die verschiedenen Schemata werden über entsprechende Konfigurationsoptionen auf dem API-Server aktiviert. Für die X.509-Client-Zertifikatsauthentifizierung ist der Pfad zu einer Datei erforderlich, die ein oder mehrere Zertifikate für CAs enthält (z. B. –client-ca-file). Es ist unbedingt zu beachten, dass alle API-Anfragen, die mit keinem Authentifizierungsschema authentifiziert wurden, standardmäßig als anonyme Anfragen behandelt werden. Auch wenn der Zugriff für anonyme Anfragen durch Autorisierung eingeschränkt werden kann, sollte er vollständig deaktiviert werden, wenn er nicht benötigt wird (–anonymous-auth=false).

Sobald eine Anforderung authentifiziert ist, betrachtet der API-Server die Anfrage im Hinblick auf die Autorisierungsrichtlinien. Hier sind die Autorisierungsmodi ebenfalls eine Konfigurationsoption (–authorization-mode), die zumindest vom Standardwert AlwaysAllow abweichen sollte. Die Liste der Autorisierungsmodi sollte idealerweise RBAC und Node umfassen: die erste Option zur Aktivierung der RBAC-API für fein abgestimmte Zugriffskontrolle und die zweite Option zur Autorisierung von Kubelet-API-Anfragen (siehe weiter unten).

Nach Authentifizierung und Autorisierung einer API-Anfrage kann das Ressourcenobjekt mithilfe von Admission Controllern validiert oder verändert werden, bevor es in der Statusdatenbank des Clusters dauerhaft hinterlegt wird. Es wird ein Mindestbestand an Admission Controllern empfohlen, der nicht gekürzt werden sollte, sofern nicht ein sehr guter Grund dafür vorliegt. Zusätzliche sicherheitsrelevante Admission Controller, die berücksichtigt werden sollten:

  • Falls Ihre Pods mit erweiterten Rechten ausgeführt werden sollen (z. B. mithilfe der IPC/PID-Namensräume des Hosts), verhindert dieser Admission Controller, dass Benutzer Befehle in den privilegierten Containern des Pods ausführen können.
  • Diese Pod-Sicherheitsrichtlinie räumt die Möglichkeit ein, für alle erstellten Pods verschiedene Sicherheitsmechanismen anzuwenden. Wir werden das in einem weiteren Artikel dieser Serie vertiefen. Im Moment sollte aber sichergestellt sein, dass dieser Admission Controller aktiviert ist, da unsere Sicherheitsrichtlinien andernfalls nicht angewendet werden können .
  • Ein Admission Controller, der den Zugriff eines Kubelets auf Ressourcen steuert, was weiter unten näher erläutert werden wird.
  • Damit können die für Container eines Pods definierten Images von einem externen „Image Validator“, wie beispielsweise Image Enforcer, auf Schwachstellen überprüft werden. Image Enforcer basiert auf dem Open Policy Agent (OPA) und funktioniert mit dem Open-Source-Schwachstellenscanner Clair.

Die dynamische Zugriffskontrolle – eine relativ neue Funktion in Kubernetes – zielt darauf ab, viel mehr Flexibilität als eine statische Plug-In-Zugriffskontrolle zu bieten. Sie wird mit Admission Webhooks und Controller-basierten Initializern eingerichtet und bietet eine vielversprechende Cluster-Sicherheit, sobald Community-Lösungen eine ausreichende Reife erreicht haben.

Kubelet

Kubelet ist ein Agent, der auf jedem Node im Cluster läuft und für alle Pod-bezogenen Aktivitäten auf dem Node, auf dem es läuft, verantwortlich ist. Dazu gehören unter anderem auch die Starts/Stopps und Neustarts der Pod-Container oder die Berichterstattung zum Zustand der Pod-Container. Gleich nach dem API-Server ist das Kubelet die nächstwichtige Cluster-Komponente, die in Sachen Sicherheit berücksichtigt werden muss.

Zugriff auf die Kubelet REST-API

Das Kubelet stellt eine kleine REST-API auf den Ports 10250 und 10255 bereit. Port 10250 ist ein Lese-/Schreib-Port, während 10255 schreibgeschützt ist und eine Teilmenge der API-Endpunkte aufweist.

Der ungehinderte Zugriff auf Port 10250 ist gefährlich, da innerhalb der Container eines Pod beliebige Befehle ausgeführt und beliebige Pods gestartet werden können. Ebenso bieten beide Ports einen Lesezugriff auf möglicherweise sensible Informationen zu Pods und ihren Containern, was die Workloads gefährden könnte.

Um mögliche Gefährdungen zu vermeiden, sollte der schreibgeschützte Port deaktiviert werden. Dazu wird die Konfiguration des Kubelets auf –-read-only-port=0 gesetzt. Port 10250 muss jedoch für die Erfassung der Metriken und andere wichtige Funktionen zur Verfügung stehen. Der Zugriff auf diesen Port sollte sorgfältig kontrolliert werden. Daher sollten wir die wichtigsten Sicherheitseinstellungen erörtern.

Client-Authentifizierung

Sofern nicht anders konfiguriert, ist die Kubelet-API für nicht authentifizierte Anfragen von Clients offen. Daher sollte eine der verfügbaren Authentifizierungsmethoden konfiguriert werden: X.509-Client-Zertifikate oder Anfragen mit Autorisierungsheadern, die Bearer-Token enthalten.

Bei X.509-Client-Zertifikaten muss dem Kubelet der Inhalt eines CA-Bundles zur Verfügung gestellt werden, damit es die von den Clients während des TLS-Handshake präsentierten Zertifikate authentifizieren kann. Dies wird im Rahmen der Kubelet-Konfiguration (–client-ca-file) bereitgestellt.

In einer idealen Welt wäre der Kubernetes API-Server der einzige Client, der einen Zugriff auf die API eines Kubelets benötigt. Er muss für verschiedene Funktionen auf die API-Endpunkte des Kubelets zugreifen. Dazu gehören beispielsweise das Erfassen von Protokollen und Metriken, das Ausführen eines Befehls in einem Container (zum Beispiel kubectl exec), das Weiterleiten eines Ports an einen Container usw. Um vom Kubelet authentifiziert werden zu können, muss der API-Server mit TLS-Anmeldedaten des Clients konfiguriert werden (–kubelet-client-certificate und –kubelet-client-key).

Anonyme Authentifizierung

Wenn Sie darauf geachtet haben, den Zugriff des API-Servers auf die API des Kubelets zu konfigurieren, so liegt es vielleicht nahe, „Job erledigt“ zu denken. Das ist aber nicht der Fall, denn alle Anfragen, welche die API des Kubelets betreffen und nicht versuchen, sich mit dem Kubelet zu authentifizieren, werden als anonyme Anfragen betrachtet. Standardmäßig gibt das Kubelet anonyme Anfragen an die Autorisierung weiter, anstatt sie als unauthentifiziert abzulehnen.

Sollte es in Ihrer Umgebung von grundlegender Bedeutung sein, auch anonyme Kubelet-API-Anfragen zuzulassen, so gibt es das „Authentifizierungs-Gate“. Bei der Bestimmung, was von der API bedient werden darf und was nicht, ermöglicht dieses Gate eine gewisse Flexibilität. Es ist jedoch viel sicherer, anonyme API-Anfragen ganz zu verbieten. Dazu setzen Sie die Einstellung –-anonym-auth des Kubelets auf false. Mit dieser Konfiguration gibt die API an nicht autorisierte Clients die Antwort 401 Unauthorized zurück.

Autorisierung

Mit der Autorisierung von Anfragen an die Kubelet-API kann man zudem erneut mit einer Standardeinstellung von Kubernetes in Konflikt geraten. Die Autorisierung für die Kubelet-API erfolgt in einem von zwei Modi: AlwaysAllow (Standard) oder Webhook. Der AlwaysAllow-Modus macht genau das, was Sie erwarten würden: Er lässt alle Anfragen zu, die das Authentifizierungs-Gate passiert haben. Dazu gehören auch anonyme Anfragen.

Anstatt diesen Eingang weit offen zu lassen, ist es am besten, die Autorisierungsentscheidung an den Kubernetes-API-Server zu übertragen. Dazu wird die Konfigurationsoption –authorization-mode des Kubelets mit dem Wert webhook verwendet. In dieser Konfiguration ruft das Kubelet die SubjectAccessReview-API (die Teil des API-Servers ist) auf, um zu bestimmen, ob das Subjekt die Anfrage stellen darf oder nicht.

Einschränkung der Autorisierung des Kubelets

In älteren Kubernetes-Versionen (vor 1.7) hatte das Kubelet Lese- und Schreibzugriff auf alle Node- und Pod-API-Objekte, selbst wenn diese unter der Kontrolle eines anderen Kubelets standen, das auf einem anderen Node ausgeführt wurde. Ebenso hatte es Lesezugriff auf alle Objekte, die in den Pod-Spezifikationen enthalten waren: die Objekte Secret, ConfigMap, PersistentVolume und PersistentVolumeClaim. Anders ausgedrückt: Ein Kubelet konnte auf zahlreiche Ressourcen zugreifen und diese kontrollieren, obwohl es eigentlich keine Verantwortlichkeit dafür hatte. Dies ist eine sehr mächtige Funktion und im Falle einer Gefährdung des Cluster-Nodes könnte der Schaden schnell über den betreffenden Node hinaus eskalieren.

Node-Authorizer

Daher wurde speziell für das Kubelet ein Node-Autorisierungsmodus eingeführt, um den Zugriff auf die Kubernetes-API kontrollieren zu können. Der Node-Authorizer beschränkt das Kubelet auf Lesevorgänge an den für das Kubelet relevanten Objekten (z. B. Pods, Nodes, Services) und wendet weitere schreibgeschützte Beschränkungen auf Secrets, Configmap, PersistentVolume und PersistentVolumeClaim-Objekte an. Diese sind speziell mit den Pods verknüpft, die an den Node gebunden sind, auf dem das Kubelet läuft.

NodeRestriction-Admission Controller

Wenn man den Zugriff des Kubelets auf relevante Objekte auf einen schreibgeschützten Zugriff beschränkt, so ist dies ein wichtiger Schritt, um die Gefährdung von Clustern oder Workloads zu vermeiden. Das Kubelet benötigt im Rahmen seiner normalen Funktion einen Schreibzugriff für seine Node- und Pod-Objekte. Dazu unterliegt die API-Anforderung eines Kubelets, sobald sie die Node-Autorisierung durchlaufen hat, dem NodeRestriction-Admission Controller. Dieser Controller beschränkt die Node- und Pod-Objekte, die das Kubelet modifizieren darf, auf seine eigenen. Damit das funktioniert, muss der Kubelet-Benutzer system:node:<nodeName> sein, der zur Gruppe system:nodes gehört. Es ist natürlich die nodeName-Komponente des Kubelet-Benutzers, welche der NodeRestriction-Admission Controller nutzt, um Kubelet-API-Anfragen zum Ändern von Node- und Pod-Objekten zuzulassen oder abzulehnen. Daraus folgt, dass jedes Kubelet ein eindeutiges X.509-Zertifikat zur Authentifizierung gegenüber dem API-Server haben sollte. Dabei gibt der Common Name des Distinguished Name eines Subjekts den Benutzer und die Organisation die Gruppe an.

Auch diese wichtigen Konfigurationen erfolgen nicht automatisch. Der API-Server muss mit Node als einer der kommagetrennten Plug-In-Liste für die Konfigurationsoption —authorization-mode gestartet werden. Dabei muss NodeRestriction in der Liste der Admission Controller enthalten sein, die mit der Option –enable-admission-plugins angegeben sind.

Best Practice

Wir müssen betonen, dass wir hier nur einen Teil der Sicherheitsüberlegungen für die Cluster-Ebene abgedeckt haben (wenn auch die wichtigen). Sollte das für Sie in irgendeiner Weise beängstigend klingen, so fürchten Sie sich bitte nicht, denn Hilfe ist da!

Genauso wie für Elemente der Infrastrukturebene, wie beispielsweise Docker, Benchmark-Sicherheitsempfehlungen erstellt wurden, so wurden diese auch für einen Kubernetes-Cluster erstellt. Das Center for Internet Security (CIS) hat für jede Komponente des Clusters eine Reihe von Konfigurationseinstellungen und Dateisystemprüfungen zusammengestellt, die als CIS Kubernetes Benchmark veröffentlicht wurden.

Sie sollten auch wissen, dass die Kubernetes-Community ein Open-Source-Tool entwickelt hat, um einen Kubernetes-Cluster gegen den Benchmark zu prüfen – die Kubernetes Bench for Security. Es handelt sich dabei um eine Golang-Anwendung, die eine Reihe verschiedener Kubernetes-Versionen (ab 1.6 aufwärts) sowie verschiedene Versionen des Benchmarks unterstützt.

Wenn Sie Ihren Cluster richtig absichern wollen, dann ist der Einsatz des Benchmarks als Maßstab für die Compliance ein absolutes Muss.

Zusammenfassung

Die vorbeugenden Maßnahmen zur Absicherung Ihres Clusters mithilfe einer angemessenen Konfiguration sind natürlich von entscheidender Bedeutung, um die in diesem Cluster laufenden Workloads zu schützen. Obwohl die Kubernetes-Community sehr hart darauf hingearbeitet hat, alle notwendigen Sicherheitskontrollen für die Einführung dieser Sicherheit bereitzustellen, übersehen einige Standardkonfigurationen aus historischen Gründen, was als Best Practice gilt. Wir ignorieren diese Mängel auf eigene Gefahr und tragen die Verantwortung dafür, diese Lücken zu schließen, wenn wir einen Cluster erstellen oder auf neuere Versionen mit neuen Funktionen aktualisieren.

Einige der hier erörterten Punkte bereiten den Weg für die nächste Ebene im Stack. Dort nutzen wir die von uns konfigurierten Sicherheitsmechanismen, um Sicherheitskontrollen zu definieren und anzuwenden. So schützen wir die Workloads, die auf dem Cluster laufen.

Wenn Sie Ihre eigenen Cloud-nativen Projekte in Produktion bringen wollen, wenden Sie sich für Unterstützung an die Experten von Giant Swarm

Beiträge empfohlen von Microsoft


http://brawo.ixvl0318.nbsp.de/zukunftsmacher/absichern-der-konfiguration-von-kubernetes-cluster-komponentenhttp://brawo.ixvl0318.nbsp.de/zukunftsmacher/absichern-der-konfiguration-von-kubernetes-cluster-komponenten

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.