Einführung in die Netzwerkrichtlinien von Kubernetes für Sicherheitsexperten

Einführung in die Netzwerkrichtlinien von Kubernetes für Sicherheitsexperten

Anmerkung des Übersetzers.: Der Autor des Artikels – Reuven Harrison – verfügt über mehr als 20 Jahre Erfahrung in der Softwareentwicklung und ist derzeit technischer Direktor und Mitgründer des Unternehmens Tufin, das Lösungen für das Sicherheitsrichtlinienmanagement entwickelt. Er betrachtet Kubernetes-Netzwerkrichtlinien als ein leistungsfähiges Mittel zur Netzsegmentierung in einem Cluster, ist jedoch gleichzeitig der Meinung, dass sie in der praktischen Anwendung nicht so einfach sind. Dieses (ziemlich umfangreiche) Material soll das Bewusstsein der Fachleute für dieses Thema schärfen und ihnen bei der Erstellung der benötigten Konfigurationen helfen.

Heute entscheiden sich viele Unternehmen zunehmend für Kubernetes zur Ausführung ihrer Anwendungen. Das Interesse an dieser Software ist so groß, dass einige Kubernetes als „neues Betriebssystem für Rechenzentren“ bezeichnen. Allmählich wird Kubernetes (oder k8s) als kritischer Bestandteil des Geschäfts angesehen, der die Organisation reifer Geschäftsprozesse erfordert, einschließlich der Gewährleistung der Netzwerksicherheit.

Für Sicherheitsexperten, die Schwierigkeiten mit Kubernetes haben, könnte die Standardrichtlinie dieser Plattform eine wahre Offenbarung sein: Alles erlauben.

Dieses Handbuch hilft dabei, das interne Wesen von Netzwerkrichtlinien zu verstehen; es erklärt, wie sie sich von Regeln für herkömmliche Firewalls unterscheiden. Es werden auch einige Stolpersteine angesprochen und Empfehlungen gegeben, die helfen, Anwendungen in Kubernetes zu schützen.

Kubernetes-Netzwerkrichtlinien

Der Mechanismus der Kubernetes-Netzwerkrichtlinien ermöglicht die Verwaltung der Interaktionen der auf der Plattform bereitgestellten Anwendungen auf Netzwerkebene (Schicht drei im OSI-Modell). Netzwerkrichtlinien verfügen nicht über einige der fortschrittlichen Funktionen moderner Firewalls, wie etwa die Kontrolle auf OSI-Schicht 7 und Bedrohungserkennung, bieten jedoch ein grundlegendes Maß an Netzwerksicherheit, das einen soliden Ausgangspunkt darstellt.

Netzwerkrichtlinien steuern die Kommunikation zwischen Pods

Arbeitslasten in Kubernetes werden auf Pods verteilt, die aus einem oder mehreren Containern bestehen, die gemeinsam bereitgestellt werden. Kubernetes weist jedem Pod eine IP-Adresse zu, die von anderen Pods zugänglich ist. Die Netzwerkrichtlinien von Kubernetes legen die Zugriffsrechte für Gruppen von Pods ähnlich fest, wie Sicherheitgruppen in der Cloud verwendet werden, um den Zugriff auf Instanzen virtueller Maschinen zu verwalten.

Definition von Netzwerk-Richtlinien

Wie andere Kubernetes-Ressourcen werden Netzwerk-Richtlinien in YAML definiert. Im folgenden Beispiel wird der Anwendung balance Zugriff auf in einer Umgebung, in der die Locale nicht UTF-8 ist, beispielsweise in einer leeren Umgebung (hier:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default.postgres
  namespace: default
spec:
  podSelector:
    matchLabels:
      app: postgres
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: balance
  policyTypes:
  - Ingress

Einführung in die Netzwerkrichtlinien von Kubernetes für Sicherheitsexperten

(Anmerkung des Übersetzers.: Dieses Screenshot, wie alle folgenden ähnlichen, wurde nicht mit den nativen Mitteln von Kubernetes erstellt, sondern mit dem Tool Tufin Orca, dessen Entwicklung von dem Unternehmen hinter dem ursprünglichen Artikel stammt und das am Ende des Materials erwähnt wird.

Um eine eigene Netzwerk-Richtlinie zu definieren, sind grundlegende Kenntnisse in YAML erforderlich. Diese Sprache basiert auf Einrückungen (die mit Leerzeichen anstelle von Tabulatoren angegeben werden). Ein Element mit einer Einrückung gehört zum nächsten übergeordneten Element mit einer Einrückung. Ein neues Listenelement beginnt mit einem Bindestrich, während alle anderen Elemente wie folgt aussehen: von Schlüssel-Wert-Paaren.

Nachdem Sie die Richtlinie in YAML beschrieben haben, verwenden Sie kubectl, um sie im Cluster zu erstellen:

kubectl create -f policy.yaml

Spezifikation der Netzwerk-Richtlinie

Die Spezifikation der Netzwerk-Richtlinie von Kubernetes umfasst vier Elemente:

  1. podSelector: definiert die Pods, die von dieser Richtlinie betroffen sind (Ziele) – obligatorisch;
  2. policyTypes: gibt an, welche Arten von Richtlinien in dieser enthalten sind: ingress und/oder egress – optional, ich empfehle jedoch, dies in allen Fällen ausdrücklich anzugeben;
  3. ingress: definiert den erlaubten eingehenden Datenverkehr zu den Ziel-Pods – optional;
  4. egress: definiert den erlaubten ausgehenden Datenverkehr aus den Ziel-Pods – optional.

Ein Beispiel, das von der Kubernetes-Website entnommen wurde (ich habe role auf App), zeigt, wie alle vier Elemente verwendet werden:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: test-network-policy
  namespace: default
spec:
  podSelector:    # <<<
    matchLabels:
      app: db
  policyTypes:    # <<<
  - Ingress
  - Egress
  ingress:        # <<<
  - from:
    - ipBlock:
        cidr: 172.17.0.0/16
        except:
        - 172.17.1.0/24
    - namespaceSelector:
        matchLabels:
          project: myproject
    - podSelector:
        matchLabels:
          role: frontend
    ports:
    - protocol: TCP
      port: 6379
  egress:         # <<<
  - to:
    - ipBlock:
        cidr: 10.0.0.0/24
    ports:
    - protocol: TCP
      port: 5978

Einführung in die Netzwerkrichtlinien von Kubernetes für Sicherheitsexperten
Einführung in die Netzwerkrichtlinien von Kubernetes für Sicherheitsexperten

Bitte beachten Sie, dass nicht alle vier Elemente zwingend erforderlich sind. Nur podSelectorist notwendig, die anderen Parameter können nach Bedarf verwendet werden.

Wenn Sie weglassen policyTypes, wird die Richtlinie wie folgt interpretiert:

  • Standardmäßig wird davon ausgegangen, dass sie die Ingress-Seite definiert. Wenn in der Richtlinie keine ausdrücklichen Hinweise gegeben werden, wird das System annehmen, dass der gesamte Verkehr verboten ist.
  • Das Verhalten auf der Egress-Seite wird durch das Vorhandensein oder Fehlen des entsprechenden Egress-Parameters bestimmt.

Um Fehler zu vermeiden, empfehle ich immer ausdrücklich anzugeben policyTypes.

Gemäß der obigen Logik wird, falls die Parameter ingress und/oder egress weggelassen werden, die Richtlinie den gesamten Verkehr verbieten (siehe "Aufräumregel" unten).

Standardrichtlinie — erlauben

Wenn keine Richtlinien definiert sind, erlaubt Kubernetes standardmäßig den gesamten Verkehr. Alle Pods können frei Informationen austauschen. Aus Sicht der Sicherheit mag das unlogisch erscheinen, aber denken Sie daran, dass Kubernetes ursprünglich von Entwicklern erstellt wurde, um die Interoperabilität von Anwendungen zu gewährleisten. Netzwerkrichtlinien wurden später hinzugefügt.

Namespaces

Namespaces (Namespaces) sind ein Mechanismus für die Zusammenarbeit in Kubernetes. Sie sind dazu gedacht, logische Umgebungen voneinander zu isolieren, während der Datenaustausch zwischen Namespaces standardmäßig erlaubt ist.

Wie die meisten Komponenten von Kubernetes befinden sich Netzwerkrichtlinien in einem bestimmten Namespace. Im Block in der Ressourcenspezifikation des Pods. Genauere Informationen finden Sie im kann angegeben werden, welchem Namespace die Richtlinie angehört:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: test-network-policy
  namespace: my-namespace  # <<<
spec:
...

Wenn der Namespace in den Metadaten nicht ausdrücklich angegeben ist, verwendet das System den Namespace, der in kubectl angegeben ist (standardmäßig namespace=default):

kubectl apply -n my-namespace -f namespace.yaml

Ich empfehle den Namespace ausdrücklich anzugeben, es sei denn, Sie schreiben Richtlinien, die für mehrere Namensräume gleichzeitig vorgesehen sind.

Haupt Element podSelector in der Richtlinie wählt Pods aus dem Namensraum aus, zu dem die Richtlinie gehört (es hat keinen Zugriff auf Pods aus einem anderen Namensraum).

In ähnlicher Weise können podSelector in den ingress- und egress-Blöcken nur Pods aus ihrem eigenen Namensraum auswählen, es sei denn, Sie verbinden sie mit (darüber wird im Abschnitt 'Filter nach Namensräumen und Pods' gesprochen). namespaceSelector Namensregeln für Richtlinien

Die Namen von Richtlinien sind innerhalb eines Namensraums eindeutig. Es können keine zwei Richtlinien mit demselben Namen im gleichen Namensraum existieren, aber es können Richtlinien mit denselben Namen in verschiedenen Namensräumen vorhanden sein. Dies ist praktisch, wenn Sie dieselbe Richtlinie auf mehreren Namensräumen anwenden möchten.

Ich mag besonders eine der Namenskonventionen. Sie besteht darin, den Namen des Namensraums mit den Ziel-Pods zu kombinieren. Zum Beispiel:

apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: default.postgres # <<< namespace: default spec: podSelector: matchLabels: app: postgres ingress: - from: - podSelector: matchLabels: app: admin policyTypes: - Ingress

Labels

Einführung in die Netzwerkrichtlinien von Kubernetes für Sicherheitsexperten

Benutzerdefinierte Labels können an Kubernetes-Objekte wie Pods und Namensräume angehängt werden. Labels (

— Tags) sind das Äquivalent zu Tags in der Cloud. Kubernetes-Netzwerkrichtlinien verwenden Labels, um auszuwählenlabels , auf die sie angewendet werden: PodspodSelector: matchLabels: role: db

… oder

Namensräume , auf die sie angewendet werden. In diesem Beispiel werden alle Pods in den Namensräumen mit den entsprechenden Labels ausgewählt:namespaceSelector: matchLabels: project: myproject

Eine Warnung: Bei der Verwendung von

stellen Sie sicher, dass die ausgewählten Namensräume das benötigte Label enthalten namespaceSelector . Bedenken Sie, dass die eingebauten Namensräume wie, standardmäßig keine Labels enthalten. default und kube-systemEin Label zu einem Namensraum kann wie folgt hinzugefügt werden:

kubectl label namespace default namespace=default

Dabei muss der Namensraum im Abschnitt

auf den tatsächlichen Namen des Namensraums und nicht auf das Label verweisen: in der Ressourcenspezifikation des Pods. Genauere Informationen finden Sie im apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: test-network-policy namespace: default # <<< spec: ...

Quelle und Empfänger

Quelle und Empfänger

Die Richtlinien für Firewalls bestehen aus Regeln mit Quellen und Zielen. Netzwerkrichtlinien in Kubernetes werden für das Ziel festgelegt – eine Gruppe von Pods, auf die sie angewendet werden, und legen dann Regeln für eingehenden (Ingress) und/oder ausgehenden (Egress) Datenverkehr fest. In unserem Beispiel ist das Ziel der Richtlinie, alle Pods im Namensraum default mit einem Label mit dem Schlüssel App und mit dem Wert. db:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: test-network-policy
  namespace: default
spec:
  podSelector:
    matchLabels:
      app: db   # <<<
  policyTypes:
  - Ingress
  - Egress
  ingress:
  - from:
    - ipBlock:
        cidr: 172.17.0.0/16
        except:
        - 172.17.1.0/24
    - namespaceSelector:
        matchLabels:
          project: myproject
    - podSelector:
        matchLabels:
          role: frontend
    ports:
    - protocol: TCP
      port: 6379
  egress:
  - to:
    - ipBlock:
        cidr: 10.0.0.0/24
    ports:
    - protocol: TCP
      port: 5978

Einführung in die Netzwerkrichtlinien von Kubernetes für Sicherheitsexperten
Einführung in die Netzwerkrichtlinien von Kubernetes für Sicherheitsexperten

Unterabschnitt ingress in dieser Richtlinie öffnet den eingehenden Datenverkehr zu den Ziel-Pods. Mit anderen Worten, der Ingress fungiert als Quelle, und das Ziel ist der entsprechende Empfänger. Ebenso ist Egress der Empfänger, und das Ziel ist seine Quelle.

Einführung in die Netzwerkrichtlinien von Kubernetes für Sicherheitsexperten

Dies entspricht zwei Regeln für die Firewall: Ingress → Ziel; Ziel → Egress.

Egress und DNS (wichtig!)

Wenn Sie den ausgehenden Datenverkehr einschränken, achten Sie besonders auf DNS – Kubernetes verwendet diesen Dienst, um Dienste mit IP-Adressen zu verknüpfen. Zum Beispiel wird die folgende Richtlinie nicht funktionieren, da Sie dem Programm nicht erlaubt haben, balance auf DNS zuzugreifen:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default.balance
  namespace: default
spec:
  podSelector:
    matchLabels:
      app: balance
  egress:
  - to:
    - podSelector:
        matchLabels:
          app: postgres
  policyTypes:
  - Egress

Einführung in die Netzwerkrichtlinien von Kubernetes für Sicherheitsexperten

Sie können sie beheben, indem Sie den Zugriff auf den DNS-Dienst öffnen:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default.balance
  namespace: default
spec:
  podSelector:
    matchLabels:
      app: balance
  egress:
  - to:
    - podSelector:
        matchLabels:
          app: postgres
  - to:               # <<<
    ports:            # <<<
    - protocol: UDP   # <<<
      port: 53        # <<<
  policyTypes:
  - Egress

Einführung in die Netzwerkrichtlinien von Kubernetes für Sicherheitsexperten

Das letzte Element to ist leer und wählt daher indirekt alle Pods in allen Namensräumen, erlaubt balance das Senden von DNS-Anfragen an den entsprechenden Kubernetes-Dienst (normalerweise läuft dieser im Namensraum kube-system).

Dieser Ansatz funktioniert, jedoch ist übermäßig großzügig und unsicher, da er es erlaubt, DNS-Anfragen außerhalb des Clusters zu senden.

Sie können ihn durch drei aufeinanderfolgende Schritte verbessern.

1. Erlauben Sie DNS-Anfragen nur innerhalb zum Cluster, indem Sie hinzufügen namespaceSelector:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default.balance
  namespace: default
spec:
  podSelector:
    matchLabels:
      app: balance
  egress:
  - to:
    - podSelector:
        matchLabels:
          app: postgres
  - to:
    - namespaceSelector: {} # <<<
    ports:
    - protocol: UDP
      port: 53
  policyTypes:
  - Egress

Einführung in die Netzwerkrichtlinien von Kubernetes für Sicherheitsexperten

2. Erlaube DNS-Anfragen nur im Namensraum kube-system.

Dafür muss ein Label im Namensraum hinzugefügt werden kube-system: kubectl label namespace kube-system namespace=kube-system — und es in der Richtlinie festgelegt werden durch namespaceSelector:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default.balance
  namespace: default
spec:
  podSelector:
    matchLabels:
      app: balance
  egress:
  - to:
    - podSelector:
        matchLabels:
          app: postgres
  - to:
    - namespaceSelector:         # <<<
        matchLabels:             # <<<
          namespace: kube-system # <<<
    ports:
    - protocol: UDP
      port: 53
  policyTypes:
  - Egress

Einführung in die Netzwerkrichtlinien von Kubernetes für Sicherheitsexperten

3. Paranoide können noch weiter gehen und DNS-Anfragen auf einen bestimmten DNS-Dienst in kube-system. Im Abschnitt „Filter nach Namensräumen und Pods“ wird erklärt, wie dies erreicht werden kann.

Eine andere Möglichkeit besteht darin, DNS auf Namensraum-Ebene zu erlauben. In diesem Fall muss es nicht für jeden Dienst geöffnet werden:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default.dns
  namespace: default
spec:
  podSelector: {} # <<<
  egress:
  - to:
    - namespaceSelector: {}
    ports:
    - protocol: UDP
      port: 53
  policyTypes:
  - Egress

Leer podSelector wählt alle Pods im Namensraum aus.

Einführung in die Netzwerkrichtlinien von Kubernetes für Sicherheitsexperten

Erste Übereinstimmung und Reihenfolge der Regeln

In herkömmlichen Firewalls wird die Aktion ("Erlauben" oder "Verweigern") in Bezug auf ein Paket durch die erste Regel bestimmt, die es erfüllt. In Kubernetes hat die Reihenfolge der Richtlinien keine Bedeutung.

Standardmäßig, wenn keine Richtlinien definiert sind, sind die Kommunikationen zwischen Pods erlaubt und sie können Informationen frei austauschen. Sobald Sie jedoch beginnen, Richtlinien zu formulieren, wird jeder Pod, der von einer der Richtlinien betroffen ist, isoliert gemäß der Disjunktion (logisches ODER) aller Richtlinien, die ihn ausgewählt haben. Pods, die von keiner Richtlinie betroffen sind, bleiben offen.

Sie können ein solches Verhalten durch eine Bereinigungsregel ändern.

Die Bereinigungsregel ("Verweigern")

Firewalls-Richtlinien verbieten in der Regel jeglichen ausdrücklich nicht erlaubten Datenverkehr.

In Kubernetes gibt es keine Aktion „verweigern“ (deny),aber ein ähnlicher Effekt kann durch eine herkömmliche (erlaubende) Richtlinie erzielt werden, indem eine leere Quelle-Pod-Gruppe (ingress) ausgewählt wird:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: deny-all
  namespace: default
spec:
  podSelector: {}
  policyTypes:
  - Ingress

Einführung in die Netzwerkrichtlinien von Kubernetes für Sicherheitsexperten

Diese Richtlinie wählt alle Pods im Namensraum aus und lässt den Ingress undefiniert, wodurch der gesamte eingehende Verkehr blockiert wird.

Ähnlich kann der gesamte ausgehende Verkehr aus dem Namensraum eingeschränkt werden:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: deny-all-egress
  namespace: default
spec:
  podSelector: {}
  policyTypes:
  - Egress

Einführung in die Netzwerkrichtlinien von Kubernetes für Sicherheitsexperten

Bitte beachten Sie, dass alle zusätzlichen Richtlinien, die den Verkehr zu Pods im Namensraum erlauben, Vorrang vor dieser Regel haben werden (ähnlich wie das Hinzufügen einer erlaubenden Regel vor einer verbietenden in einer Firewall-Konfiguration).

Erlaube alles (Any-Any-Any-Allow)

Um eine „Erlaube alles“-Richtlinie zu erstellen, muss die oben angegebene verbietende Richtlinie um ein leeres Element ergänzt werden. ingress:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-all
  namespace: default
spec:
  podSelector: {}
  ingress: # >>>
  - {}     # >>>
  policyTypes:
  - Ingress

Einführung in die Netzwerkrichtlinien von Kubernetes für Sicherheitsexperten

Sie öffnet den Zugang von allen Pods in allen Namensräumen (und allen IPs) zu jedem Pod im Namensraum default. Ein solches Verhalten ist standardmäßig aktiviert, sodass es normalerweise nicht zusätzlich definiert werden muss. In bestimmten Fällen kann es jedoch erforderlich sein, einige spezifische Berechtigungen vorübergehend zu deaktivieren, um ein Problem zu diagnostizieren.

Die Regel kann eingeschränkt werden, um den Zugang nur zu einer bestimmten Gruppe von Pods (app:balance) im Namensraum default:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-all-to-balance
  namespace: default
spec:
  podSelector:
    matchLabels:
      app: balance
  ingress: 
  - {}
  policyTypes:
  - Ingress

Einführung in die Netzwerkrichtlinien von Kubernetes für Sicherheitsexperten

Die folgende Richtlinie erlaubt gesamten eingehenden (Ingress) und ausgehenden (Egress) Verkehr, einschließlich Zugriff auf jede IP außerhalb des Clusters:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-all
spec:
  podSelector: {}
  ingress:
  - {}
  egress:
  - {}
  policyTypes:
  - Ingress
  - Egress

Einführung in die Netzwerkrichtlinien von Kubernetes für Sicherheitsexperten
Einführung in die Netzwerkrichtlinien von Kubernetes für Sicherheitsexperten

Kombination mehrerer Richtlinien

Richtlinien werden auf drei Ebenen mit logischem ODER kombiniert; die Berechtigungen jedes Pods werden entsprechend der Disjunktion aller Richtlinien, die ihn betreffen, festgelegt:

1. In den Feldern from und to können drei Typen von Elementen definiert werden (alle werden mit ODER kombiniert):

  • namespaceSelector — wählt den Namensraum vollständig aus;
  • podSelector — wählt Pods aus;
  • ipBlock — wählt ein Subnetz aus.

Dabei ist die Anzahl der Elemente (auch wenn sie gleich sind) in den Unterabschnitten from/to nicht begrenzt. Alle werden mit logischem ODER kombiniert.

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default.postgres
  namespace: default
spec:
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: indexer
    - podSelector:
        matchLabels:
          app: admin
  podSelector:
    matchLabels:
      app: postgres
  policyTypes:
  - Ingress

Einführung in die Netzwerkrichtlinien von Kubernetes für Sicherheitsexperten

2. Innerer Abschnitt der Richtlinie ingress kann mehrere Elemente enthalten from (die logisch mit ODER kombiniert werden). Entsprechend kann der Abschnitt egress mehrere Elemente umfassen to (die ebenfalls mit ODER kombiniert werden):

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default.postgres
  namespace: default
spec:
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: indexer
  - from:
    - podSelector:
        matchLabels:
          app: admin
  podSelector:
    matchLabels:
      app: postgres
  policyTypes:
  - Ingress

Einführung in die Netzwerkrichtlinien von Kubernetes für Sicherheitsexperten

3. Verschiedene Richtlinien werden ebenfalls logisch mit ODER kombiniert

Aber bei ihrer Kombination gibt es eine Einschränkung, auf die wies darauf hin Chris Cooney: Kubernetes kann Richtlinien nur mit verschiedenen policyTypes (Ingress oder Egress). Richtlinien, die ingress (oder egress) definieren, überschreiben sich gegenseitig.

Kommunikation zwischen Namespaces

Standardmäßig ist der Informationsaustausch zwischen Namespaces erlaubt. Dies kann durch eine verbietende Richtlinie geändert werden, die den ausgehenden und/oder eingehenden Datenverkehr zu einem Namespace einschränkt (siehe oben "Bereinigungsvorschrift").

Wenn Sie den Zugriff auf einen Namespace blockieren (siehe oben "Bereinigungsvorschrift"), können Sie Ausnahmen in der verbietenden Richtlinie vornehmen, indem Sie Verbindungen von einem bestimmten Namespace über namespaceSelector:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: database.postgres
  namespace: database
spec:
  podSelector:
    matchLabels:
      app: postgres
  ingress:
  - from:
    - namespaceSelector: # <<<
        matchLabels:
          namespace: default
  policyTypes:
  - Ingress

Einführung in die Netzwerkrichtlinien von Kubernetes für Sicherheitsexperten

Infolgedessen haben alle Pods im Namespace default Zugriff auf Pods in einer Umgebung, in der die Locale nicht UTF-8 ist, beispielsweise in einer leeren Umgebung (hier im Namensraum database. Aber was, wenn Sie den Zugriff auf in einer Umgebung, in der die Locale nicht UTF-8 ist, beispielsweise in einer leeren Umgebung (hier nur bestimmte Pods im Namespace öffnen möchten? default?

Filter nach Namespaces und Pods

Kubernetes Version 1.11 und höher ermöglicht die Kombination von Operatoren namespaceSelector und podSelector mit logischem UND. So sieht das aus:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: database.postgres
  namespace: database
spec:
  podSelector:
    matchLabels:
      app: postgres
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          namespace: default
      podSelector: # <<<
        matchLabels:
          app: admin
  policyTypes:
  - Ingress

Einführung in die Netzwerkrichtlinien von Kubernetes für Sicherheitsexperten

Warum wird das als UND statt als gewohnt ODER interpretiert?

Beachten Sie, dass podSelector beginnt nicht mit einem Bindestrich. In YAML bedeutet dies, dass podSelector und das davor stehende namespaceSelector zu demselben Listelement gehören. Daher werden sie logisch mit UND kombiniert.

Das Hinzufügen eines Bindestrichs davor podSelector führt zur Entstehung eines neuen Listenelements, das mit dem vorhergehenden kombiniert wird namespaceSelector mittels logischem ODER.

Um Pods mit einem bestimmten Label auszuwählen in allen Namensräumen, geben Sie leer ein namespaceSelector:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: database.postgres
  namespace: database
spec:
  podSelector:
    matchLabels:
      app: postgres
  ingress:
  - from:
    - namespaceSelector: {}
      podSelector:
        matchLabels:
          app: admin
  policyTypes:
  - Ingress

Einführung in die Netzwerkrichtlinien von Kubernetes für Sicherheitsexperten

Mehrere Labels werden mit UND kombiniert

Regeln für Firewalls mit mehreren Objekten (Hosts, Netzwerken, Gruppen) werden mittels logischem ODER kombiniert. Die folgende Regel tritt in Kraft, wenn die Quelladresse des Pakets übereinstimmt mit Host_1 ODER Host_2:

| Quelle | Ziel | Dienst | Aktion |
| ----------------------------------------|
| Host_1 | Subnetz_A    | HTTPS   | Erlauben  |
| Host_2 |             |         |        |
| ----------------------------------------|

Im Gegensatz dazu werden in Kubernetes verschiedene Labels in podSelector oder namespaceSelector logischem UND kombiniert. Zum Beispiel wählt die folgende Regel Pods aus, die beide Labels besitzen, role=db Und version=v2:

podSelector:
  matchLabels:
    role: db
    version: v2

Die gleiche Logik gilt für alle Typen von Operatoren: Zielpolicy-Selektoren, Pod-Selektoren und Namensraumselektoren.

Subnetze und IP-Adressen (IPBlocks)

Zur Segmentierung des Netzwerks verwenden Firewalls VLANs, IP-Adressen und Subnetze.

In Kubernetes werden IP-Adressen automatisch Pods zugewiesen und können sich häufig ändern, daher werden Labels zur Auswahl von Pods und Namensräumen in Netzwerkpolitiken verwendet.

Subnetze (ipBlocks) werden zur Verwaltung eingehender (Ingress) oder ausgehender (Egress) externer (North-South) Verbindungen verwendet. Diese Politik gewährt beispielsweise allen Pods im Namensraum default Zugriff auf den DNS-Dienst von Google:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: egress-dns
  namespace: default
spec:
  podSelector: {}
  policyTypes:
  - Egress
  egress:
  - to:
    - ipBlock:
        cidr: 8.8.8.8/32
    ports:
    - protocol: UDP
      port: 53

Einführung in die Netzwerkrichtlinien von Kubernetes für Sicherheitsexperten

Ein leerer Pod-Selector in diesem Beispiel bedeutet „alle Pods im Namensraum auswählen“.

Diese Politik erlaubt nur den Zugriff auf 8.8.8.8; der Zugriff auf jede andere IP ist verboten. Damit haben Sie effektiv den Zugriff auf den internen Kubernetes-DNS-Service blockiert. Wenn Sie diesen dennoch gewähren möchten, geben Sie dies ausdrücklich an.

Normalerweise ipBlocks und podSelectors sind sich gegenseitig ausschließend, da interne IP-Adressen von Pods nicht in ipBlocksverwendet werden. Indem Sie interne IPs von Pods angeben, Sie erlauben praktisch Verbindungen zu/von Pods mit diesen Adressen. In der Praxis werden Sie nicht wissen, welche IP-Adresse verwendet werden soll, daher sollten sie nicht zur Auswahl von Pods verwendet werden.

Als Gegenbeispiel enthält die folgende Richtlinie alle IPs und erlaubt somit den Zugriff auf alle anderen Pods:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: egress-any
  namespace: default
spec:
  podSelector: {}
  policyTypes:
  - Egress
  egress:
  - to:
    - ipBlock:
        cidr: 0.0.0.0/0

Einführung in die Netzwerkrichtlinien von Kubernetes für Sicherheitsexperten

Zugriff kann nur auf externe IPs gewährt werden, indem interne IP-Adressen der Pods ausgeschlossen werden. Zum Beispiel, wenn das Subnetz Ihres Pods 10.16.0.0/14 ist:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: egress-any
  namespace: default
spec:
  podSelector: {}
  policyTypes:
  - Egress
  egress:
  - to:
    - ipBlock:
        cidr: 0.0.0.0/0
        except:
        - 10.16.0.0/14

Einführung in die Netzwerkrichtlinien von Kubernetes für Sicherheitsexperten

Ports und Protokolle

Normalerweise hören Pods auf einem Port. Das bedeutet, dass Sie die Portnummern in den Richtlinien einfach weglassen und alles auf die Standardeinstellungen belassen können. Es wird jedoch empfohlen, die Richtlinien möglichst restriktiv zu gestalten, daher können in einigen Fällen auch Ports angegeben werden:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default.postgres
  namespace: default
spec:
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: indexer
    - podSelector:
        matchLabels:
          app: admin
    ports:             # <<<
      - port: 443      # <<<
        protocol: TCP  # <<<
      - port: 80       # <<<
        protocol: TCP  # <<<
  podSelector:
    matchLabels:
      app: postgres
  policyTypes:
  - Ingress

Einführung in die Netzwerkrichtlinien von Kubernetes für Sicherheitsexperten

Beachten Sie, dass der Selektor ports auf alle Elemente im Block angewendet wird, to oder from, in dem er sich befindet. Um verschiedene Ports für unterschiedliche Elementgruppen anzugeben, teilen Sie ingress oder egress in mehrere Unterabschnitte auf mit to oder from und geben Sie in jedem Ihre Ports an:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default.postgres
  namespace: default
spec:
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: indexer
    ports:             # <<<
     - port: 443       # <<<
       protocol: TCP   # <<<
  - from:
    - podSelector:
        matchLabels:
          app: admin
    ports:             # <<<
     - port: 80        # <<<
       protocol: TCP   # <<<
  podSelector:
    matchLabels:
      app: postgres
  policyTypes:
  - Ingress

Einführung in die Netzwerkrichtlinien von Kubernetes für Sicherheitsexperten

Standardmäßige Portverarbeitung:

  • Wenn Sie die Portdefinitionen vollständig weglassen (ports), bedeutet dies alle Protokolle und alle Ports;
  • Wenn Sie die Protokolldefinition weglassen (protocol), bedeutet dies TCP;
  • Wenn Sie die Portdefinition weglassen (port), bedeutet dies alle Ports.

Beste Praxis: Verlassen Sie sich nicht auf Standardwerte, geben Sie die benötigten Werte eindeutig an.

Bitte beachten Sie, dass Sie die Ports der Pods und nicht die der Dienste verwenden müssen (nähere Informationen dazu im nächsten Absatz).

Sind die Richtlinien für Pods oder Dienste definiert?

Normalerweise kommunizieren Pods in Kubernetes über einen Dienst — einen virtuellen Lastenausgleicher, der den Datenverkehr zu den Pods umleitet, die den Dienst implementieren. Man könnte denken, dass Netzwerkrichtlinien den Zugang zu Diensten kontrollieren, aber das ist nicht der Fall. Netzwerkrichtlinien in Kubernetes arbeiten mit den Ports der Pods und nicht mit denen der Dienste.

Wenn ein Dienst beispielsweise den Port 80 abhört, aber den Datenverkehr auf Port 8080 seiner Pods umleitet, muss in der Netzwerkrichtlinie genau 8080 angegeben werden.

Ein solches Verfahren wird als suboptimal angesehen: Bei Änderungen an der internen Struktur des Dienstes (dessen Ports von den Pods abgehört werden) müssen die Netzwerkrichtlinien aktualisiert werden.

Ein neuer architektonischer Ansatz mit Service Mesh (z. B. siehe weiter unten zu Istio — Anm. d. Übers.) löst dieses Problem.

Muss man sowohl Ingress als auch Egress angeben?

Die kurze Antwort lautet: Ja, damit Pod A mit Pod B kommunizieren kann, muss ihm erlaubt werden, eine ausgehende Verbindung zu erstellen (dazu muss die Egress-Richtlinie konfiguriert werden), und Pod B muss in der Lage sein, eine eingehende Verbindung zu akzeptieren (dazu ist entsprechend eine Ingress-Richtlinie erforderlich).

In der Praxis kann jedoch oft auf die Standardrichtlinie zurückgegriffen werden, die Verbindungen in einer oder beiden Richtungen zulässt.

Wenn ein Pod-Quelle von einer oder mehreren egress-Richtlinien ausgewählt wird, werden die ihm auferlegten Beschränkungen durch ihre Disjunktion bestimmt. In diesem Fall muss der Zugriff auf den Pod-Zielausdrücklich gewährt werden. Wenn ein Pod von keiner Richtlinie ausgewählt wird, ist der ausgehende (Egress) Datenverkehr standardmäßig erlaubt.

In ähnlicher Weise wird das Schicksal des Pod-Ziel, der von einer oder mehreren ingress-Richtlinien ausgewählt wird, durch deren Disjunktion bestimmt. In diesem Fall muss ihm ausdrücklich gestattet werden, Datenverkehr von dem Pod-Quelle zu empfangen. Wenn ein Pod von keiner Richtlinie ausgewählt wird, ist der gesamte eingehende (Ingress) Datenverkehr für ihn standardmäßig erlaubt.

Siehe Punkt „Stateful oder Stateless“ weiter unten.

Logs

Netzwerkrichtlinien in Kubernetes können den Datenverkehr nicht protokollieren. Dies erschwert die Feststellung, ob eine Richtlinie ordnungsgemäß funktioniert, und macht die Sicherheitsanalyse deutlich komplizierter.

Die Kontrolle des Datenverkehrs zu externen Diensten

Die Kubernetes-Netzwerk-Richtlinien erlauben es nicht, einen vollwertigen Domainnamen (DNS) in den Egress-Abschnitten anzugeben. Diese Tatsache führt zu erheblichen Unannehmlichkeiten, wenn man versucht, den Datenverkehr zu externen Adressen, die keine feste IP-Adresse haben (wie aws.com), zu beschränken.

Richtlinienprüfung

Firewalls warnen Sie oder lehnen sogar ab, fehlerhafte Richtlinien zu akzeptieren. Auch Kubernetes führt einige Überprüfungen durch. Wenn eine Netzwerk-Richtlinie über kubectl festgelegt wird, kann Kubernetes angeben, dass sie ungültig ist und die Annahme verweigern. In anderen Fällen akzeptiert Kubernetes die Richtlinie und ergänzt sie mit fehlenden Details. Diese können Sie mit dem Befehl einsehen:

kubernetes get networkpolicy  -o yaml

Bitte beachten Sie, dass das Prüfssystem von Kubernetes nicht fehlerfrei ist und bestimmte Arten von Fehlern übersehen kann.

Implementierung

Kubernetes selbst implementiert keine Netzwerk-Richtlinien, sondern fungiert lediglich als API-Gateway, das die lästige Aufgabe der Kontrolle auf das zugrunde liegende System, das als Container Networking Interface (CNI) bezeichnet wird, überträgt. Das Festlegen von Richtlinien in einem Kubernetes-Cluster ohne die Zuweisung des entsprechenden CNI ist vergleichbar mit dem Erstellen von Richtlinien auf einem Firewall-Management-Server, ohne diese anschließend in die Firewalls zu implementieren. Sie müssen selbst sicherstellen, dass ein adäquates CNI vorhanden ist oder, bei in der Cloud gehosteten Kubernetes-Plattformen, die Netzwerk-Richtlinien aktivieren, die das CNI automatisch für Sie festlegt. (die Liste der Anbieter finden Sie hier hier — Anm. d. Ü.), aktivieren Sie die Netzwerk-Richtlinien, die das CNI für Sie festlegen.

Bitte beachten Sie, dass Kubernetes Sie nicht warnt, wenn Sie eine Netzwerk-Richtlinie ohne das entsprechende unterstützende CNI festlegen.

Stateful oder Stateless?

Alle CNI von Kubernetes, mit denen ich bisher zu tun hatte, speichern den Zustand (zum Beispiel verwendet Calico Linux conntrack). Dies ermöglicht es einem Pod, Antworten auf die von ihm initiierten TCP-Verbindungen zu erhalten, ohne diese neu aufbauen zu müssen. Mir ist jedoch kein Kubernetes-Standard bekannt, der die Speicherung des Zustands (Statefulness) garantiert.

Erweiterte Sicherheitsrichtlinienverwaltung

Hier sind einige Möglichkeiten, die Effektivität der Umsetzung von Sicherheitsrichtlinien in Kubernetes zu verbessern:

  1. Das architektonische Muster Service Mesh verwendet Sidecar-Container, um umfassende Telemetrie und Kontrolle über den Datenverkehr auf der Service-Ebene bereitzustellen. Ein Beispiel könnte sein Istio.
  2. Einige der CNI-Anbieter haben ihre Tools erweitert, sodass sie über die Netzwerkrichtlinien von Kubernetes hinausgehen.
  3. Tufin Orca bietet Transparenz und Automatisierung der Netzwerkrichtlinien von Kubernetes.

Das Tufin Orca-Paket verwaltet die Netzwerkrichtlinien von Kubernetes (und dient als Quelle für die oben gezeigten Screenshots).

Zusätzliche Informationen

Fazit

Die Netzwerkrichtlinien von Kubernetes bieten eine ansprechende Reihe von Werkzeugen zur Segmentierung von Clustern, sind jedoch nicht intuitiv und weisen zahlreiche Feinheiten auf. Ich bin der Meinung, dass aufgrund dieser Komplexität viele bestehende Cluster fehlerhaft konfiguriert sind. Mögliche Lösungen für dieses Problem sind die Automatisierung von Richtlinieneinstellungen oder die Anwendung anderer Segmentierungswerkzeuge.

Ich hoffe, dass dieser Leitfaden dazu beiträgt, einige Fragen zu klären und Probleme zu lösen, auf die Sie möglicherweise stoßen.

P.S. vom Übersetzer

Lesen Sie auch in unserem Blog:

Quelle: habr.com

60GB SSD 8Gb DDR4