Une introduction aux politiques réseau Kubernetes pour les professionnels de la sécurité

Une introduction aux politiques réseau Kubernetes pour les professionnels de la sécurité

Noter. trad.: L'auteur de l'article, Reuven Harrison, a plus de 20 ans d'expérience dans le développement de logiciels et est aujourd'hui CTO et co-fondateur de Tufin, une société qui crée des solutions de gestion des politiques de sécurité. S’il considère les politiques réseau Kubernetes comme un outil assez puissant pour la segmentation du réseau dans un cluster, il estime également qu’elles ne sont pas si faciles à mettre en œuvre dans la pratique. Ce matériel (assez volumineux) est destiné à sensibiliser les spécialistes à cette question et à les aider à créer les configurations nécessaires.

Aujourd’hui, de nombreuses entreprises choisissent de plus en plus Kubernetes pour exécuter leurs applications. L'intérêt pour ce logiciel est tel que certains appellent Kubernetes « le nouveau système d'exploitation pour le centre de données ». Peu à peu, Kubernetes (ou k8s) commence à être perçu comme un élément essentiel de l'entreprise, qui nécessite l'organisation de processus métiers matures, notamment la sécurité des réseaux.

Pour les professionnels de la sécurité que le fait de travailler avec Kubernetes laisse perplexes, la véritable révélation pourrait être la politique par défaut de la plateforme : tout autoriser.

Ce guide vous aidera à comprendre la structure interne des politiques de réseau ; comprendre en quoi elles diffèrent des règles des pare-feu classiques. Il abordera également certains pièges et fournira des recommandations pour aider à sécuriser les applications sur Kubernetes.

Politiques réseau Kubernetes

Le mécanisme de politique réseau Kubernetes permet de gérer l'interaction des applications déployées sur la plateforme au niveau de la couche réseau (la troisième du modèle OSI). Les politiques réseau ne disposent pas de certaines fonctionnalités avancées des pare-feu modernes, telles que l'application de la couche 7 OSI et la détection des menaces, mais elles fournissent un niveau de sécurité réseau de base qui constitue un bon point de départ.

Les politiques réseau contrôlent les communications entre les pods

Les charges de travail dans Kubernetes sont réparties sur des pods, constitués d'un ou plusieurs conteneurs déployés ensemble. Kubernetes attribue à chaque pod une adresse IP accessible depuis d'autres pods. Les stratégies réseau Kubernetes définissent les droits d'accès pour les groupes de pods de la même manière que les groupes de sécurité dans le cloud sont utilisés pour contrôler l'accès aux instances de machines virtuelles.

Définir des politiques de réseau

Comme les autres ressources Kubernetes, les politiques réseau sont spécifiées en YAML. Dans l'exemple ci-dessous, l'application balance accès à 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

Une introduction aux politiques réseau Kubernetes pour les professionnels de la sécurité

(Noter. trad.: cette capture d'écran, comme toutes les captures d'écran similaires ultérieures, a été créée non pas à l'aide des outils natifs Kubernetes, mais à l'aide de l'outil Tufin Orca, qui a été développé par la société de l'auteur de l'article original et qui est mentionné à la fin du document.)

Pour définir votre propre politique réseau, vous aurez besoin de connaissances de base en YAML. Ce langage est basé sur l'indentation (spécifiée par des espaces plutôt que par des tabulations). Un élément en retrait appartient à l'élément en retrait le plus proche au-dessus de lui. Un nouvel élément de liste commence par un trait d'union, tous les autres éléments ont la forme valeur clé.

Après avoir décrit la politique en YAML, utilisez kubectlpour le créer dans le cluster :

kubectl create -f policy.yaml

Spécification de la politique de réseau

La spécification de la politique réseau Kubernetes comprend quatre éléments :

  1. podSelector: définit les pods affectés par cette politique (cibles) - obligatoire ;
  2. policyTypes: indique quels types de politiques sont inclus dans ceci : entrée et/ou sortie - facultatif, mais je recommande de le spécifier explicitement dans tous les cas ;
  3. ingress: définit autorisé entrant trafic vers les pods cibles - facultatif ;
  4. egress: définit autorisé sortant le trafic depuis les pods cibles est facultatif.

Exemple tiré du site Kubernetes (j'ai remplacé role sur app), montre comment les quatre éléments sont utilisés :

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

Une introduction aux politiques réseau Kubernetes pour les professionnels de la sécurité
Une introduction aux politiques réseau Kubernetes pour les professionnels de la sécurité

Veuillez noter qu’il n’est pas nécessaire que les quatre éléments soient inclus. C'est seulement obligatoire podSelector, d'autres paramètres peuvent être utilisés à volonté.

Si nous omettons policyTypes, la politique sera interprétée comme suit :

  • Par défaut, on suppose qu'il définit le côté entrée. Si la politique ne l’indique pas explicitement, le système supposera que tout trafic est interdit.
  • Le comportement côté sortie sera déterminé par la présence ou l’absence du paramètre de sortie correspondant.

Pour éviter les erreurs je recommande rends-le toujours explicite policyTypes.

Selon la logique ci-dessus, si les paramètres ingress et / ou egress omise, la stratégie refusera tout le trafic (voir « Règle de suppression » ci-dessous).

La stratégie par défaut est Autoriser

Si aucune stratégie n'est définie, Kubernetes autorise tout le trafic par défaut. Tous les pods peuvent échanger librement des informations entre eux. Cela peut sembler contre-intuitif du point de vue de la sécurité, mais rappelez-vous que Kubernetes a été conçu à l'origine par les développeurs pour permettre l'interopérabilité des applications. Les politiques réseau ont été ajoutées ultérieurement.

Espaces de noms

Les espaces de noms constituent le mécanisme de collaboration Kubernetes. Ils sont conçus pour isoler les environnements logiques les uns des autres, tandis que la communication entre les espaces est autorisée par défaut.

Comme la plupart des composants Kubernetes, les politiques réseau résident dans un espace de noms spécifique. Dans le bloc metadata vous pouvez spécifier à quel espace appartient la stratégie :

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

Si l'espace de noms n'est pas explicitement spécifié dans les métadonnées, le système utilisera l'espace de noms spécifié dans kubectl (par défaut namespace=default):

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

Je recommande spécifier explicitement l'espace de noms, sauf si vous écrivez une stratégie qui cible plusieurs espaces de noms à la fois.

Primaire élément podSelector dans la stratégie sélectionnera les pods de l'espace de noms auquel appartient la stratégie (l'accès aux pods d'un autre espace de noms lui sera refusé).

De même, les podSelectors dans les blocs d'entrée et de sortie ne peut sélectionner que des pods dans leur propre espace de noms, à moins bien sûr que vous les combiniez avec namespaceSelector (ceci sera abordé dans la section « Filtrer par espaces de noms et pods »).

Règles de dénomination des stratégies

Les noms de stratégie sont uniques au sein du même espace de noms. Il ne peut pas y avoir deux stratégies portant le même nom dans le même espace, mais il peut y avoir des stratégies portant le même nom dans des espaces différents. Ceci est utile lorsque vous souhaitez réappliquer la même stratégie sur plusieurs espaces.

J'aime particulièrement l'une des méthodes de dénomination. Elle consiste à combiner le nom de l’espace de noms avec les pods cibles. Par exemple:

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

Une introduction aux politiques réseau Kubernetes pour les professionnels de la sécurité

Étiquettes

Vous pouvez attacher des étiquettes personnalisées aux objets Kubernetes, tels que les pods et les espaces de noms. Étiquettes (qui - tags) sont l'équivalent des tags dans le cloud. Les stratégies réseau Kubernetes utilisent des étiquettes pour sélectionner goussesauxquels ils s'appliquent :

podSelector:
  matchLabels:
    role: db

… ou espaces de nomsauxquels ils s'appliquent. Cet exemple sélectionne tous les pods dans les espaces de noms avec les étiquettes correspondantes :

namespaceSelector:
  matchLabels:
    project: myproject

Une mise en garde : lors de l'utilisation namespaceSelector assurez-vous que les espaces de noms que vous sélectionnez contiennent la bonne étiquette. Sachez que les espaces de noms intégrés tels que default и kube-system, par défaut, ne contiennent pas d'étiquettes.

Vous pouvez ajouter une étiquette à un espace comme ceci :

kubectl label namespace default namespace=default

En même temps, l'espace de noms dans la section metadata doit faire référence au nom réel de l'espace, et non à l'étiquette :

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

Origine et destination

Les politiques de pare-feu consistent en des règles avec des sources et des destinations. Les politiques réseau Kubernetes sont définies pour une cible (un ensemble de pods auxquels elles s'appliquent) et définissent ensuite des règles pour le trafic entrant et/ou sortant. Dans notre exemple, la cible de la politique sera tous les pods de l'espace de noms default avec étiquette avec clé app et sens 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

Une introduction aux politiques réseau Kubernetes pour les professionnels de la sécurité
Une introduction aux politiques réseau Kubernetes pour les professionnels de la sécurité

Sous-section ingress dans cette stratégie, ouvre le trafic entrant vers les pods cibles. En d’autres termes, l’entrée est la source et la cible est la destination correspondante. De même, la sortie est la destination et la cible est sa source.

Une introduction aux politiques réseau Kubernetes pour les professionnels de la sécurité

Cela équivaut à deux règles de pare-feu : Ingress → Target ; Objectif → Sortie.

Sortie et DNS (important !)

En limitant le trafic sortant, portez une attention particulière au DNS - Kubernetes utilise ce service pour mapper les services aux adresses IP. Par exemple, la stratégie suivante ne fonctionnera pas car vous n'avez pas autorisé l'application balance accéder au 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

Une introduction aux politiques réseau Kubernetes pour les professionnels de la sécurité

Vous pouvez le réparer en ouvrant l'accès au service 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
  - to:               # <<<
    ports:            # <<<
    - protocol: UDP   # <<<
      port: 53        # <<<
  policyTypes:
  - Egress

Une introduction aux politiques réseau Kubernetes pour les professionnels de la sécurité

Dernier élément to est vide, et donc il sélectionne indirectement tous les pods dans tous les espaces de noms, en permettant balance envoyer des requêtes DNS au service Kubernetes approprié (généralement exécuté dans l'espace kube-system).

Cette approche fonctionne, mais elle trop permissif et peu sûr, car il permet de diriger les requêtes DNS en dehors du cluster.

Vous pouvez l'améliorer en trois étapes successives.

1. Autoriser uniquement les requêtes DNS à l'intérieur cluster en ajoutant 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

Une introduction aux politiques réseau Kubernetes pour les professionnels de la sécurité

2. Autoriser les requêtes DNS uniquement dans l'espace de noms kube-system.

Pour ce faire, vous devez ajouter une étiquette à l'espace de noms kube-system: kubectl label namespace kube-system namespace=kube-system - et notez-le dans la politique en utilisant 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

Une introduction aux politiques réseau Kubernetes pour les professionnels de la sécurité

3. Les personnes paranoïaques peuvent aller encore plus loin et limiter les requêtes DNS à un service DNS spécifique dans kube-system. La section « Filtrer par espaces de noms ET pods » vous expliquera comment y parvenir.

Une autre option consiste à résoudre le DNS au niveau de l'espace de noms. Dans ce cas, il ne sera pas nécessaire de l'ouvrir pour chaque prestation :

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

nul podSelector sélectionne tous les pods dans l’espace de noms.

Une introduction aux politiques réseau Kubernetes pour les professionnels de la sécurité

Premier match et ordre des règles

Dans les pare-feu classiques, l'action (Autoriser ou Refuser) sur un paquet est déterminée par la première règle qu'il satisfait. Dans Kubernetes, l’ordre des politiques n’a pas d’importance.

Par défaut, lorsqu'aucune stratégie n'est définie, les communications entre les pods sont autorisées et ils peuvent échanger librement des informations. Une fois que vous commencez à formuler des politiques, chaque pod affecté par au moins l'une d'entre elles devient isolé en fonction de la disjonction (OU logique) de toutes les politiques qui l'ont sélectionné. Les pods qui ne sont concernés par aucune règle restent ouverts.

Vous pouvez modifier ce comportement à l'aide d'une règle de suppression.

Règle de suppression (« Refuser »)

Les politiques de pare-feu refusent généralement tout trafic qui n'est pas explicitement autorisé.

Il n'y a pas d'action de refus dans Kubernetes, cependant, un effet similaire peut être obtenu avec une politique régulière (permissive) en sélectionnant un groupe vide de pods sources (entrée) :

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

Une introduction aux politiques réseau Kubernetes pour les professionnels de la sécurité

Cette stratégie sélectionne tous les pods dans l'espace de noms et laisse l'entrée indéfinie, refusant ainsi tout le trafic entrant.

De la même manière, vous pouvez restreindre tout le trafic sortant d'un espace de noms :

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

Une introduction aux politiques réseau Kubernetes pour les professionnels de la sécurité

Veuillez noter que toute politique supplémentaire autorisant le trafic vers les pods dans l'espace de noms aura priorité sur cette règle (similaire à l'ajout d'une règle d'autorisation avant une règle de refus dans une configuration de pare-feu).

Tout autoriser (Any-Any-Any-Allow)

Pour créer une stratégie Autoriser tout, vous devez compléter la stratégie Refuser ci-dessus avec un élément vide ingress:

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

Une introduction aux politiques réseau Kubernetes pour les professionnels de la sécurité

Il permet l'accès depuis tous les pods de tous les espaces de noms (et toutes les adresses IP) vers n'importe quel pod de l'espace de noms default. Ce comportement est activé par défaut, il n'est donc généralement pas nécessaire de le définir davantage. Cependant, vous devrez parfois désactiver temporairement certaines autorisations spécifiques pour diagnostiquer le problème.

La règle peut être restreinte pour autoriser l'accès uniquement à un ensemble spécifique de pods (app:balance) dans l'espace de noms default:

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

Une introduction aux politiques réseau Kubernetes pour les professionnels de la sécurité

La stratégie suivante autorise tout le trafic entrant et sortant, y compris l'accès à toute adresse IP en dehors du cluster :

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

Une introduction aux politiques réseau Kubernetes pour les professionnels de la sécurité
Une introduction aux politiques réseau Kubernetes pour les professionnels de la sécurité

Combinaison de plusieurs politiques

Les politiques sont combinées à l'aide d'un OU logique à trois niveaux ; Les autorisations de chaque pod sont définies conformément à la disjonction de toutes les politiques qui l'affectent :

1. Dans les champs from и to Trois types d'éléments peuvent être définis (tous combinés par OU) :

  • namespaceSelector — sélectionne l'intégralité de l'espace de noms ;
  • podSelector — sélectionne les pods ;
  • ipBlock — sélectionne un sous-réseau.

De plus, le nombre d'éléments (même identiques) dans les sous-sections from/to pas limité. Tous seront combinés par OU logique.

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

Une introduction aux politiques réseau Kubernetes pour les professionnels de la sécurité

2. Dans la section politique ingress peut avoir de nombreux éléments from (combiné par OU logique). De même, la section egress peut inclure de nombreux éléments to (également combiné par disjonction):

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

Une introduction aux politiques réseau Kubernetes pour les professionnels de la sécurité

3. Différentes politiques sont également combinées avec un OU logique

Mais en les combinant, il existe une limitation à laquelle indiqué Chris Coney : Kubernetes ne peut combiner des politiques qu'avec différentes policyTypes (Ingress ou Egress). Les politiques définissant l’entrée (ou la sortie) s’écraseront mutuellement.

Relation entre les espaces de noms

Par défaut, le partage d'informations entre les espaces de noms est autorisé. Cela peut être modifié en utilisant une politique de refus qui limitera le trafic sortant et/ou entrant dans l'espace de noms (voir « Règle de suppression » ci-dessus).

Une fois que vous avez bloqué l'accès à un espace de noms (voir la « Règle de suppression » ci-dessus), vous pouvez faire des exceptions à la politique de refus en autorisant les connexions à partir d'un espace de noms spécifique en utilisant 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

Une introduction aux politiques réseau Kubernetes pour les professionnels de la sécurité

Par conséquent, tous les pods de l'espace de noms default aura accès aux pods postgres dans l'espace de noms database. Mais que se passe-t-il si vous souhaitez ouvrir l'accès à postgres uniquement des pods spécifiques dans l'espace de noms default?

Filtrer par espaces de noms et pods

Kubernetes version 1.11 et supérieure vous permet de combiner des opérateurs namespaceSelector и podSelector en utilisant le ET logique. Cela ressemble à ceci :

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

Une introduction aux politiques réseau Kubernetes pour les professionnels de la sécurité

Pourquoi cela est-il interprété comme ET au lieu de l’habituel OU ?

S'il vous plaît noter que podSelector ne commence pas par un trait d'union. En YAML, cela signifie que podSelector et debout devant lui namespaceSelector faire référence au même élément de liste. Par conséquent, ils sont combinés avec un ET logique.

Ajouter un trait d'union avant podSelector entraînera l'émergence d'un nouvel élément de liste, qui sera combiné avec le précédent namespaceSelector en utilisant le OU logique.

Pour sélectionner des modules avec une étiquette spécifique dans tous les espaces de noms, entrez vide 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

Une introduction aux politiques réseau Kubernetes pour les professionnels de la sécurité

Plusieurs labels font équipe avec I

Les règles d'un pare-feu avec plusieurs objets (hôtes, réseaux, groupes) sont combinées à l'aide d'un OU logique. La règle suivante fonctionnera si la source du paquet correspond Host_1 OU Host_2:

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

Au contraire, dans Kubernetes les différents labels de podSelector ou namespaceSelector sont combinés avec un ET logique. Par exemple, la règle suivante sélectionnera les pods qui ont les deux étiquettes, role=db И version=v2:

podSelector:
  matchLabels:
    role: db
    version: v2

La même logique s'applique à tous les types d'opérateurs : sélecteurs de cible de stratégie, sélecteurs de pod et sélecteurs d'espace de noms.

Sous-réseaux et adresses IP (IPBlocks)

Les pare-feu utilisent des VLAN, des adresses IP et des sous-réseaux pour segmenter un réseau.

Dans Kubernetes, les adresses IP sont attribuées automatiquement aux pods et peuvent changer fréquemment. Les étiquettes sont donc utilisées pour sélectionner les pods et les espaces de noms dans les stratégies réseau.

Sous-réseaux (ipBlocks) sont utilisés lors de la gestion des connexions externes (Nord-Sud) entrantes (entrée) ou sortantes (sortie). Par exemple, cette stratégie s'ouvre à tous les pods de l'espace de noms default accès au service Google DNS :

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

Une introduction aux politiques réseau Kubernetes pour les professionnels de la sécurité

Le sélecteur de pod vide dans cet exemple signifie « sélectionner tous les pods dans l'espace de noms ».

Cette politique autorise uniquement l'accès à 8.8.8.8 ; l’accès à toute autre IP est interdit. Donc, en substance, vous avez bloqué l’accès au service DNS interne de Kubernetes. Si vous souhaitez quand même l'ouvrir, indiquez-le explicitement.

Habituellement ipBlocks и podSelectors s'excluent mutuellement, puisque les adresses IP internes des pods ne sont pas utilisées dans ipBlocks. En indiquant modules IP internes, vous autoriserez en fait les connexions vers/depuis les pods avec ces adresses. En pratique, vous ne saurez pas quelle adresse IP utiliser, c’est pourquoi il ne faut pas les utiliser pour sélectionner les pods.

À titre de contre-exemple, la stratégie suivante inclut toutes les IP et autorise donc l'accès à tous les autres 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

Une introduction aux politiques réseau Kubernetes pour les professionnels de la sécurité

Vous pouvez ouvrir l'accès uniquement aux adresses IP externes, à l'exclusion des adresses IP internes des pods. Par exemple, si le sous-réseau de votre pod est 10.16.0.0/14 :

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

Une introduction aux politiques réseau Kubernetes pour les professionnels de la sécurité

Ports et protocoles

Généralement, les pods écoutent un seul port. Cela signifie que vous pouvez simplement ne pas spécifier les numéros de port dans les politiques et tout laisser par défaut. Cependant, il est recommandé de rendre les politiques aussi restrictives que possible, de sorte que dans certains cas, vous pouvez toujours spécifier des ports :

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

Une introduction aux politiques réseau Kubernetes pour les professionnels de la sécurité

Notez que le sélecteur ports s'applique à tous les éléments du bloc to ou from, qui contient. Pour spécifier différents ports pour différents ensembles d'éléments, divisez ingress ou egress en plusieurs sous-sections avec to ou from et dans chaque registre vos 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

Une introduction aux politiques réseau Kubernetes pour les professionnels de la sécurité

Fonctionnement du port par défaut :

  • Si vous omettez complètement la définition du port (ports), cela signifie tous les protocoles et tous les ports ;
  • Si vous omettez la définition du protocole (protocol), cela signifie TCP ;
  • Si vous omettez la définition du port (port), cela signifie tous les ports.

Bonne pratique : ne vous fiez pas aux valeurs par défaut, spécifiez explicitement ce dont vous avez besoin.

Veuillez noter que vous devez utiliser des ports de pod, pas des ports de service (plus de détails à ce sujet dans le paragraphe suivant).

Des politiques sont-elles définies pour les pods ou les services ?

En règle générale, les pods de Kubernetes accèdent les uns aux autres via un service : un équilibreur de charge virtuel qui redirige le trafic vers les pods qui implémentent le service. Vous pourriez penser que les politiques réseau contrôlent l’accès aux services, mais ce n’est pas le cas. Les stratégies réseau Kubernetes fonctionnent sur les ports de pod, pas sur les ports de service.

Par exemple, si un service écoute le port 80, mais redirige le trafic vers le port 8080 de ses pods, vous devez spécifier exactement 8080 dans la stratégie réseau.

Un tel mécanisme doit être considéré comme sous-optimal : si la structure interne du service (les ports sur lesquels les pods écoutent) change, les politiques réseau devront être mises à jour.

Nouvelle approche architecturale utilisant Service Mesh (par exemple, voir à propos d'Istio ci-dessous - traduction approximative.) vous permet de faire face à ce problème.

Est-il nécessaire d'enregistrer à la fois l'entrée et la sortie ?

La réponse courte est oui, pour que le pod A communique avec le pod B, il doit être autorisé à créer une connexion sortante (pour cela, vous devez configurer une politique de sortie), et le pod B doit être capable d'accepter une connexion entrante ( pour cela, vous avez donc besoin d'une politique d'entrée).

Cependant, en pratique, vous pouvez compter sur la stratégie par défaut pour autoriser les connexions dans un sens ou dans les deux.

Si certains pod-source sera sélectionné par un ou plusieurs sortie-politiques, les restrictions qui lui seront imposées seront déterminées par leur disjonction. Dans ce cas, vous devrez autoriser explicitement la connexion au pod -au destinataire. Si un pod n'est sélectionné par aucune stratégie, son trafic sortant (de sortie) est autorisé par défaut.

De même, le sort du pod estdestinataire, sélectionné par un ou plusieurs entrée-les hommes politiques, seront déterminés par leur disjonction. Dans ce cas, vous devez explicitement l'autoriser à recevoir le trafic du pod source. Si un pod n'est sélectionné par aucune stratégie, tout le trafic entrant le concernant est autorisé par défaut.

Voir Avec état ou Apatride ci-dessous.

Les journaux

Les stratégies réseau Kubernetes ne peuvent pas enregistrer le trafic. Cela rend difficile de déterminer si une politique fonctionne comme prévu et complique grandement l’analyse de la sécurité.

Contrôle du trafic vers les services externes

Les stratégies réseau Kubernetes ne vous permettent pas de spécifier un nom de domaine complet (DNS) dans les sections de sortie. Ce fait entraîne des inconvénients importants lorsque l'on tente de limiter le trafic vers des destinations externes qui n'ont pas d'adresse IP fixe (telles que aws.com).

Vérification de la politique

Les pare-feu vous avertiront ou refuseront même d’accepter la mauvaise politique. Kubernetes effectue également quelques vérifications. Lors de la définition d'une politique réseau via kubectl, Kubernetes peut déclarer qu'elle est incorrecte et refuser de l'accepter. Dans d'autres cas, Kubernetes prendra la politique et la remplira avec les détails manquants. Ils peuvent être vus en utilisant la commande :

kubernetes get networkpolicy <policy-name> -o yaml

Gardez à l'esprit que le système de validation Kubernetes n'est pas infaillible et peut manquer certains types d'erreurs.

Exécution

Kubernetes n'implémente pas lui-même de politiques réseau, mais constitue simplement une passerelle API qui délègue la charge de contrôle à un système sous-jacent appelé Container Networking Interface (CNI). Définir des politiques sur un cluster Kubernetes sans attribuer le CNI approprié revient à créer des politiques sur un serveur de gestion de pare-feu sans ensuite les installer sur des pare-feu. A vous de vous assurer d'avoir un CNI décent ou, dans le cas des plateformes Kubernetes, hébergé dans le cloud (vous pouvez voir la liste des prestataires ici - environ. trans.), activez les politiques réseau qui définiront CNI pour vous.

Notez que Kubernetes ne vous avertira pas si vous définissez une politique réseau sans l'assistant CNI approprié.

Avec ou sans état ?

Tous les CNI Kubernetes que j'ai rencontrés sont avec état (par exemple, Calico utilise Linux conntrack). Cela permet au pod de recevoir des réponses sur la connexion TCP qu'il a initiée sans avoir à la rétablir. Cependant, je ne connais pas de norme Kubernetes qui garantirait l'état.

Gestion avancée des politiques de sécurité

Voici quelques façons d’améliorer l’application des politiques de sécurité dans Kubernetes :

  1. Le modèle architectural Service Mesh utilise des conteneurs side-car pour fournir une télémétrie détaillée et un contrôle du trafic au niveau du service. A titre d'exemple nous pouvons prendre Istio.
  2. Certains fournisseurs CNI ont étendu leurs outils pour aller au-delà des politiques réseau Kubernetes.
  3. Orque tufin Fournit une visibilité et une automatisation des politiques réseau Kubernetes.

Le package Tufin Orca gère les politiques réseau Kubernetes (et est la source des captures d'écran ci-dessus).

Informations supplémentaires

Conclusion

Les politiques réseau Kubernetes offrent un bon ensemble d’outils pour segmenter les clusters, mais elles ne sont pas intuitives et comportent de nombreuses subtilités. En raison de cette complexité, je pense que de nombreuses politiques de cluster existantes sont boguées. Les solutions possibles à ce problème incluent l'automatisation des définitions de politiques ou l'utilisation d'autres outils de segmentation.

J'espère que ce guide vous aidera à clarifier certaines questions et à résoudre les problèmes que vous pourriez rencontrer.

PS du traducteur

A lire aussi sur notre blog :

Source: habr.com

Ajouter un commentaire