Skip to main content

TLS in Kubernetes implementieren

Artikel von
Headshot of Rubaiat Hossain

Rubaiat Hossain

feature kubernetes polp

31. Juli 2023

0 Min. Lesezeit

Mit 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 mkcert gemäß 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:

git clone https://github.com/snyk-snippets/tls-in-k8s.git

Wechseln Sie anschließend mit diesem Befehl in das Projektverzeichnis:

cd k8s-tls-demo

Sobald Sie sich im Projektverzeichnis befinden, können Sie die Anwendung in Ihrem Kubernetes-Cluster bereitstellen.

Erstellen Sie mit folgendem Befehl Ihren kind-Cluster:

kind create cluster --config=config.yaml

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.

docker build -t demo-payment-app .
kind load docker-image demo-payment-app

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:

kubectl apply -f deployment.yaml
kubectl apply -f service.yaml

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:

kubectl get deployments
kubectl get pods

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:

kubectl get services

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:

kubectl get nodes -o wide

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:

http://172.18.0.2:30080

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:

Browserfenster mit einem Zahlungsformular mit Feldern für Kartennummer, Ablaufdatum und CVV sowie einer Schaltfläche „Zahlung absenden“.

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:

Der Browser zeigt ein Zahlungsformular an, während eine Sicherheitswarnung darauf hinweist, dass die Verbindung zur Website nicht sicher ist.

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:

openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/CN=my-demo-app.local"

Erstellen Sie anschließend ein Kubernetes-Secret mit dem Zertifikat und dem privaten Schlüssel:

kubectl create secret tls my-demo-app-tls --key tls.key --cert tls.crt

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:

controller:
  service:
    type: NodePort
    nodePorts:
      http: 32080
      https: 32443

Installieren Sie anschließend den Nginx Ingress Controller mit Helm und der benutzerdefinierten Wertedatei:

helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update
helm install ingress-nginx ingress-nginx/ingress-nginx -f ingress-values.yaml

Erstellen Sie eine Datei ingress.yaml mit folgendem Inhalt:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: demo-payment-app-ingress
  annotations:
    kubernetes.io/ingress.class: "nginx"
spec:
  tls:
  - hosts:
    - my-demo-app.local
    secretName: my-demo-app-tls
  rules:
  - host: my-demo-app.local
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: demo-payment-app
            port:
              number: 80

Wenden Sie dieses Manifest anschließend mit folgendem Befehl an:

kubectl apply -f ingress.yaml

Ergänzen Sie Ihre Datei /etc/hosts um folgenden Eintrag:

<control_plane_IP> my-demo-app.local

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:

Browser mit einem Zahlungsformular mit Feldern für Kartennummer, Ablaufdatum und CVV; die Adressleiste zeigt eine HTTPS-Warnung „Nicht sicher“.

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:

mkcert -install
mkcert my-demo-app.local

Löschen Sie das vorherige Secret und erstellen Sie ein neues für mkcert:

kubectl delete secret my-demo-app-tls
kubectl create secret tls my-demo-app-tls --key 
my-demo-app.local-key.pem --cert my-demo-app.local.pem

Stellen Sie abschließend die Ingress-Ressource mit folgendem Befehl erneut bereit:

kubectl delete ingress demo-payment-app-ingress
kubectl apply -f ingress.yaml

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:

Browserfenster mit einer Zahlungsseite, die Felder für Kartennummer, Ablaufdatum und CVV sowie eine Schaltfläche „Zahlung übermitteln“ zeigt.

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

Browser mit einem Zahlungsformular mit Feldern für Kartennummer, Ablaufdatum und CVV sowie einem Sicherheitshinweis, der eine sichere Verbindung bestätigt.

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.

Weiterlesen

feature customer snowflake
Article

Sicherheit von Anfang an: Die Snyk Studio-Integration für Snowflake Cortex Code

Snyk Studio ist in Snowflake Cortex Code integriert und scannt KI-generierten Code, Abhängigkeiten und Container während der Entwicklung auf Schwachstellen.

feature insights announcement
Blog

Node-gyp-Supply-Chain-Kompromittierung: Ein sich selbst verbreitender npm-Wurm, der sich in binding.gyp versteckt

Ein neuer npm-Wurm missbraucht binding.gyp, um node-gyp während der Installation auszuführen. So können schädliche Pakete Code ohne Lifecycle-Skripte ausführen. Der Wurm stiehlt Zugangsdaten, setzt sich in GitHub fest und verbreitet sich selbstständig über Maintainer.

Article

Miasma-Supply-Chain-Angriff: Schadcode in npm-Paketen von @redhat-cloud-services entdeckt

Der als Miasma bekannte Supply-Chain-Wurm wurde in Dutzenden npm-Releases von @redhat-cloud-services entdeckt. Der schädliche Preinstall-Hook stiehlt Zugangsdaten, sondiert Cloud-Identitäten und kann weitere Pakete erneut veröffentlichen.