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

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

Hinweis.: Der Autor des Artikels, Reuven Harrison, bringt über 20 Jahre Erfahrung in der Softwareentwicklung mit und ist derzeit technischer Direktor und Mitgründer von Tufin, einem Unternehmen, das Lösungen zur Verwaltung von Sicherheitsrichtlinien entwickelt. Während er Kubernetes-Netzwerkrichtlinien als ein kraftvolles Mittel zur Netzwerksegmentierung innerhalb von Clustern sieht, ist er gleichzeitig der Meinung, dass deren praktische Anwendung nicht so einfach ist. Dieser umfangreiche Beitrag soll das Bewusstsein der Fachleute zu diesem Thema schärfen und ihnen helfen, die erforderlichen Konfigurationen zu erstellen.

Heute entscheiden sich immer mehr Unternehmen dafür, Kubernetes zur Ausführung ihrer Anwendungen zu nutzen. Das Interesse an dieser Software ist so groß, dass manche Kubernetes als "das neue Betriebssystem für Rechenzentren" bezeichnen. Allmählich wird Kubernetes (oder k8s) als eine kritische Komponente für Unternehmen wahrgenommen, die eine reife Organisation der Geschäftsprozesse erfordert, einschließlich der Gewährleistung der Netzwerksicherheit.

Für Sicherheitsexperten, die sich mit Kubernetes auseinandersetzen, kann die Standardpolitik dieser Plattform eine echte Offenbarung sein: alles zuzulassen.

Dieses Handbuch hilft, die inneren Abläufe der Netzwerkpolitiken zu verstehen und die Unterschiede zu den Regeln herkömmlicher Firewalls zu erkennen. Außerdem werden einige Fallstricke beleuchtet und Empfehlungen gegeben, die helfen, Anwendungen in Kubernetes zu schützen.

Netzwerkpolitiken von Kubernetes

Der Mechanismus der Netzwerkpolitiken von Kubernetes ermöglicht die Steuerung der Interaktion von in der Plattform bereitgestellten Anwendungen auf Netzwerkschicht (der dritten Schicht im OSI-Modell). Netzwerkpolitiken bieten nicht die erweiterten Funktionen moderner Firewalls, wie etwa die Kontrolle auf Schicht 7 des OSI-Modells und Bedrohungserkennung, gewährleisten jedoch ein grundlegendes Maß an Netzwerksicherheit, das einen guten Ausgangspunkt darstellt.

Netzwerkpolitiken steuern die Kommunikation zwischen Pods.

Kubernetes verteilt Arbeitslasten auf Pods, die aus einem oder mehreren Container bestehen, die gemeinsam bereitgestellt werden. Kubernetes weist jedem Pod eine IP-Adresse zu, die von anderen Pods erreichbar ist. Die Netzwerkrichtlinien von Kubernetes legen den Zugriff für Gruppen von Pods fest, ähnlich wie Sicherheitgruppen in der Cloud verwendet werden, um den Zugang zu virtuellen Maschinen zu steuern.

Definition von Netzwerkrichtlinien

Wie andere Ressourcen in Kubernetes werden Netzwerkrichtlinien im YAML-Format definiert. Im folgenden Beispiel wird der Anwendung balance Zugriff gewährt auf postgres:

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 Netzwerkpolitik von Kubernetes für Sicherheitsexperten

(Hinweis.: Dieser Screenshot, wie alle folgenden ähnlichen, wurde nicht mit nativen Mitteln von Kubernetes erstellt, sondern mit dem Tool Tufin Orca, das von der Firma des Autors des Originalartikels entwickelt wurde und am Ende des Materials erwähnt wird.

Für die Festlegung der eigenen Netzwerkrichtlinien sind grundlegende Kenntnisse in YAML erforderlich. Diese Sprache basiert auf Einrückungen (die durch Leerzeichen und nicht durch Tabulatoren erstellt werden). Ein eingerücktes Element gehört zum nächstgelegenen übergeordneten Element mit einer Einrückung. Ein neues Listenelement beginnt mit einem Bindestrich, alle anderen Elemente erscheinen als Schlüssel-Wert-Paar.

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

kubectl create -f policy.yaml

Spezifikation der Netzwerkrichtlinie

Die Spezifikation der Kubernetes-Netzwerkrichtlinie umfasst vier Elemente:

  1. podSelector: definiert die Pods, die von dieser Richtlinie betroffen sind (Ziele) – verpflichtend;
  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 Traffic zu den Ziel-Pods – optional;
  4. egress: definiert den erlaubten ausgehenden Traffic von den Ziel-Pods – optional.

Ein Beispiel, das von der Kubernetes-Website entnommen wurde (ich habe role findet man 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 Netzwerkpolitik von Kubernetes für Sicherheitsexperten
Einführung in die Netzwerkpolitik von Kubernetes für Sicherheitsexperten

Bitte beachten Sie, dass das Einfügen aller vier Elemente nicht zwingend erforderlich ist. Nur podSelectorist Pflicht; die übrigen Parameter können nach Bedarf verwendet werden.

Wenn Sie weglassen policyTypes, wird die Richtlinie folgendermaßen interpretiert:

  • Standardmäßig wird angenommen, dass sie die Ingress-Seite definiert. Wenn keine expliziten Hinweise dazu in der Richtlinie enthalten sind, 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 explizit anzugeben. policyTypes.

Gemäß der oben genannten Logik wird die Richtlinie, falls die Parameter ingress und/oder egress weggelassen werden, den gesamten Verkehr blockieren (siehe "Clearance-Regel" unten).

Standardpolitik - Erlauben

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

Namespaces

Namespaces (Namensräume) sind ein Mechanismus für die Zusammenarbeit in Kubernetes. Sie dienen dazu, logische Umgebungen voneinander zu isolieren, wobei der Datenaustausch zwischen den Namensräumen standardmäßig erlaubt ist.

Wie die meisten Komponenten von Kubernetes gibt es Netzwerkrichtlinien innerhalb eines bestimmten Namensraums. Im Block metadata kann angegeben werden, zu welchem Namensraum die Richtlinie gehört:

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

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

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

Ich empfehle den Namensraum ausdrücklich anzugeben, es sei denn, Sie schreiben eine Richtlinie, die für mehrere Namespaces gleichzeitig gültig ist.

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

In ähnlicher Weise können podSelector in Ingress- und Egress-Blocks nur Pods aus ihrem eigenen Namespace auswählen, es sei denn, Sie kombinieren sie mit namespaceSelector (dies wird im Abschnitt „Filtern nach Namespaces und Pods“ behandelt).

Namensgebung von Richtlinien

Richtliniennamen sind innerhalb eines einzelnen Namespaces einzigartig. Es kann keine zwei Richtlinien mit dem gleichen Namen in einem Namespace geben, aber es kann Richtlinien mit denselben Namen in verschiedenen Namespaces geben. Dies ist praktisch, wenn Sie dieselbe Richtlinie in mehreren Namespaces wiederverwenden möchten.

Besonders gefällt mir eine der Methoden zur Namensgebung. Sie besteht darin, den Namen des Namespaces 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

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

Labels

Benutzerdefinierte Labels können an Kubernetes-Objekte wie Pods und Namespaces angeheftet werden. Labels (labels — Tags) sind das Äquivalent von Tags in der Cloud. Kubernetes-Netzwerkrichtlinien verwenden Labels zur Auswahl Pods, auf die sie angewendet werden:

podSelector:
  matchLabels:
    role: db

… oder Namespaces, auf die sie angewendet werden. In diesem Beispiel werden alle Pods in Namespaces mit den entsprechenden Labels ausgewählt:

namespaceSelector:
  matchLabels:
    project: myproject

Eine Warnung: Bei der Verwendung von namespaceSelector stellen Sie sicher, dass die ausgewählten Namespaces das erforderliche Label enthalten. Bedenken Sie, dass systemeigene Namespaces wie default und kube-system, standardmäßig keine Labels enthalten.

Ein Label kann zu einem Namespace wie folgt hinzugefügt werden:

kubectl label namespace default namespace=default

Dabei sollte der Namespace im Abschnitt metadata auf den tatsächlichen Namen des Namespaces verweisen, nicht auf das Label:

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

Quelle und Ziel

Die Richtlinien für Firewalls bestehen aus Regeln mit Quellen und Zielen. Die Netzwerkrichtlinien von Kubernetes werden für das Ziel — eine Gruppe von Pods, auf die sie angewendet werden — definiert und legen Regeln für eingehenden (Ingress) und/oder ausgehenden (Egress) Datenverkehr fest. In unserem Beispiel ist das Ziel der Richtlinie jeder Pod im Namensraum default mit dem Label mit dem Schlüssel app und 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 Netzwerkpolitik von Kubernetes für Sicherheitsexperten
Einführung in die Netzwerkpolitik von Kubernetes für Sicherheitsexperten

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

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

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

Egress und DNS (wichtig!)

Bei der Begrenzung des ausgehenden Datenverkehrs sollten Sie besonders auf DNS achten. — Kubernetes verwendet diesen Dienst, um Dienste mit IP-Adressen zu verknüpfen. Zum Beispiel wird die folgende Richtlinie nicht funktionieren, da Sie der Anwendung 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 Netzwerkpolitik von Kubernetes für Sicherheitsexperten

Sie können dies 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 Netzwerkpolitik von Kubernetes für Sicherheitsexperten

Das letzte Element zu — leer und wählt somit indirekt alle Pods in allen Namespaces, wodurch balance DNS-Anfragen an den entsprechenden Kubernetes-Dienst gesendet werden (dieser läuft normalerweise im Namespace kube-system).

Dieser Ansatz funktioniert, ist jedoch übermäßig permissiv und unsicher, da es ermöglicht, DNS-Anfragen außerhalb des Clusters zu senden.

Sie können es in drei aufeinanderfolgenden Schritten verbessern.

1. Erlauben Sie DNS-Anfragen nur innerhalb des Clusters, indem Sie 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 Netzwerkpolitik von Kubernetes für Sicherheitsexperten

2. Erlauben Sie DNS-Abfragen nur im Namespace kube-system.

Dazu muss ein Label zum Namespace hinzugefügt werden kube-system: kubectl label namespace kube-system namespace=kube-system — und es in die Richtlinie eingetragen werden 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 Netzwerkpolitik von Kubernetes für Sicherheitsexperten

3. Paranoide können noch weiter gehen und die DNS-Abfragen auf einen bestimmten DNS-Dienst beschränken kube-system. Im Abschnitt "Nach Namespaces und Pods filtern" wird erklärt, wie dies erreicht werden kann.

Eine andere Möglichkeit besteht darin, DNS auf Namespace-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 Netzwerkpolitik von Kubernetes für Sicherheitsexperten

Erstes Übereinstimmung und Regelreihenfolge

In herkömmlichen Firewalls wird die Aktion („Erlauben“ oder „Verbieten“) für ein Paket durch die erste Regel bestimmt, die erfüllt wird. In Kubernetes spielt die Reihenfolge der Richtlinien keine Rolle.

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

Solches Verhalten kann durch eine Bereinigungregel geändert werden.

Bereinigungsregel („Verbieten“)

Firewall-Richtlinien verbieten in der Regel jeglichen ausdrücklich nicht erlaubten Verkehr.

In Kubernetes gibt es keine Aktion „verbieten“ (deny),aber ähnliche Effekte können mit einer regulären (erlaubenden) Richtlinie erzielt werden, indem eine leere Gruppe von Quell-Pods (Ingress) gewählt wird:

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

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

Diese Richtlinie wählt alle Pods im Namensraum aus und lässt den Ingress undefiniert, wodurch jeglicher eingehender Verkehr verweigert wird.

In ähnlicher Weise 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 Netzwerkpolitik von Kubernetes für Sicherheitsexperten

Bitte beachten Sie, dass alle zusätzlichen Richtlinien, die Verkehr zu Pods im Namensraum erlauben, Vorrang vor dieser Regel haben werden (vergleichbar mit dem Hinzufügen einer Erlaubungsregel vor einer Verweigerungsregel in der Firewall-Konfiguration).

Alle erlauben (Any-Any-Any-Allow)

Um eine "Alle erlauben"-Richtlinie zu erstellen, muss die oben genannte Verweigerungsrichtlinie mit einem leeren 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 Netzwerkpolitik von Kubernetes für Sicherheitsexperten

Sie ermöglicht den Zugriff von allen Pods in allen Namensräumen (und allen IPs) auf jeden Pod im Namensraum default. Dieses Verhalten ist standardmäßig aktiviert, daher muss es normalerweise nicht zusätzlich definiert werden. In einigen Fällen kann es jedoch erforderlich sein, bestimmte Erlaubnisse vorübergehend zu deaktivieren, um ein Problem zu diagnostizieren.

Die Regel kann eingeschränkt und der 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 Netzwerkpolitik von Kubernetes für Sicherheitsexperten

Die folgende Richtlinie erlaubt den 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 Netzwerkpolitik von Kubernetes für Sicherheitsexperten
Einführung in die Netzwerkpolitik von Kubernetes für Sicherheitsexperten

Kombination mehrerer Richtlinien

Richtlinien werden durch logisches ODER auf drei Ebenen kombiniert; die Berechtigungen jedes Pods werden anhand der Disjunktion aller Richtlinien, die ihn betreffen, festgelegt:

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

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

Die Anzahl der Elemente (auch identische) in den Unterbereichen from/zu ist dabei nicht begrenzt. Alle werden durch logisches 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 Netzwerkpolitik von Kubernetes für Sicherheitsexperten

2. Im Abschnitt der Richtlinie ingress kann es mehrere Elemente geben from (die durch eine logische ODER-Verknüpfung verbunden sind). Ebenso kann der Abschnitt egress viele Elemente enthalten zu (die ebenfalls durch Disjunktion verbunden sind):

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 Netzwerkpolitik von Kubernetes für Sicherheitsexperten

3. Verschiedene Richtlinien werden ebenfalls durch logische ODER-Verknüpfung kombiniert

Es gibt jedoch eine Einschränkung, die bei deren Kombination erwähnt wurde Chris Cooney: Kubernetes kann Richtlinien nur mit unterschiedlichen 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 einschränkende Richtlinie geändert werden, die den ausgehenden und/oder eingehenden Datenverkehr in den Namespace einschränkt (siehe „Cleanup-Regel“ oben).

Durch das Blockieren des Zugriffs auf den Namensraum (siehe „Bereinigungsregel“ oben) können Sie Ausnahmen in die Sperrpolitik einfügen, indem Sie Verbindungen aus einem bestimmten Namensraum erlauben mit 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 Netzwerkpolitik von Kubernetes für Sicherheitsexperten

Infolgedessen erhalten alle Pods im Namensraum default Zugriff auf die Pods postgres im Namespace database. Aber was, wenn Sie nur bestimmten Pods im Namensraum Zugriff gewähren möchten? postgres Filterung nach Namensräumen und Pods default?

Kubernetes Version 1.11 und höher ermöglicht es, Operatoren

mit logischem UND zu kombinieren. So sieht es aus: namespaceSelector und podSelector 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

Warum wird dies als UND und nicht als übliches ODER interpretiert?

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

Beachten Sie, dass

nicht mit einem Bindestrich beginnt. In YAML bedeutet dies, dass podSelector und das davorstehende podSelector und vor ihm stehend namespaceSelector gehören zu dasselbe Listenelement. Daher werden sie logisch mit UND kombiniert.

Das Hinzufügen eines Bindestrichs vor podSelector führt zur Erzeugung 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 ein leeres 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 Netzwerkpolitik von Kubernetes für Sicherheitsexperten

Mehrere Labels werden mit UND kombiniert

Regeln für die Firewall mit mehreren Objekten (Hosts, Netzwerken, Gruppen) werden mit logischen ODER kombiniert. Die folgende Regel funktioniert, wenn die Quelle 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 logisch mit UND kombiniert. Zum Beispiel wählt die folgende Regel Pods aus, die beide Labels haben, role=db Und version=v2:

podSelector:
  matchLabels:
    role: db
    version: v2

Die gleiche Logik gilt für alle Arten von Operatoren: Ziel-Selectors von Richtlinien, Pod-Selectors und Namespace-Selectors.

Subnetze und IP-Adressen (IPBlocks)

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

In Kubernetes werden IP-Adressen den Pods automatisch zugewiesen und können sich häufig ändern. Daher werden Labels zur Auswahl von Pods und Namensräumen in Netzwerk-Richtlinien verwendet.

Subnetze (ipBlocks) werden bei der Verwaltung von eingehenden (Ingress) oder ausgehenden (Egress) externen (North-South) Verbindungen genutzt. Diese Richtlinie 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 Netzwerkpolitik von Kubernetes für Sicherheitsexperten

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

Diese Richtlinie erlaubt nur den Zugriff auf 8.8.8.8; der Zugriff auf jede andere IP ist verboten. Somit haben Sie im Grunde den Zugriff auf den internen Kubernetes DNS-Dienst blockiert. Wenn Sie diesen jedoch öffnen möchten, geben Sie dies explizit an.

Normalerweise ipBlocks und podSelectors sind sich gegenseitig ausschließend, da interne IP-Adressen von Pods nicht in ipBlocks. Wenn Sie interne IP-Adressen von Pods, erlauben Sie im Grunde Verbindungen zu/von Pods mit diesen Adressen. In der Praxis werden Sie nicht wissen, welche IP-Adresse zu verwenden ist, weshalb sie nicht zur Auswahl von Pods verwendet werden sollten.

Als Gegenbeispiel umfasst die folgende Richtlinie alle IPs und erlaubt somit den Zugang zu allen 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 Netzwerkpolitik von Kubernetes für Sicherheitsexperten

Zugriff auf externe IPs kann eröffnet werden, indem interne IP-Adressen von 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 Netzwerkpolitik von Kubernetes für Sicherheitsexperten

Ports und Protokolle

In der Regel hört ein Pod auf einen 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 so restriktiv wie möglich zu gestalten, daher können in einigen Fällen trotzdem 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 Netzwerkpolitik von Kubernetes für Sicherheitsexperten

Bitte beachten Sie, dass der Selektor ports auf alle Elemente im Block angewendet wird, in dem er enthalten ist. Um verschiedene Ports für unterschiedliche Sets von Elementen anzugeben, unterteilen Sie zu oder fromin mehrere Unterabschnitte mit ingress oder egress und geben Sie in jedem Ihre Ports an: zu oder from und trag deine Ports in jede ein:

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 Netzwerkpolitik von Kubernetes für Sicherheitsexperten

Standardverhalten der Ports:

  • Wenn Sie die Portdefinition 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 erforderlichen Werte explizit an.

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

Sind Richtlinien für Pods oder Dienste definiert?

In der Regel kommunizieren Pods in Kubernetes miteinander über einen Dienst – einen virtuellen Lastenausgleicher, der den Verkehr zu den Pod identifiziert, die den Dienst bereitstellen. Man könnte denken, dass die Netzwerkrichtlinien den Zugriff auf die Dienste kontrollieren, aber das ist nicht der Fall. Kubernetes-Netzwerkrichtlinien arbeiten mit den Ports der Pods und nicht mit denen der Dienste.

Wenn beispielsweise ein Dienst Port 80 abhört, aber den Verkehr an Port 8080 seiner Pods weiterleitet, muss in der Netzwerkrichtlinie genau 8080 angegeben werden.

Ein solches Verfahren wird als suboptimal angesehen: Bei Änderungen 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 (siehe beispielsweise unten zu Istio — Anm. der Übers.) hilft, dieses Problem zu lösen.

Müssen sowohl Ingress als auch Egress angegeben werden?

Die kurze Antwort ist ja: Damit Pod A mit Pod B kommunizieren kann, muss es die Erlaubnis haben, eine ausgehende Verbindung herzustellen (dazu ist die Konfiguration einer Egress-Policy erforderlich), und Pod B muss die Möglichkeit haben, eine eingehende Verbindung entgegenzunehmen (hierfür ist eine Ingress-Policy notwendig).

In der Praxis kann man jedoch auf die Standardrichtlinie vertrauen, die Verbindungen in eine oder beide Richtungen erlaubt.

Wenn ein PodQuelle von einer oder mehreren egress-Richtlinien ausgewählt wird, bestimmen die auferlegten Einschränkungen deren Disjunktion. In diesem Fall muss die Verbindung zu dem Pod-Zielexplizit erlaubt werden. Wenn ein Pod nicht von einer Richtlinie ausgewählt wird, ist sein ausgehender (Egress-) Datenverkehr standardmäßig erlaubt.

Ähnlich wird das Schicksal des Pod-Ziel, der von einer oder mehreren ingress-Richtlinien ausgewählt wird, durch deren Disjunktion bestimmt. In diesem Fall muss explizit erlaubt werden, dass er Datenverkehr von Pod-Quelle erhält. Wenn ein Pod nicht von einer Richtlinie ausgewählt wird, ist der gesamte eingehende (Ingress-) Datenverkehr für ihn standardmäßig erlaubt.

Siehe Punkt "Stateful oder Stateless" unten.

Protokolle

Die Netzwerkpolicy von Kubernetes kann den Datenverkehr nicht protokollieren. Das erschwert die Feststellung, ob die Richtlinie ordnungsgemäß funktioniert und kompliziert die Sicherheitsanalysen erheblich.

Überwachung des Datenverkehrs zu externen Diensten

Die Netzwerkpolicy von Kubernetes erlaubt es nicht, einen vollwertigen Domainnamen (DNS) in den Egress-Abschnitten anzugeben. Dies führt zu erheblichen Unannehmlichkeiten, wenn versucht wird, den Datenverkehr zu externen Adressen ohne feste IP-Adresse (wie aws.com) einzuschränken.

Richtlinienprüfung

Firewalls werden Sie warnen oder sogar eine fehlerhafte Richtlinie zurückweisen. Kubernetes führt ebenfalls eine gewisse Überprüfung durch. Wenn Sie eine Netzwerkpolicy über kubectl festlegen, kann Kubernetes angeben, dass sie fehlerhaft ist und die Annahme verweigern. In anderen Fällen akzeptiert Kubernetes die Richtlinie und ergänzt sie um fehlende Details. Diese finden Sie mit dem Befehl:

kubernetes get networkpolicy  -o yaml

Bitte beachten Sie, dass das Überprüfungssystem von Kubernetes nicht narrensicher ist und einige Arten von Fehlern übersehen kann.

Ausführung

Kubernetes implementiert keine Netzwerkpolitiken eigenständig, sondern fungiert lediglich als API-Gateway, das die Kontrolle an das darunterliegende System, die Container Networking Interface (CNI), delegiert. Das Festlegen von Politiken in einem Kubernetes-Cluster ohne Zuordnung einer passenden CNI ist vergleichbar mit dem Erstellen von Politiken auf einem Firewall-Management-Server, ohne diese anschließend in die Firewalls zu integrieren. Sie müssen selbst sicherstellen, dass eine geeignete CNI vorhanden ist oder, im Falle von cloudbasierten Kubernetes-Plattformen, sich darauf verlassen, (die Liste der Anbieter finden Sie hier hier — Anmerkung des Übersetzers.), die Netzwerkpolitiken implementiert, die die CNI für Sie einrichten.

Bitte beachten Sie, dass Kubernetes Sie nicht warnen wird, wenn Sie eine Netzwerkpolitik ohne die entsprechende unterstützende CNI definieren.

Stateful oder Stateless?

Alle CNI in Kubernetes, die ich kennengelernt habe, sind zustandsbehaftet (zum Beispiel verwendet Calico Linux conntrack). Dadurch kann ein Pod Antworten auf eine von ihm initiierte TCP-Verbindung erhalten, ohne sie neu aufbauen zu müssen. Mir ist jedoch kein Kubernetes-Standard bekannt, der die Speicherung von Zuständen (Statefulness) garantieren würde.

Erweiterte Sicherheitsrichtlinienverwaltung

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

  1. Das Architekturmuster Service Mesh verwendet Sidecar-Container, um detaillierte Telemetriedaten und Verkehrskontrolle auf Diensteebene zu gewährleisten. Ein Beispiel dafür ist Istio.
  2. Einige der CNI-Anbieter haben ihre Tools erweitert, um über die Netzwerkrichtlinien von Kubernetes hinauszugehen.
  3. Tufin Orca stellt Transparenz und Automatisierung der Netzwerkrichtlinien in Kubernetes sicher.

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

Zusätzliche Informationen

Fazit

Kubernetes-Netzwerkrichtlinien bieten eine ansprechende Palette von Werkzeugen zur Segmentierung von Clustern, allerdings sind sie nicht intuitiv und haben viele Feinheiten. Ich bin der Meinung, dass aufgrund dieser Komplexität viele der existierenden Clusterfehler enthalten. Mögliche Lösungen für dieses Problem sind die Automatisierung der Richtliniendefinitionen oder die Anwendung anderer Segmentierungsmittel.

Ich hoffe, dass dieses Handbuch einige Fragen klärt und Probleme löst, auf die Sie möglicherweise stoßen.

P.S. vom Übersetzer

Lesen Sie auch in unserem Blog:

Quelle: habr.com

Kaufen Sie zuverlässiges Hosting für Websites mit DDoS-Schutz, VPS VDS-Server 🔥 Kaufen Sie zuverlässiges Hosting für Websites mit DDoS-Schutz, VPS VDS-Server | ProHoster