Eine Einführung in Kubernetes-Netzwerkrichtlinien für Sicherheitsexperten

Eine Einführung in Kubernetes-Netzwerkrichtlinien für Sicherheitsexperten

Notiz. übersetzen: Der Autor des Artikels, Reuven Harrison, verfügt über mehr als 20 Jahre Erfahrung in der Softwareentwicklung und ist heute CTO und Mitbegründer von Tufin, einem Unternehmen, das Lösungen für das Sicherheitsrichtlinienmanagement entwickelt. Er betrachtet Kubernetes-Netzwerkrichtlinien zwar als recht leistungsfähiges Werkzeug zur Netzwerksegmentierung in einem Cluster, glaubt aber auch, dass sie in der Praxis nicht so einfach umzusetzen sind. Dieses Material (recht umfangreich) soll das Bewusstsein der Fachleute für dieses Thema schärfen und ihnen helfen, die notwendigen Konfigurationen zu erstellen.

Heutzutage entscheiden sich viele Unternehmen zunehmend für Kubernetes zur Ausführung ihrer Anwendungen. Das Interesse an dieser Software ist so groß, dass manche Kubernetes als „das neue Betriebssystem für das Rechenzentrum“ bezeichnen. Allmählich wird Kubernetes (oder k8s) als kritischer Teil des Geschäfts wahrgenommen, der die Organisation ausgereifter Geschäftsprozesse, einschließlich Netzwerksicherheit, erfordert.

Für Sicherheitsexperten, denen die Arbeit mit Kubernetes ein Rätsel ist, könnte die eigentliche Offenbarung die Standardrichtlinie der Plattform sein: alles zulassen.

Dieser Leitfaden hilft Ihnen, die interne Struktur von Netzwerkrichtlinien zu verstehen. Verstehen Sie, wie sie sich von den Regeln für normale Firewalls unterscheiden. Außerdem werden einige Fallstricke behandelt und Empfehlungen zur Sicherung von Anwendungen auf Kubernetes gegeben.

Kubernetes-Netzwerkrichtlinien

Mit dem Kubernetes-Netzwerkrichtlinienmechanismus können Sie die Interaktion von auf der Plattform bereitgestellten Anwendungen auf der Netzwerkebene (der dritten im OSI-Modell) verwalten. Den Netzwerkrichtlinien fehlen einige der erweiterten Funktionen moderner Firewalls, wie z. B. die Durchsetzung von OSI Layer 7 und die Bedrohungserkennung, sie bieten jedoch ein grundlegendes Maß an Netzwerksicherheit, das einen guten Ausgangspunkt darstellt.

Netzwerkrichtlinien steuern die Kommunikation zwischen Pods

Arbeitslasten werden in Kubernetes auf Pods verteilt, die aus einem oder mehreren gemeinsam bereitgestellten Containern bestehen. Kubernetes weist jedem Pod eine IP-Adresse zu, auf die von anderen Pods aus zugegriffen werden kann. Kubernetes-Netzwerkrichtlinien legen Zugriffsrechte für Pod-Gruppen auf die gleiche Weise fest, wie Sicherheitsgruppen in der Cloud zur Steuerung des Zugriffs auf Instanzen virtueller Maschinen verwendet werden.

Definieren von Netzwerkrichtlinien

Wie bei anderen Kubernetes-Ressourcen werden Netzwerkrichtlinien in YAML angegeben. Im Beispiel unten die Anwendung balance Zugriff 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

Eine Einführung in Kubernetes-Netzwerkrichtlinien für Sicherheitsexperten

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

Um Ihre eigene Netzwerkrichtlinie zu definieren, benötigen Sie Grundkenntnisse in YAML. Diese Sprache basiert auf Einrückungen (angegeben durch Leerzeichen statt Tabulatoren). Ein eingerücktes Element gehört zum nächstgelegenen eingerückten Element darüber. Ein neues Listenelement beginnt mit einem Bindestrich, alle anderen Elemente haben die Form Schlüsselwert.

Nachdem Sie die Richtlinie in YAML beschrieben haben, verwenden Sie kubectlum es im Cluster zu erstellen:

kubectl create -f policy.yaml

Spezifikation der Netzwerkrichtlinie

Die Kubernetes-Netzwerkrichtlinienspezifikation umfasst vier Elemente:

  1. podSelector: definiert die von dieser Richtlinie betroffenen Pods (Ziele) – erforderlich;
  2. policyTypes: gibt an, welche Arten von Richtlinien darin enthalten sind: Ein- und/oder Ausstieg – optional, ich empfehle jedoch, dies in allen Fällen explizit anzugeben;
  3. ingress: definiert erlaubt eingehend Datenverkehr zu Ziel-Pods – optional;
  4. egress: definiert erlaubt kontaktfreudig Der Datenverkehr von Ziel-Pods ist optional.

Beispiel von der Kubernetes-Website (ich habe ersetzt 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

Eine Einführung in Kubernetes-Netzwerkrichtlinien für Sicherheitsexperten
Eine Einführung in Kubernetes-Netzwerkrichtlinien für Sicherheitsexperten

Bitte beachten Sie, dass nicht alle vier Elemente enthalten sein müssen. Es ist lediglich verpflichtend podSelector, andere Parameter können nach Wunsch verwendet werden.

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

  • Standardmäßig wird davon ausgegangen, dass es die Eingangsseite definiert. Wenn die Richtlinie dies nicht ausdrücklich angibt, geht das System davon aus, dass jeglicher Datenverkehr verboten ist.
  • Das Verhalten auf der Ausgangsseite wird durch das Vorhandensein oder Fehlen des entsprechenden Ausgangsparameters bestimmt.

Um Fehler zu vermeiden, empfehle ich Machen Sie es immer explizit policyTypes.

Gemäß der obigen Logik, wenn die Parameter ingress und / oder egress Wird diese Option weggelassen, verweigert die Richtlinie den gesamten Datenverkehr (siehe „Stripping-Regel“ unten).

Die Standardrichtlinie ist Zulassen

Wenn keine Richtlinien definiert sind, lässt Kubernetes standardmäßig den gesamten Datenverkehr zu. Alle Pods können untereinander frei Informationen austauschen. Dies mag aus Sicherheitsgründen kontraintuitiv erscheinen, aber bedenken Sie, dass Kubernetes ursprünglich von Entwicklern entwickelt wurde, um die Interoperabilität von Anwendungen zu ermöglichen. Netzwerkrichtlinien wurden später hinzugefügt.

Namensräume

Namespaces sind der Kubernetes-Kollaborationsmechanismus. Sie dienen dazu, logische Umgebungen voneinander zu isolieren, während die Kommunikation zwischen Räumen standardmäßig zulässig ist.

Wie die meisten Kubernetes-Komponenten befinden sich Netzwerkrichtlinien in einem bestimmten Namespace. Im Block metadata Sie können angeben, zu welchem ​​Bereich die Richtlinie gehört:

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

Wenn der Namespace nicht explizit in den Metadaten angegeben ist, verwendet das System standardmäßig den in kubectl angegebenen Namespace namespace=default):

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

Ich empfehle Namespace explizit angeben, es sei denn, Sie schreiben eine Richtlinie, die auf mehrere Namespaces gleichzeitig abzielt.

Primär элемент podSelector in der Richtlinie wählt Pods aus dem Namespace aus, zu dem die Richtlinie gehört (der Zugriff auf Pods aus einem anderen Namespace wird ihr verweigert).

Ebenso podSelectors in Eingangs- und Ausgangsblöcken Sie können Pods nur aus ihrem eigenen Namensraum auswählen, es sei denn, Sie kombinieren sie natürlich mit namespaceSelector (Dies wird im Abschnitt „Nach Namespaces und Pods filtern“ besprochen).

Richtlinienbenennungsregeln

Richtliniennamen sind innerhalb desselben Namespace eindeutig. Es können nicht zwei Richtlinien mit demselben Namen im selben Bereich vorhanden sein, es können jedoch Richtlinien mit demselben Namen in verschiedenen Bereichen vorhanden sein. Dies ist nützlich, wenn Sie dieselbe Richtlinie in mehreren Bereichen erneut anwenden möchten.

Eine der Benennungsmethoden gefällt mir besonders gut. Es besteht aus der Kombination des Namespace-Namens mit den Ziel-Pods. 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

Eine Einführung in Kubernetes-Netzwerkrichtlinien für Sicherheitsexperten

Etiketten

Sie können Kubernetes-Objekten wie Pods und Namespaces benutzerdefinierte Beschriftungen hinzufügen. Etiketten (Etiketten - Tags) sind das Äquivalent von Tags in der Cloud. Kubernetes-Netzwerkrichtlinien verwenden Labels zur Auswahl Schotenfür die sie gelten:

podSelector:
  matchLabels:
    role: db

… oder Namensräumefür die sie gelten. In diesem Beispiel werden alle Pods in Namespaces mit den entsprechenden Bezeichnungen ausgewählt:

namespaceSelector:
  matchLabels:
    project: myproject

Eine Vorsichtsmaßnahme: bei der Verwendung namespaceSelector Stellen Sie sicher, dass die von Ihnen ausgewählten Namespaces die richtige Bezeichnung enthalten. Beachten Sie, dass integrierte Namespaces wie default и kube-system, enthalten standardmäßig keine Beschriftungen.

Sie können einem Bereich wie folgt eine Beschriftung hinzufügen:

kubectl label namespace default namespace=default

Gleichzeitig Namespace im Abschnitt metadata sollte sich auf den tatsächlichen Space-Namen beziehen, nicht auf die Beschriftung:

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

Quelle und Ziel

Firewall-Richtlinien bestehen aus Regeln mit Quellen und Zielen. Kubernetes-Netzwerkrichtlinien werden für ein Ziel definiert – eine Reihe von Pods, für die sie gelten – und legen dann Regeln für den ein- und/oder ausgehenden Datenverkehr fest. In unserem Beispiel sind alle Pods im Namespace das Ziel der Richtlinie default mit Etikett mit Schlüssel app und Bedeutung 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

Eine Einführung in Kubernetes-Netzwerkrichtlinien für Sicherheitsexperten
Eine Einführung in Kubernetes-Netzwerkrichtlinien für Sicherheitsexperten

Unterabschnitt ingress In dieser Richtlinie wird eingehender Datenverkehr zu den Ziel-Pods geöffnet. Mit anderen Worten: Ingress ist die Quelle und Target das entsprechende Ziel. Ebenso ist Egress das Ziel und Target seine Quelle.

Eine Einführung in Kubernetes-Netzwerkrichtlinien für Sicherheitsexperten

Dies entspricht zwei Firewall-Regeln: Ingress → Target; Ziel → Ausstieg.

Egress und DNS (wichtig!)

Durch die Begrenzung des ausgehenden Datenverkehrs Achten Sie besonders auf DNS – Kubernetes nutzt diesen Dienst, um Dienste IP-Adressen zuzuordnen. Die folgende Richtlinie funktioniert beispielsweise nicht, weil Sie die Anwendung nicht zugelassen haben balance Zugriff auf DNS:

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

Eine Einführung in Kubernetes-Netzwerkrichtlinien für Sicherheitsexperten

Sie können das Problem 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

Eine Einführung in Kubernetes-Netzwerkrichtlinien für Sicherheitsexperten

Letztes Element to ist leer und wählt daher indirekt aus alle Pods in allen Namespaces, erlauben balance Senden Sie DNS-Abfragen an den entsprechenden Kubernetes-Dienst (der normalerweise im Space ausgeführt wird). kube-system).

Dieser Ansatz funktioniert jedoch übermäßig freizügig und unsicher, da es die Weiterleitung von DNS-Anfragen außerhalb des Clusters ermöglicht.

Sie können es in drei aufeinanderfolgenden Schritten verbessern.

1. Nur DNS-Abfragen zulassen innen Cluster durch 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

Eine Einführung in Kubernetes-Netzwerkrichtlinien für Sicherheitsexperten

2. Erlauben Sie DNS-Abfragen nur innerhalb des Namespace kube-system.

Dazu müssen Sie dem Namespace eine Bezeichnung hinzufügen kube-system: kubectl label namespace kube-system namespace=kube-system - und notieren Sie es in der Police 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

Eine Einführung in Kubernetes-Netzwerkrichtlinien für Sicherheitsexperten

3. Paranoide Menschen können sogar noch weiter gehen und DNS-Anfragen auf einen bestimmten DNS-Dienst beschränken kube-system. Im Abschnitt „Nach Namespaces UND Pods filtern“ erfahren Sie, wie Sie dies erreichen.

Eine weitere Möglichkeit besteht darin, DNS auf Namespace-Ebene aufzulösen. 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

nichtig podSelector wählt alle Pods im Namespace aus.

Eine Einführung in Kubernetes-Netzwerkrichtlinien für Sicherheitsexperten

Erste Übereinstimmung und Regelreihenfolge

Bei herkömmlichen Firewalls wird die Aktion (Zulassen oder Verweigern) für ein Paket durch die erste Regel bestimmt, die es erfüllt. In Kubernetes spielt die Reihenfolge der Richtlinien keine Rolle.

Wenn keine Richtlinien festgelegt sind, ist die Kommunikation zwischen Pods standardmäßig zulässig und sie können frei Informationen austauschen. Sobald Sie mit der Formulierung von Richtlinien beginnen, wird jeder Pod, der von mindestens einer davon betroffen ist, gemäß der Disjunktion (logisches ODER) aller Richtlinien, die ihn ausgewählt haben, isoliert. Pods, die von keiner Richtlinie betroffen sind, bleiben geöffnet.

Sie können dieses Verhalten mithilfe einer Stripping-Regel ändern.

Stripping-Regel („Deny“)

Firewall-Richtlinien verweigern normalerweise jeglichen Datenverkehr, der nicht ausdrücklich zugelassen ist.

In Kubernetes gibt es keine Deny-AktionEin ähnlicher Effekt kann jedoch mit einer regulären (permissiven) Richtlinie erzielt werden, indem eine leere Gruppe von Quell-Pods (Ingress) ausgewählt wird:

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

Eine Einführung in Kubernetes-Netzwerkrichtlinien für Sicherheitsexperten

Diese Richtlinie wählt alle Pods im Namespace aus und lässt den eingehenden Datenverkehr undefiniert, sodass jeglicher eingehender Datenverkehr verweigert wird.

Auf ähnliche Weise können Sie den gesamten ausgehenden Datenverkehr aus einem Namespace einschränken:

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

Eine Einführung in Kubernetes-Netzwerkrichtlinien für Sicherheitsexperten

Bitte beachten Sie das Alle zusätzlichen Richtlinien, die Datenverkehr zu Pods im Namespace zulassen, haben Vorrang vor dieser Regel (Ähnlich dem Hinzufügen einer Zulassungsregel vor einer Verweigerungsregel in einer Firewall-Konfiguration).

Alles zulassen (Any-Any-Any-Allow)

Um eine Richtlinie „Alle zulassen“ zu erstellen, müssen Sie die obige Richtlinie „Verweigern“ um ein leeres Element ergänzen ingress:

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

Eine Einführung in Kubernetes-Netzwerkrichtlinien für Sicherheitsexperten

Es ermöglicht den Zugriff von alle Pods in allen Namespaces (und alle IP) zu jedem Pod im Namespace default. Dieses Verhalten ist standardmäßig aktiviert und muss daher in der Regel nicht weiter definiert werden. Manchmal müssen Sie jedoch möglicherweise bestimmte Berechtigungen vorübergehend deaktivieren, um das Problem zu diagnostizieren.

Die Regel kann eingegrenzt werden, um nur den Zugriff zu erlauben ein bestimmter Satz 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

Eine Einführung in Kubernetes-Netzwerkrichtlinien für Sicherheitsexperten

Die folgende Richtlinie lässt den gesamten ein- und ausgehenden Datenverkehr zu, einschließlich des Zugriffs auf alle IP-Adressen außerhalb des Clusters:

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

Eine Einführung in Kubernetes-Netzwerkrichtlinien für Sicherheitsexperten
Eine Einführung in Kubernetes-Netzwerkrichtlinien für Sicherheitsexperten

Kombinieren mehrerer Richtlinien

Richtlinien werden durch logisches ODER auf drei Ebenen kombiniert; Die Berechtigungen jedes Pods werden entsprechend der Disjunktion aller ihn betreffenden Richtlinien festgelegt:

1. Auf den Feldern from и to Es können drei Arten von Elementen definiert werden (die alle mit ODER verknüpft werden):

  • namespaceSelector – wählt den gesamten Namespace aus;
  • podSelector – wählt Pods aus;
  • ipBlock – wählt ein Subnetz aus.

Darüber hinaus die Anzahl der Elemente (auch identischer) in Unterabschnitten from/to nicht limitiert. Alle werden durch logisches ODER verknüpft.

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

Eine Einführung in Kubernetes-Netzwerkrichtlinien für Sicherheitsexperten

2. Im Abschnitt „Richtlinien“. ingress kann viele Elemente haben from (kombiniert durch logisches ODER). Ebenso Abschnitt egress kann viele Elemente enthalten to (auch durch Disjunktion kombiniert):

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

Eine Einführung in Kubernetes-Netzwerkrichtlinien für Sicherheitsexperten

3. Verschiedene Richtlinien werden auch mit logischem ODER kombiniert

Bei der Kombination gibt es jedoch eine Einschränkung angezeigt Chris Cooney: Kubernetes kann nur Richtlinien mit unterschiedlichen kombinieren policyTypes (Ingress oder Egress). Richtlinien, die den Eingang (oder Ausgang) definieren, überschreiben sich gegenseitig.

Beziehung zwischen Namespaces

Standardmäßig ist der Informationsaustausch zwischen Namespaces zulässig. Dies kann durch die Verwendung einer Verweigerungsrichtlinie geändert werden, die den ausgehenden und/oder eingehenden Datenverkehr in den Namespace einschränkt (siehe „Stripping-Regel“ oben).

Sobald Sie den Zugriff auf einen Namespace blockiert haben (siehe die „Stripping-Regel“ oben), können Sie Ausnahmen von der Verweigerungsrichtlinie machen, indem Sie Verbindungen von einem bestimmten Namespace aus zulassen 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

Eine Einführung in Kubernetes-Netzwerkrichtlinien für Sicherheitsexperten

Infolgedessen alle Pods im Namespace default wird Zugriff auf Pods haben postgres im Namensraum database. Aber was ist, wenn Sie den Zugriff öffnen möchten? postgres nur bestimmte Pods im Namespace default?

Filtern Sie nach Namespaces und Pods

Mit Kubernetes Version 1.11 und höher können Sie Operatoren kombinieren namespaceSelector и podSelector mit logischem UND. Es sieht so 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

Eine Einführung in Kubernetes-Netzwerkrichtlinien für Sicherheitsexperten

Warum wird dies als UND statt als übliches ODER interpretiert?

Bitte beachten Sie, dass podSelector beginnt nicht mit einem Bindestrich. In YAML bedeutet dies das podSelector und stand vor ihm namespaceSelector beziehen sich auf dasselbe Listenelement. Daher werden sie mit logischem UND verknüpft.

Vorher einen Bindestrich hinzufügen podSelector führt zur Entstehung eines neuen Listenelements, das mit dem vorherigen kombiniert wird namespaceSelector mit logischem ODER.

Um Pods mit einer bestimmten Bezeichnung auszuwählen in allen Namensräumen, geben Sie Leerzeichen 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

Eine Einführung in Kubernetes-Netzwerkrichtlinien für Sicherheitsexperten

Mehrere Labels schließen sich mit I zusammen

Regeln für eine Firewall mit mehreren Objekten (Hosts, Netzwerke, Gruppen) werden durch logisches ODER kombiniert. Die folgende Regel funktioniert, wenn die Paketquelle übereinstimmt Host_1 OR Host_2:

| Source | Destination | Service | Action |
| ----------------------------------------|
| Host_1 | Subnet_A    | HTTPS   | Allow  |
| Host_2 |             |         |        |
| ----------------------------------------|

Im Gegenteil, in Kubernetes gibt es verschiedene Bezeichnungen podSelector oder namespaceSelector werden mit logischem UND kombiniert. Die folgende Regel wählt beispielsweise Pods aus, die beide Bezeichnungen haben: role=db И version=v2:

podSelector:
  matchLabels:
    role: db
    version: v2

Die gleiche Logik gilt für alle Arten von Operatoren: Richtlinienzielselektoren, Pod-Selektoren und Namespace-Selektoren.

Subnetze und IP-Adressen (IPBlocks)

Firewalls verwenden VLANs, IP-Adressen und Subnetze, um ein Netzwerk zu segmentieren.

In Kubernetes werden IP-Adressen Pods automatisch zugewiesen und können sich häufig ändern. Daher werden Labels verwendet, um Pods und Namespaces in Netzwerkrichtlinien auszuwählen.

Subnetze (ipBlocks) werden bei der Verwaltung eingehender (Ingress) oder ausgehender (Egress) externer (Nord-Süd) Verbindungen verwendet. Diese Richtlinie wird beispielsweise für alle Pods aus dem Namespace geöffnet default Zugriff auf den Google DNS-Dienst:

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

Eine Einführung in Kubernetes-Netzwerkrichtlinien für Sicherheitsexperten

Der leere Pod-Selektor bedeutet in diesem Beispiel „Alle Pods im Namespace auswählen“.

Diese Richtlinie erlaubt nur den Zugriff auf 8.8.8.8; Der Zugriff auf andere IP-Adressen ist untersagt. Sie haben also im Wesentlichen den Zugriff auf den internen Kubernetes-DNS-Dienst blockiert. Wenn Sie es dennoch öffnen möchten, geben Sie dies explizit an.

In der Regel ipBlocks и podSelectors schließen sich gegenseitig aus, da die internen IP-Adressen von Pods nicht verwendet werden ipBlocks. Durch Angabe interne IP-Pods, werden Sie tatsächlich Verbindungen zu/von Pods mit diesen Adressen zulassen. In der Praxis wissen Sie nicht, welche IP-Adresse Sie verwenden sollen, weshalb diese nicht zur Auswahl von Pods verwendet werden sollte.

Als Gegenbeispiel umfasst die folgende Richtlinie alle IPs und ermöglicht daher 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

Eine Einführung in Kubernetes-Netzwerkrichtlinien für Sicherheitsexperten

Sie können den Zugriff nur auf externe IPs öffnen, mit Ausnahme der internen IP-Adressen von Pods. Wenn das Subnetz Ihres Pods beispielsweise 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

Eine Einführung in Kubernetes-Netzwerkrichtlinien für Sicherheitsexperten

Ports und Protokolle

Typischerweise überwachen Pods einen Port. Das bedeutet, dass Sie einfach keine Portnummern in Richtlinien angeben und alles auf den Standardwerten belassen können. Es wird jedoch empfohlen, die Richtlinien so restriktiv wie möglich zu gestalten, sodass Sie in einigen Fällen trotzdem Ports angeben können:

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

Eine Einführung in Kubernetes-Netzwerkrichtlinien für Sicherheitsexperten

Beachten Sie, dass der Selektor ports gilt für alle Elemente im Block to oder from, was beinhaltet. Um unterschiedliche Ports für unterschiedliche Elementsätze anzugeben, teilen Sie ingress oder egress in mehrere Unterabschnitte mit to oder from und in jedem registrieren Sie Ihre Ports:

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

Eine Einführung in Kubernetes-Netzwerkrichtlinien für Sicherheitsexperten

Standard-Port-Betrieb:

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

Best Practice: Verlassen Sie sich nicht auf Standardwerte, sondern geben Sie explizit an, was Sie benötigen.

Bitte beachten Sie, dass Sie Pod-Ports und keine Service-Ports verwenden müssen (mehr dazu im nächsten Absatz).

Sind Richtlinien für Pods oder Dienste definiert?

Typischerweise greifen Pods in Kubernetes über einen Dienst aufeinander zu – einen virtuellen Load Balancer, der den Datenverkehr an die Pods umleitet, die den Dienst implementieren. Man könnte meinen, dass Netzwerkrichtlinien den Zugriff auf Dienste steuern, aber das ist nicht der Fall. Kubernetes-Netzwerkrichtlinien funktionieren auf Pod-Ports, nicht auf Service-Ports.

Wenn ein Dienst beispielsweise auf Port 80 lauscht, den Datenverkehr jedoch auf Port 8080 seiner Pods umleitet, müssen Sie in der Netzwerkrichtlinie genau 8080 angeben.

Ein solcher Mechanismus sollte als suboptimal angesehen werden: Wenn sich die interne Struktur des Dienstes (die Ports, auf denen die Pods lauschen) ändert, müssen die Netzwerkrichtlinien aktualisiert werden.

Neuer Architekturansatz mit Service Mesh (Siehe zum Beispiel unten über Istio – ungefähre Übersetzung.) ermöglicht es Ihnen, dieses Problem zu bewältigen.

Ist es notwendig, sowohl Ingress als auch Egress zu registrieren?

Die kurze Antwort lautet: Ja, damit Pod A mit Pod B kommunizieren kann, muss es ihm gestattet sein, eine ausgehende Verbindung herzustellen (dazu müssen Sie eine Ausgangsrichtlinie konfigurieren), und Pod B muss in der Lage sein, eine eingehende Verbindung zu akzeptieren ( hierfür benötigen Sie dementsprechend eine Ingress-Policy).

In der Praxis können Sie sich jedoch darauf verlassen, dass die Standardrichtlinie Verbindungen in eine oder beide Richtungen zulässt.

Wenn einige Pod-Quelle wird von einem oder mehreren ausgewählt Austritt-Politiker, die ihr auferlegten Beschränkungen werden durch ihre Disjunktion bestimmt. In diesem Fall müssen Sie die Verbindung zum Pod explizit zulassen –an den Adressaten. Wenn ein Pod durch keine Richtlinie ausgewählt wird, ist sein ausgehender (Ausgangs-)Verkehr standardmäßig zugelassen.

Ebenso ist das Schicksal der Schotedie Adresse, ausgewählt von einem oder mehreren Eintritt-Politiker, werden durch ihre Disjunktion bestimmt. In diesem Fall müssen Sie ihm ausdrücklich erlauben, Datenverkehr vom Quell-Pod zu empfangen. Wenn ein Pod durch keine Richtlinie ausgewählt wird, wird standardmäßig der gesamte eingehende Datenverkehr für ihn zugelassen.

Siehe unten „Stateful“ oder „Stateless“.

Protokolle

Kubernetes-Netzwerkrichtlinien können keinen Datenverkehr protokollieren. Dies erschwert die Feststellung, ob eine Richtlinie wie vorgesehen funktioniert, und erschwert die Sicherheitsanalyse erheblich.

Kontrolle des Datenverkehrs zu externen Diensten

Kubernetes-Netzwerkrichtlinien erlauben es Ihnen nicht, in Ausgangsabschnitten einen vollständig qualifizierten Domänennamen (DNS) anzugeben. Diese Tatsache führt zu erheblichen Unannehmlichkeiten, wenn versucht wird, den Datenverkehr auf externe Ziele zu beschränken, die keine feste IP-Adresse haben (z. B. aws.com).

Richtlinienprüfung

Firewalls warnen Sie oder weigern sich sogar, die falsche Richtlinie zu akzeptieren. Kubernetes führt auch einige Überprüfungen durch. Beim Festlegen einer Netzwerkrichtlinie über kubectl erklärt Kubernetes möglicherweise, dass sie falsch ist, und weigert sich, sie zu akzeptieren. In anderen Fällen übernimmt Kubernetes die Richtlinie und ergänzt sie mit den fehlenden Details. Sie können mit dem folgenden Befehl angezeigt werden:

kubernetes get networkpolicy <policy-name> -o yaml

Beachten Sie, dass das Kubernetes-Validierungssystem nicht unfehlbar ist und möglicherweise einige Arten von Fehlern übersieht.

Ausführung

Kubernetes implementiert selbst keine Netzwerkrichtlinien, sondern ist lediglich ein API-Gateway, das die Kontrolllast an ein zugrunde liegendes System namens Container Networking Interface (CNI) delegiert. Das Festlegen von Richtlinien auf einem Kubernetes-Cluster ohne Zuweisung des entsprechenden CNI ist dasselbe wie das Erstellen von Richtlinien auf einem Firewall-Verwaltungsserver, ohne sie anschließend auf Firewalls zu installieren. Es liegt an Ihnen, sicherzustellen, dass Sie über ein anständiges CNI verfügen oder, im Fall von Kubernetes-Plattformen, in der Cloud gehostet werden (Sie können die Liste der Anbieter einsehen hier — ca. trans.), aktivieren Sie Netzwerkrichtlinien, die CNI für Sie festlegen.

Beachten Sie, dass Kubernetes Sie nicht warnt, wenn Sie eine Netzwerkrichtlinie ohne die entsprechende Hilfs-CNI festlegen.

Staatenbehaftet oder staatenlos?

Alle Kubernetes-CNIs, auf die ich gestoßen bin, sind zustandsbehaftet (Calico verwendet beispielsweise Linux Conntrack). Dadurch kann der Pod Antworten auf die von ihm initiierte TCP-Verbindung empfangen, ohne diese neu aufbauen zu müssen. Allerdings ist mir kein Kubernetes-Standard bekannt, der Statefulness garantieren würde.

Erweitertes Sicherheitsrichtlinienmanagement

Hier sind einige Möglichkeiten, die Durchsetzung von Sicherheitsrichtlinien in Kubernetes zu verbessern:

  1. Das Service Mesh-Architekturmuster verwendet Sidecar-Container, um detaillierte Telemetrie und Verkehrskontrolle auf Serviceebene bereitzustellen. Als Beispiel können wir nehmen Istio.
  2. Einige der CNI-Anbieter haben ihre Tools erweitert, um über die Kubernetes-Netzwerkrichtlinien hinauszugehen.
  3. Tufin Orca Bietet Transparenz und Automatisierung von Kubernetes-Netzwerkrichtlinien.

Das Tufin Orca-Paket verwaltet Kubernetes-Netzwerkrichtlinien (und ist die Quelle der obigen Screenshots).

Weitere Informationen

Abschluss

Kubernetes-Netzwerkrichtlinien bieten eine Reihe guter Tools zur Segmentierung von Clustern, sind jedoch nicht intuitiv und weisen viele Feinheiten auf. Aufgrund dieser Komplexität glaube ich, dass viele bestehende Cluster-Richtlinien fehlerhaft sind. Mögliche Lösungen für dieses Problem sind die Automatisierung von Richtliniendefinitionen oder die Verwendung anderer Segmentierungstools.

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

PS vom Übersetzer

Lesen Sie auch auf unserem Blog:

Source: habr.com

Kommentar hinzufügen