Verbessern der Microservice-Sicherheit mit Istio

Hallo! Mein Name ist Ilya, ich arbeite als DevOps-Ingenieur im Entwicklungsteam. Wir verfolgen aktiv einen Microservice-Ansatz, und aufgrund der Besonderheiten unserer Arbeit ist uns die Sicherheit der dienststellenübergreifenden Kommunikation wichtig. In diesem Artikel möchte ich die Funktionsweise von Istio beschreiben und Ihnen anhand eines Beispiels zeigen, wie Sie einige seiner Sicherheitsfunktionen verwenden. Ich hoffe, dass dies zur Lösung Ihrer Probleme hilfreich sein wird. Viel Spaß beim Lesen!







Wofür ist ein Servicenetz?



Das Service-Mesh, in diesem Fall Istio, ist eine Bindung für alles, was zum Verwalten und Konfigurieren der dienstübergreifenden Kommunikation erforderlich ist: Routing, Authentifizierung, Autorisierung, Ablaufverfolgung, Zugriffskontrolle und vieles mehr. Und obwohl es viele Open-Source-Bibliotheken gibt, um diese Funktionen direkt im Service-Code zu implementieren, können Sie mit Istio alle gleich erhalten, ohne dem Service selbst etwas hinzuzufügen.



Komponenten 



Artikel geschrieben für istio 1.6


Über Änderungen
Istio , . , , - , , . , , Istio 1.4   v1beta1 , Istio RBAC. 1.5 , Pilot, Galley Citadel istiod. - . .



Istio ist logisch in eine Datenebene und eine Steuerebene unterteilt.

Die Datenebene ist eine Sammlung von Proxy-Servern (Envoy), die dem Pod als Sidecars hinzugefügt wurden. Diese Proxys stellen die gesamte Netzwerkkommunikation zwischen Mikrodiensten bereit und steuern diese und werden von der Steuerebene aus konfiguriert.



Die Verwaltungsebene (istiod) bietet Serviceerkennung, Konfiguration und Zertifikatverwaltung. Es konvertiert Istio-Objekte in Envoy-freundliche Konfigurationen und verteilt sie in der Datenebene.







Istio Service Mesh-Komponenten



Sie können dem Anwendungs-Pod entweder manuell oder durch Einrichten des automatischen Hinzufügens mithilfe des Webhooks Mutating Admission, den Istio während der Installation hinzufügt, einen Gesandten hinzufügen. Setzen Sie dazu das Tag istio-insert = enabled in den erforderlichen Namespace.



Zusätzlich zum Proxy-Beiwagen mit Gesandten wird Istio dem Pod einen speziellen Init-Container hinzufügen, der den Kampfverkehr mit dem Gesandten auf den Container umleitet. Aber wie wird das erreicht? In diesem Fall gibt es keine Magie, und dies wird implementiert, indem zusätzliche iptables-Regeln im Netzwerk-Namespace des Pods festgelegt werden.



Über den Ressourcenverbrauch
, 100 Istio ~2-3 , envoy 40 , CPU 5%-7% pod.



Lassen Sie uns einen praktischen Blick darauf werfen, wie ein Beiwagen eingehenden und ausgehenden Verkehr von einem Container erfasst. Schauen wir uns dazu den Netzwerkbereich eines Pods mit dem von Istio hinzugefügten Beiwagen genauer an. 



Demo stehen
Kubernetes Istio. 

Kubernetes minikube:



Linux:
curl -Lo minikube https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64 && chmod +x minikube
sudo mkdir -p /usr/local/bin/
sudo install minikube /usr/local/bin/

minikube start --driver=<driver_name> // --driver=none        .




MacOS:
brew install minikube
minikube start --driver=<driver_name>






Istio demo :



curl -L https://istio.io/downloadIstio | sh -
cd istio-1.6.3
export PATH=$PWD/bin:$PATH
istioctl install --set profile=demo


: productpage details. Istio .



kubectl label namespace default istio-injection=enabled
kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml








Sehen wir uns die Liste der Productpage-Anwendungscontainer an:



kubectl -n default get pods productpage-v1-7df7cb7f86-ntwzz -o jsonpath="{.spec['containers','initContainers'][*].name}"
productpage 
istio-proxy 
istio-init


Zusätzlich zur Produktseite selbst arbeiten Sidecar Istio-Proxy (der gleiche Gesandte) und Init Container Istio-Init im Pod.



Sie können die im Pod-Bereich konfigurierten iptables-Regeln mit dem Dienstprogramm nsenter anzeigen. Dazu müssen wir die PID des Containerprozesses herausfinden:



docker inspect k8s_productpage --format '{{ .State.Pid }}'
16286


Jetzt können wir die in diesem Container installierten iptables-Regeln sehen.







Sie können sehen, dass fast der gesamte eingehende und ausgehende Datenverkehr jetzt abgefangen und an Ports umgeleitet wird, auf die der Gesandte bereits wartet. 



Aktivieren Sie die gegenseitige Verkehrsverschlüsselung



Die Politik und MeshPolicy Objekte wurden entfernt von istio 1.6. Stattdessen wird empfohlen, das PeerAuthentication-Objekt zu verwenden


Mit Istio können Sie den gesamten Datenverkehr zwischen Containern verschlüsseln, und die Anwendungen selbst wissen nicht einmal, dass sie über tls kommunizieren. Dies wird von Istio selbst sofort mit buchstäblich einem Manifest durchgeführt, da Client-Zertifikate bereits im Proxy-Beiwagen montiert sind. 



Der Algorithmus ist wie folgt: 



  1. Envoy-Proxys auf Client- und Serverseite authentifizieren sich gegenseitig, bevor Anforderungen gesendet werden.

  2. Wenn die Prüfung erfolgreich ist, verschlüsselt der Client-Proxy den Datenverkehr und sendet ihn an den Server-Proxy.

  3. Die Proxyserverseite entschlüsselt den Datenverkehr und leitet ihn lokal an den eigentlichen Zieldienst weiter.



Sie können mTLS auf verschiedenen Ebenen aktivieren:



  • Auf der Ebene des gesamten Netzwerks;

  • Auf der Namespace-Ebene;

  • Auf der spezifischen Pod-Ebene. 



Betriebsarten:



  • PERMISSIVE: Sowohl verschlüsselter als auch Klartextverkehr sind zulässig.

  • STRENG: nur TLS erlaubt;

  • DEAKTIVIEREN: Nur einfacher Text zulässig.



Lassen Sie uns über den Productpage-Pod mit curl ohne TLS auf den Detailservice zugreifen und sehen, was mit tcpdump für Details geliefert wird:



Anfrage:







Dumping des Datenverkehrs:







Alle Textkörper und Header sind im Klartext perfekt lesbar.



Lassen Sie uns tls einschalten. Erstellen Sie dazu mit unseren Pods im Namespace ein Objekt vom Typ PeerAuthentication.



apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
  name: default
  namespace: default
spec:
  mtls:
    mode: STRICT


Lassen Sie uns die Anfrage von der Produktseite aus erneut ausführen, um Details zu erfahren, und sehen, was wir erhalten: Der







Datenverkehr ist verschlüsselt



Anmeldung



ClusterRbacConfig, ServiceRole und ServiceRoleBinding Objekte wurden entfernt mit der Umsetzung der neuen Berechtigungspolitik zusammen. Stattdessen wird vorgeschlagen, das AuthorizationPolicy-Objekt zu verwenden.


Mithilfe von Autorisierungsrichtlinien kann Istio eine Anwendung für den Zugriff auf eine andere konfigurieren. Im Gegensatz zu reinen Kubernetes-Netzwerkrichtlinien funktioniert dies außerdem auf L7-Ebene. Beispielsweise können Sie für http-Verkehr die Anforderungsmethoden und -pfade optimieren.



Wie wir im vorherigen Beispiel gesehen haben, ist der Zugriff standardmäßig auf alle Pods im gesamten Cluster offen.



Jetzt deaktivieren wir alle Aktivitäten im Standard-Namespace mithilfe der folgenden yaml-Datei:



apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: deny-all
  namespace: default
spec:
  {}


Und versuchen wir, den Detailservice zu erreichen:



curl details:9080
RBAC: access denied


Großartig, jetzt schlägt unsere Anfrage fehl.



Jetzt konfigurieren wir den Zugriff so, dass nur eine GET-Anforderung und nur der Pfad / details übergeben wird und alle anderen Anforderungen abgelehnt werden. Hierfür gibt es mehrere Möglichkeiten:



  • Sie können konfigurieren, dass Anforderungen mit bestimmten Headern übergeben werden.

  • Nach Dienstkonto der Anwendung;

  • Durch ausgehende IP-Adresse;

  • Durch ausgehenden Namespace;

  • Nach Angaben im JWT-Token.



Am einfachsten ist es, den Zugriff auf das Dienstkonto der Anwendung einzurichten, da hierfür keine vorläufige Konfiguration erforderlich ist, da die Bookinfo-Demoanwendung bereits über ein erstelltes und überwachtes Dienstkonto verfügt.



Um Autorisierungsrichtlinien zu verwenden, die auf Dienstkonten basieren, müssen Sie die gegenseitige TLS-Authentifizierung aktivieren.


Einrichten einer neuen Zugriffsrichtlinie:



apiVersion: "security.istio.io/v1beta1"
kind: "AuthorizationPolicy"
metadata:
  name: "details-viewer"
  namespace: default
spec:
  selector:
    matchLabels:
      app: details
  rules:
  - from:
    - source:
        principals: ["cluster.local/ns/default/sa/bookinfo-productpage"]
    to:
    - operation:
        methods: ["GET"]
        paths: ["/details/*"]


Und wir versuchen wieder zu erreichen:



root@productpage-v1-6b64c44d7c-2fpkc:/# curl details:9080/details/0
{"id":0,"author":"William Shakespeare","year":1595,"type":"paperback","pages":200,"publisher":"PublisherA","language":"English","ISBN-10":"1234567890","ISBN-13":"123-1234567890"}


Alles arbeitet. Probieren wir andere Methoden und Wege aus:



root@productpage-v1-6b64c44d7c-2fpkc:/# curl -XPOST details:9080/details/0
RBAC: access denied
root@productpage-v1-6b64c44d7c-2fpkc:/# 
root@productpage-v1-6b64c44d7c-2fpkc:/# curl -XGET details:9080/ping
RBAC: access denied


Fazit



Abschließend stelle ich fest, dass die berücksichtigten Funktionen nur einen kleinen Bruchteil dessen darstellen, was Istio leisten kann. Wir haben die Verschlüsselung und Autorisierung des dienstübergreifenden Datenverkehrs sofort erhalten und konfiguriert, allerdings auf Kosten des Hinzufügens zusätzlicher Komponenten und damit des zusätzlichen Ressourcenverbrauchs. 



Danke an alle!



All Articles