TLS in Kubernetes implementieren
Rubaiat Hossain
31. Juli 2023
0 Min. LesezeitMit der Weiterentwicklung der Cloud-Technologie steigt die Nachfrage nach Kubernetes rasant. Dadurch hat Sicherheit für Entwickler, die ihre Anwendungsdaten schützen möchten, höchste Priorität erlangt. Hier kommt Transport Layer Security (TLS) ins Spiel. TLS ist unverzichtbar, um eine sichere Verbindung zwischen Ihren Anwendungen und dem Internet zu gewährleisten.
TLS nutzt asymmetrische und symmetrische Verschlüsselungsverfahren, um Ihre Daten bei der Übertragung und im Ruhezustand zu schützen. Das in Kubernetes verwendete TLS-Zertifikat ist üblicherweise ein öffentliches Schlüsselzertifikat, das von einer vertrauenswürdigen Zertifizierungsstelle (CA) ausgestellt wird. Dieses Zertifikat enthält Informationen zur Identität des Servers, zum für die Verschlüsselung verwendeten öffentlichen Schlüssel und zur digitalen Signatur der ausstellenden CA.
Dieser Artikel führt Sie durch die Implementierung einer TLS-Verbindung für Ihre Anwendungen in einem Kubernetes-Cluster und vermittelt Ihnen ein umfassendes Verständnis von TLS und seiner Bedeutung für den Schutz Ihrer Anwendungen und Daten.
So wird TLS für Kubernetes-Workloads implementiert
Wenn Anfragen bei einer Anwendung eingehen, die in einem Kubernetes-Cluster ausgeführt wird, durchlaufen sie eine Netzwerkkomponente, die als Gateway für den eingehenden Datenverkehr dient. Je nach Konfiguration Ihrer Anwendung kann diese Netzwerkkomponente ein Kubernetes-Ingress-Controller, ein Load-Balancer-Service, ein Cluster-IP-Service oder ein Node-Port-Service sein.
Kubernetes stellt keine standardmäßige TLS-Verschlüsselung für die Kommunikation zwischen Client und Netzwerkkomponente bereit. Das bedeutet, dass Anfragen über HTTP statt HTTPS verarbeitet werden. Sie können Ihre Kubernetes-App jedoch ganz einfach so konfigurieren, dass sie für eine sichere Kommunikation TLS und HTTPS verwendet.
Kubernetes bietet außerdem Funktionen wie Secrets und ConfigMaps, mit denen Sie Ihre TLS-Zertifikate und andere vertrauliche, von Ihrer Anwendung benötigte Daten sicher verwalten können.
Früher wurde TLS (und sein Vorgänger SSL) zwischen Systemen und Benutzern eingesetzt, die eine sichere Kommunikation benötigten. Mit der Verbreitung verteilter Systeme, den deutlich gesunkenen Kosten und Leistungseinbußen bei der Implementierung von TLS sowie den wachsenden Datenschutzbedenken empfehlen die meisten Experten inzwischen, den gesamten Datenverkehr zu verschlüsseln. Zu den häufigen Anwendungsfällen für Netzwerkverschlüsselung zählen:
Zahlungssysteme: Wenn Ihre Anwendung Zahlungsdaten wie Bankverbindungen und Kreditkartendaten verarbeitet, müssen Sie TLS implementieren. Dies ist eine regulatorische Anforderung und notwendig, um Daten während der Übertragung zu schützen. Die Verschlüsselung von Zahlungsdaten stärkt außerdem das Vertrauen Ihrer Kunden und gibt ihnen ein sicheres Gefühl bei der Nutzung Ihrer Dienste.
End-to-End-Datenverschlüsselung mit einem Service Mesh: Mit einem Mechanismus zur End-to-End-Datenverschlüsselung und einem Service Mesh wie Istio kann TLS die Kommunikation zwischen verschiedenen Microservices innerhalb eines Kubernetes-Clusters absichern. Dieser Ansatz ist bei modernen, verteilten Microservice-Architekturen beliebt.
IoT und Edge Computing: Kubernetes-Anwendungen, die mit IoT-Geräten oder Edge-Computing-Systemen interagieren, sollten TLS implementieren, um die Datenübertragung zwischen Geräten und Cloud abzusichern und unbefugten Zugriff auf von IoT-Geräten erzeugte Daten zu verhindern.
Content Delivery Networks (CDNs): Wenn Ihre Anwendungen CDNs zum Zwischenspeichern und Bereitstellen von Inhalten verwenden, kann TLS für eine sichere Übertragung der Inhalte sorgen und Manipulationen sowie unbefugten Zugriff verhindern.
TLS in Kubernetes konfigurieren
In den folgenden Abschnitten implementieren Sie TLS für eine einfache Kubernetes-Anwendung. Dazu verwenden Sie ein Node.js-Projekt, das eine Zahlungsabwicklungsanwendung simuliert. Den Anwendungscode und die erforderliche Kubernetes-Konfiguration finden Sie in diesem GitHub-Repository.
Voraussetzungen
Für dieses Tutorial benötigen Sie Folgendes:
Eine Container-Runtime: Für diesen Artikel gehen wir davon aus, dass Docker auf Ihrer Workstation installiert und konfiguriert ist.
Eine Kubernetes-Distribution: Sie müssen eine Kubernetes-Distribution installieren, um den Kubernetes-Cluster und weitere benötigte Ressourcen wie Deployments und Services zu erstellen. In diesem Tutorial verwenden wir kind (v0.18.0). Sie können aber auch eine andere Kubernetes-Distribution nutzen, darunter minikube oder K3s.
kubectl: Mit dieser Befehlszeilenschnittstelle kommunizieren Sie mit Ihrem Kubernetes-Cluster und führen Befehle aus. In diesem Tutorial verwenden wir Version 1.26.
mkcert: Damit erhalten Sie ein vertrauenswürdiges TLS-Zertifikat mit einem benutzerdefinierten Domänennamen für Ihren Entwicklungscomputer. Sie können
mkcertgemäß den offiziellen Anweisungen auf Ihrem Entwicklungscomputer installieren.Git und Helm: Sie benötigen Git, um das Demoprojekt lokal zu verwenden, sowie den Helm-Paketmanager für Kubernetes. In dieser Anleitung verwenden wir Helm v3.11.2.
In den folgenden Abschnitten erfahren Sie, wie Sie TLS für eine Demo-Zahlungsanwendung implementieren, die in einem lokalen Kubernetes-Cluster bereitgestellt wird. Zunächst stellen Sie die App in Ihrem kind-Cluster bereit und prüfen, ob sie HTTP statt HTTPS verwendet. Anschließend erstellen Sie ein selbstsigniertes TLS-Zertifikat und konfigurieren Ihre Zahlungs-App entsprechend. Zum Schluss erstellen Sie mit mkcert ein vertrauenswürdiges TLS-Zertifikat und prüfen, ob Ihre Kubernetes-App über HTTPS erreichbar ist.
Zahlungs-App in Kubernetes bereitstellen
Um mit der Implementierung von TLS in Ihrer Kubernetes-basierten Beispielanwendung zu beginnen, klonen Sie die Anwendung mit folgendem Befehl auf Ihren lokalen Computer:
Wechseln Sie anschließend mit diesem Befehl in das Projektverzeichnis:
Sobald Sie sich im Projektverzeichnis befinden, können Sie die Anwendung in Ihrem Kubernetes-Cluster bereitstellen.
Erstellen Sie mit folgendem Befehl Ihren kind-Cluster:
Hinweis: Die Datei config.yaml bindet einige Ports der kind-Knoten an Ihren localhost. Das ist bei Docker-Desktop-Installationen erforderlich, da die kind-Container tatsächlich in einer virtuellen Maschine (VM) ausgeführt werden. Wenn Sie eine Linux-Workstation mit nativ installiertem Docker verwenden (ohne Docker-Desktop-VM), können Sie die Option --config hier weglassen.
Als Nächstes erstellen wir das Container-Image und laden es in unseren kind-Cluster.
Hinweis: Optional können Sie das Image auch in eine Registry übertragen, statt kind load zu verwenden. In diesem Fall müssen Sie außerdem die unten verwendete Datei deployment.yaml bearbeiten, Ihre Registry-Informationen eintragen und imagePullPolicy auf „Always“ setzen, damit das Image abgerufen wird.
Sobald der Cluster erstellt ist, stellen Sie die Anwendung mit diesen Befehlen darin bereit:
Warten Sie einige Minuten, bis Kubernetes die Pods und weitere benötigte Ressourcen erstellt hat. Mit diesen Befehlen können Sie den Status Ihrer Ressourcen prüfen:
Ihr Demoprojekt stellt die Zahlungsanwendung über einen nodePort-Service auf Port 30080 bereit. Wenn Sie einen Kubernetes-Service ohne Angabe des Felds „type“ definieren, weist Kubernetes ihm standardmäßig den Servicetyp ClusterIP zu.
Die von ClusterIP bereitgestellte IP-Adresse ist jedoch nur innerhalb des Clusternetzwerks erreichbar. Daher können Sie die in Ihrem Cluster ausgeführte Anwendung nicht mit einem externen Client wie Ihrem Webbrowser aufrufen. In einer Produktionsumgebung empfiehlt sich möglicherweise ein LoadBalancer-Service, damit Ihr Cloud-Anbieter einen externen Load Balancer mit einer öffentlich erreichbaren IP-Adresse bereitstellen kann.
Mit diesen Befehlen können Sie sich die Services für diese Demo-Anwendung anzeigen lassen:
Je nach Laufzeitumgebung können Sie auf zwei Arten auf die Demo-Anwendung zugreifen:
Mit VM (z. B. Docker Desktop):
Um die Demo-Anwendung in Ihrem Browser aufzurufen, verwenden Sie die in der Datei config.yaml eingerichtete kind-Portbindung und geben einfach localhost:30080 ein.
Ohne VM (z. B. Linux ohne Docker Desktop):
Um die Demo-Anwendung in Ihrem Browser aufzurufen, müssen Sie mit folgendem Befehl die IP-Adresse ermitteln, die über den nodePort bereitgestellt wird:
Damit sollte die INTERNAL-IP Ihrer Kubernetes-Steuerungsebene angezeigt werden (z. B. 172.18.0.2). Anschließend können Sie mit Folgendem auf die Zahlungsanwendung zugreifen:
Ersetzen Sie die IP-Adresse unbedingt durch die tatsächliche INTERNAL-IP Ihrer Kubernetes-Steuerungsebene oder gemäß den obigen Anweisungen durch localhost.
Wenn Sie in Ihrem Browser die obige IP-Adresse und den Port aufrufen, wird die Zahlungsseite angezeigt, auf der Sie Kartendaten eingeben können. Da es sich um eine simulierte Anwendung handelt, werden keine echten Zahlungen verarbeitet und die Daten werden nirgendwo gespeichert:

Je nach Browser wird in der Nähe der Adressleiste ein Hinweis wie Nicht sicher angezeigt. Das bedeutet, dass diese Anwendung über HTTP und nicht über HTTPS bereitgestellt wird. Sie können dies prüfen, indem Sie auf den Hinweis klicken:

Selbstsigniertes TLS-Zertifikat für Ihre App implementieren
Implementieren Sie nun TLS für die Kubernetes-Beispielanwendung. Erstellen Sie ein selbstsigniertes Zertifikat und einen privaten Schlüssel:
Erstellen Sie anschließend ein Kubernetes-Secret mit dem Zertifikat und dem privaten Schlüssel:
Installieren Sie nun den Nginx Ingress Controller, damit eingehende Anfragen an Ihre Zahlungs-App auf HTTPS umgeleitet werden. Da Sie die App über nodePort bereitgestellt haben, müssen Sie den Ingress mit einer benutzerdefinierten Wertedatei installieren, in der der Servicetyp auf NodePort festgelegt ist.
Erstellen Sie eine Datei namens ingress-values.yaml mit folgendem Inhalt:
Installieren Sie anschließend den Nginx Ingress Controller mit Helm und der benutzerdefinierten Wertedatei:
Erstellen Sie eine Datei ingress.yaml mit folgendem Inhalt:
Wenden Sie dieses Manifest anschließend mit folgendem Befehl an:
Ergänzen Sie Ihre Datei /etc/hosts um folgenden Eintrag:
Wenn Sie Docker Desktop verwenden, ersetzen Sie <control_plane_IP> unbedingt durch 127.0.0.1. Andernfalls verwenden Sie die IP-Adresse, die Sie mit kubectl get nodes -o wide ermittelt haben.
Sie können jetzt über HTTPS auf die Zahlungs-App zugreifen, indem Sie in Ihrem Browser https://my-demo-app.local:32443 aufrufen. Beim ersten Besuch sollte Ihr Browser eine Warnseite anzeigen, auf der Sie das Risiko akzeptieren und fortfahren können. Danach können Sie die Website über HTTPS aufrufen:

Ihr Browser zeigt diesen Fehler an, weil das TLS-Zertifikat selbstsigniert ist. Das erkennen Sie daran, dass HTTPS in der URL durchgestrichen ist.
Vertrauenswürdiges TLS-Zertifikat für Ihre App implementieren
Um dieses Problem zu beheben, können Sie mit mkcert ein vertrauenswürdiges Zertifikat für Ihre Entwicklungsumgebung erstellen. Richten Sie dazu eine lokale CA ein und generieren Sie ein vertrauenswürdiges Zertifikat für Ihre lokale Domäne:
Löschen Sie das vorherige Secret und erstellen Sie ein neues für mkcert:
Stellen Sie abschließend die Ingress-Ressource mit folgendem Befehl erneut bereit:
TLS für Ihre Kubernetes-Anwendung überprüfen
Jetzt sollten Sie Ihre Zahlungs-App mit einem vertrauenswürdigen TLS-Zertifikat aufrufen können. Starten Sie den Browser neu und rufen Sie https://my-demo-app.local:32443 auf, damit das neue Zertifikat verwendet werden kann. Diesmal sollte keine Warnung angezeigt werden und HTTPS in der URL nicht durchgestrichen sein – genau wie bei Websites, die regulär mit TLS gesichert sind:

Klicken Sie auf das Schlosssymbol in der Adressleiste, um zu prüfen, ob Ihr Browser dem TLS-Zertifikat vertraut und die Verbindung sicher ist:

Die aktualisierten Codebeispiele finden Sie im Branch solution unseres GitHub-Projektrepositorys.
Fazit
Beim Umgang mit vertraulichen Daten bietet TLS die Sicherheit, die Sie benötigen. Die Implementierung von TLS kann jedoch eine Herausforderung sein, wenn Sie nicht wissen, wie Sie vorgehen müssen.
In diesem Tutorial haben Sie gelernt, wie Sie TLS für eine Anwendung implementieren, die in einem lokalen Kubernetes-Cluster bereitgestellt wird. Dieselben Prinzipien können Sie auch für Anwendungen nutzen, die lokal in Ihrem Rechenzentrum oder bei einem Cloud-Anbieter gehostet werden.
Wenn Sie TLS für ein Produktivsystem implementieren, sollten Sie ein öffentliches Zertifikat einer vertrauenswürdigen CA verwenden, zum Beispiel von Let's Encrypt. Dafür benötigen Sie Zugriff auf die Domain Ihrer Website. Sie können jedoch zusätzliche Konfigurationen einrichten, etwa einen Load-Balancer-Dienst, um Ihre Anwendung bereitzustellen, oder mehrere Zertifikate über einen Certificate Manager wie cert-manager verwalten. Wenn Sie Ihre Anwendung über einen Load Balancer bereitstellen, profitieren Sie von höherer Verfügbarkeit, Skalierbarkeit und Ausfallsicherheit. Mit einem Certificate Manager wird außerdem die Bereitstellung und Verwaltung Ihrer Cluster-Zertifikate in Zukunft zum Kinderspiel.
Sichern Sie Ihre Infrastruktur an der Quelle
Snyk automatisiert die IaC-Sicherheit und Compliance in Workflows und erkennt abweichende sowie fehlende Ressourcen.



