Calico pour le rĂ©seautage dans Kubernetes : introduction et un peu d'expĂ©rience

Calico pour le rĂ©seautage dans Kubernetes : introduction et un peu d'expĂ©rience

Le but de l'article est de présenter au lecteur les bases de la mise en réseau et de la gestion des politiques réseau dans Kubernetes, ainsi que le plugin tiers Calico qui étend les capacités standard. En cours de route, la facilité de configuration et certaines fonctionnalités seront démontrées à l'aide d'exemples réels tirés de notre expérience d'exploitation.

Une introduction rapide Ă  l’appliance rĂ©seau Kubernetes

Un cluster Kubernetes ne peut ĂȘtre imaginĂ© sans rĂ©seau. Nous avons dĂ©jĂ  publiĂ© des documents sur leurs bases : «Un guide illustrĂ© de la mise en rĂ©seau dans Kubernetes"Et"Une introduction aux politiques rĂ©seau Kubernetes pour les professionnels de la sĂ©curité».

Dans le cadre de cet article, il est important de noter que K8s lui-mĂȘme n'est pas responsable de la connectivitĂ© rĂ©seau entre les conteneurs et les nƓuds : pour cela, divers Plugins CNI (Interface rĂ©seau de conteneurs). Pour en savoir plus sur ce concept, nous ils m'ont aussi dit.

Par exemple, le plus courant de ces plugins est Flanelle — fournit une connectivitĂ© rĂ©seau complĂšte entre tous les nƓuds du cluster en Ă©levant des ponts sur chaque nƓud et en lui attribuant un sous-rĂ©seau. Toutefois, une accessibilitĂ© complĂšte et non rĂ©glementĂ©e n’est pas toujours bĂ©nĂ©fique. Pour assurer une sorte d'isolation minimale dans le cluster, il est nĂ©cessaire d'intervenir dans la configuration du pare-feu. Dans le cas gĂ©nĂ©ral, il est placĂ© sous le contrĂŽle du mĂȘme CNI, c'est pourquoi toute intervention de tiers dans iptables peut ĂȘtre mal interprĂ©tĂ©e ou totalement ignorĂ©e.

Et un « prĂȘt Ă  l'emploi Â» pour organiser la gestion des politiques de rĂ©seau dans un cluster Kubernetes est fourni API de politique de rĂ©seau. Cette ressource, rĂ©partie sur des espaces de noms sĂ©lectionnĂ©s, peut contenir des rĂšgles permettant de diffĂ©rencier les accĂšs d'une application Ă  l'autre. Il permet Ă©galement de configurer l'accessibilitĂ© entre des pods, des environnements (espaces de noms) ou des blocs d'adresses IP spĂ©cifiques :

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: test-network-policy
  namespace: default
spec:
  podSelector:
    matchLabels:
      role: 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

Ce n’est pas l’exemple le plus primitif de documents officiels pourrait une fois pour toutes dĂ©courager le dĂ©sir de comprendre la logique du fonctionnement des politiques de rĂ©seau. Cependant, nous essaierons toujours de comprendre les principes et mĂ©thodes de base de traitement des flux de trafic Ă  l'aide des politiques de rĂ©seau...

Il est logique qu'il existe 2 types de trafic : entrant dans le pod (Ingress) et sortant de celui-ci (Egress).

Calico pour le rĂ©seautage dans Kubernetes : introduction et un peu d'expĂ©rience

En fait, la politique est divisée en ces 2 catégories en fonction de la direction du mouvement.

Le prochain attribut requis est un sĂ©lecteur ; celui Ă  qui la rĂšgle s’applique. Il peut s'agir d'un pod (ou d'un groupe de pods) ou d'un environnement (c'est-Ă -dire un espace de noms). Un dĂ©tail important : les deux types de ces objets doivent contenir une Ă©tiquette (Ă©tiquette dans la terminologie Kubernetes) - ce sont ceux avec lesquels les politiciens opĂšrent.

En plus d'un nombre fini de sélecteurs unis par une sorte d'étiquette, il est possible d'écrire des rÚgles comme « Autoriser/refuser tout/tout le monde » dans différentes variantes. A cet effet, des constructions de la forme sont utilisées :

  podSelector: {}
  ingress: []
  policyTypes:
  - Ingress

— dans cet exemple, tous les pods de l'environnement sont bloquĂ©s du trafic entrant. Le comportement inverse peut ĂȘtre obtenu avec la construction suivante :

  podSelector: {}
  ingress:
  - {}
  policyTypes:
  - Ingress

De mĂȘme pour les sortants :

  podSelector: {}
  policyTypes:
  - Egress

- pour l'Ă©teindre. Et voici ce qu'il faut inclure :

  podSelector: {}
  egress:
  - {}
  policyTypes:
  - Egress

Revenant sur le choix d'un plugin CNI pour un cluster, il convient de noter que tous les plugins réseau ne prennent pas en charge NetworkPolicy. Par exemple, Flannel déjà mentionné ne sait pas comment configurer les politiques réseau, ce qui c'est dit directement dans le dépÎt officiel. Une alternative y est également mentionnée - un projet Open Source Calicot, qui élargit considérablement l'ensemble standard des API Kubernetes en termes de politiques réseau.

Calico pour le rĂ©seautage dans Kubernetes : introduction et un peu d'expĂ©rience

Apprendre à connaßtre Calico : théorie

Le plugin Calico peut ĂȘtre utilisĂ© en intĂ©gration avec Flannel (sous-projet Canalaire) ou indĂ©pendamment, couvrant Ă  la fois la connectivitĂ© rĂ©seau et les capacitĂ©s de gestion de la disponibilitĂ©.

Quelles opportunitĂ©s offre l’utilisation de la solution « en boĂźte » K8s et de l’ensemble d’API de Calico ?

Voici ce qui est intĂ©grĂ© Ă  NetworkPolicy :

  • les politiciens sont limitĂ©s par l’environnement ;
  • les stratĂ©gies sont appliquĂ©es aux pods marquĂ©s d’étiquettes ;
  • les rĂšgles peuvent ĂȘtre appliquĂ©es aux pods, aux environnements ou aux sous-rĂ©seaux ;
  • les rĂšgles peuvent contenir des protocoles, des spĂ©cifications de port nommĂ©s ou symboliques.

Voici comment Calico Ă©tend ces fonctions :

  • les politiques peuvent ĂȘtre appliquĂ©es Ă  n’importe quel objet : pod, conteneur, machine virtuelle ou interface ;
  • les rĂšgles peuvent contenir une action spĂ©cifique (interdiction, autorisation, journalisation) ;
  • la cible ou la source des rĂšgles peut ĂȘtre un port, une plage de ports, des protocoles, des attributs HTTP ou ICMP, une IP ou un sous-rĂ©seau (4e ou 6e gĂ©nĂ©ration), des sĂ©lecteurs quelconques (nƓuds, hĂŽtes, environnements) ;
  • De plus, vous pouvez rĂ©guler le passage du trafic Ă  l'aide des paramĂštres DNAT et des politiques de transfert de trafic.

Les premiers commits sur GitHub dans le rĂ©fĂ©rentiel Calico remontent Ă  juillet 2016, et un an plus tard, le projet a pris une position de leader dans l'organisation de la connectivitĂ© rĂ©seau Kubernetes - comme en tĂ©moignent, par exemple, les rĂ©sultats de l'enquĂȘte, rĂ©alisĂ© par The New Stack:

Calico pour le rĂ©seautage dans Kubernetes : introduction et un peu d'expĂ©rience

De nombreuses grandes solutions gĂ©rĂ©es avec K8, telles que Amazon EKS, Azure AKS, Google GKE et d'autres ont commencĂ© Ă  en recommander l'utilisation.

CĂŽtĂ© performances, tout est super ici. En testant son produit, l'Ă©quipe de dĂ©veloppement de Calico a dĂ©montrĂ© des performances astronomiques, exĂ©cutant plus de 50000 500 conteneurs sur 20 nƓuds physiques avec un taux de crĂ©ation de XNUMX conteneurs par seconde. Aucun problĂšme n’a Ă©tĂ© identifiĂ© concernant la mise Ă  l’échelle. De tels rĂ©sultats ont Ă©tĂ© annoncĂ©s dĂ©jĂ  Ă  l'annonce de la premiĂšre version. Des Ă©tudes indĂ©pendantes axĂ©es sur le dĂ©bit et la consommation des ressources confirment Ă©galement que les performances de Calico sont presque aussi bonnes que celles de Flannel. Par exemple:

Calico pour le rĂ©seautage dans Kubernetes : introduction et un peu d'expĂ©rience

Le projet se développe trÚs rapidement, il prend en charge le travail dans les solutions populaires gérées K8s, OpenShift, OpenStack, il est possible d'utiliser Calico lors du déploiement d'un cluster utilisant puisque, il y a des références à la construction de réseaux Service Mesh (Voici un exemple utilisé conjointement avec Istio).

EntraĂźnez-vous avec Calico

Dans le cas général d'utilisation de Kubernetes vanilla, l'installation de CNI revient à utiliser le fichier calico.yaml, téléchargé sur le site officiel, en utilisant kubectl apply -f.

La version actuelle du plugin est gĂ©nĂ©ralement compatible avec les deux ou trois derniĂšres versions de Kubernetes ; la compatibilitĂ© avec les versions antĂ©rieures n'est ni testĂ©e ni garantie. D'aprĂšs les dĂ©veloppeurs, Calico s'exĂ©cute au niveau du noyau. Linux au-dessus de 3.10 sous contrĂŽle CentOS 7, Ubuntu 16 ou Debian 8, via iptables ou IPVS.

Isolement dans l'environnement

Pour une comprĂ©hension gĂ©nĂ©rale, examinons un cas simple pour comprendre en quoi les politiques de rĂ©seau dans la notation Calico diffĂšrent des politiques standard et comment l'approche de crĂ©ation de rĂšgles simplifie leur lisibilitĂ© et leur flexibilitĂ© de configuration :

Calico pour le rĂ©seautage dans Kubernetes : introduction et un peu d'expĂ©rience

Il y a 2 applications web déployées dans le cluster : en Node.js et PHP, dont une utilise Redis. Pour bloquer l'accÚs à Redis depuis PHP, tout en conservant la connectivité avec Node.js, appliquez simplement la stratégie suivante :

kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
  name: allow-redis-nodejs
spec:
  podSelector:
    matchLabels:
      service: redis
  ingress:
  - from:
    - podSelector:
        matchLabels:
          service: nodejs
    ports:
    - protocol: TCP
      port: 6379

Essentiellement, nous avons autorisĂ© le trafic entrant vers le port Redis depuis Node.js. Et ils n’ont clairement rien interdit d’autre. DĂšs que NetworkPolicy apparaĂźt, tous les sĂ©lecteurs qui y sont mentionnĂ©s commencent Ă  ĂȘtre isolĂ©s, sauf indication contraire. Toutefois, les rĂšgles d'isolement ne s'appliquent pas aux autres objets non couverts par le sĂ©lecteur.

L'exemple utilise apiVersion Kubernetes prĂȘt Ă  l'emploi, mais rien ne vous empĂȘche de l'utiliser ressource du mĂȘme nom de la livraison Calico. La syntaxe y est plus dĂ©taillĂ©e, vous devrez donc réécrire la rĂšgle pour le cas ci-dessus sous la forme suivante :

apiVersion: crd.projectcalico.org/v1
kind: NetworkPolicy
metadata:
  name: allow-redis-nodejs
spec:
  selector: service == 'redis'
  ingress:
  - action: Allow
    protocol: TCP
    source:
      selector: service == 'nodejs'
    destination:
      ports:
      - 6379

Les constructions mentionnées ci-dessus pour autoriser ou refuser tout le trafic via l'API NetworkPolicy standard contiennent des constructions avec des parenthÚses difficiles à comprendre et à mémoriser. Dans le cas de Calico, pour changer la logique d'une rÚgle de pare-feu en sens inverse, il suffit de changer action: Allow sur action: Deny.

Isolement par environnement

Imaginez maintenant une situation dans laquelle une application génÚre des métriques commerciales à collecter dans Prometheus et à analyser plus en profondeur à l'aide de Grafana. Le téléchargement peut contenir des données sensibles, qui sont à nouveau visibles publiquement par défaut. Cachons ces données aux regards indiscrets :

Calico pour le rĂ©seautage dans Kubernetes : introduction et un peu d'expĂ©rience

Prometheus, en rĂšgle gĂ©nĂ©rale, est placĂ© dans un environnement de service distinct - dans l'exemple, il s'agira d'un espace de noms comme celui-ci :

apiVersion: v1
kind: Namespace
metadata:
  labels:
    module: prometheus
  name: kube-prometheus

Champ metadata.labels cela s’est avĂ©rĂ© n’ĂȘtre pas un hasard. Comme mentionnĂ© ci-dessus, namespaceSelector (aimer podSelector) fonctionne avec des Ă©tiquettes. Par consĂ©quent, pour permettre aux mĂ©triques d'ĂȘtre extraites de tous les pods sur un port spĂ©cifique, vous devrez ajouter une sorte d'Ă©tiquette (ou en extraire des Ă©tiquettes existantes), puis appliquer une configuration telle que :

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-metrics-prom
spec:
  podSelector: {}
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          module: prometheus
    ports:
    - protocol: TCP
      port: 9100

Et si vous utilisez les politiques Calico, la syntaxe sera la suivante :

apiVersion: crd.projectcalico.org/v1
kind: NetworkPolicy
metadata:
  name: allow-metrics-prom
spec:
  ingress:
  - action: Allow
    protocol: TCP
    source:
      namespaceSelector: module == 'prometheus'
    destination:
      ports:
      - 9100

En général, en ajoutant ce type de politiques pour des besoins spécifiques, vous pouvez vous protéger contre les interférences malveillantes ou accidentelles dans le fonctionnement des applications du cluster.

La meilleure pratique, selon les crĂ©ateurs de Calico, est l'approche « Bloquez tout et ouvrez explicitement ce dont vous avez besoin Â», documentĂ©e dans documents officiels (d'autres suivent une approche similaire - notamment dans article dĂ©jĂ  mentionnĂ©).

Utilisation d'objets Calico supplémentaires

Permettez-moi de vous rappeler que grĂące Ă  l'ensemble Ă©tendu d'API Calico, vous pouvez rĂ©guler la disponibilitĂ© des nƓuds, sans se limiter aux pods. Dans l'exemple suivant, en utilisant GlobalNetworkPolicy la possibilitĂ© de transmettre des requĂȘtes ICMP dans le cluster est fermĂ©e (par exemple, les pings d'un pod vers un nƓud, entre pods ou d'un nƓud vers un pod IP) :

apiVersion: crd.projectcalico.org/v1
kind: GlobalNetworkPolicy
metadata:
  name: block-icmp
spec:
  order: 200
  selector: all()
  types:
  - Ingress
  - Egress
  ingress:
  - action: Deny
    protocol: ICMP
  egress:
  - action: Deny
    protocol: ICMP

Dans le cas ci-dessus, il est toujours possible pour les nƓuds du cluster de « se contacter » via ICMP. Et ce problĂšme est rĂ©solu au moyen GlobalNetworkPolicy, appliquĂ© Ă  une entitĂ© HostEndpoint:

apiVersion: crd.projectcalico.org/v1
kind: GlobalNetworkPolicy
metadata:
  name: deny-icmp-kube-02
spec:
  selector: "role == 'k8s-node'"
  order: 0
  ingress:
  - action: Allow
    protocol: ICMP
  egress:
  - action: Allow
    protocol: ICMP
---
apiVersion: crd.projectcalico.org/v1
kind: HostEndpoint
metadata:
  name: kube-02-eth0
  labels:
    role: k8s-node
spec:
  interfaceName: eth0
  node: kube-02
  expectedIPs: ["192.168.2.2"]

Le cas du VPN

Enfin, je donnerai un exemple trĂšs rĂ©el d'utilisation des fonctions Calico dans le cas d'une interaction quasi-cluster, lorsqu'un ensemble standard de politiques ne suffit pas. Pour accĂ©der Ă  l'application Web, les clients utilisent un tunnel VPN, et cet accĂšs est Ă©troitement contrĂŽlĂ© et limitĂ© Ă  une liste spĂ©cifique de services dont l'utilisation est autorisĂ©e :

Calico pour le rĂ©seautage dans Kubernetes : introduction et un peu d'expĂ©rience

Les clients se connectent au VPN via le port UDP standard 1194 et, une fois connectés, reçoivent des routes vers les sous-réseaux de cluster de pods et de services. Des sous-réseaux entiers sont poussés afin de ne pas perdre de services lors des redémarrages et des changements d'adresse.

Le port dans la configuration est standard, ce qui impose quelques nuances sur le processus de configuration de l'application et de son transfert vers le cluster Kubernetes. Par exemple, dans le mĂȘme AWS LoadBalancer pour UDP est apparu littĂ©ralement Ă  la fin de l'annĂ©e derniĂšre dans une liste limitĂ©e de rĂ©gions, et NodePort ne peut pas ĂȘtre utilisĂ© en raison de son transfert sur tous les nƓuds du cluster et il est impossible de faire Ă©voluer le nombre d'instances de serveur pour Ă  des fins de tolĂ©rance aux pannes. De plus, vous devrez modifier la plage de ports par dĂ©faut...

Suite Ă  la recherche de solutions possibles, les solutions suivantes ont Ă©tĂ© retenues :

  1. Les pods avec VPN sont planifiĂ©s par nƓud dans hostNetwork, c'est-Ă -dire Ă  l'adresse IP rĂ©elle.
  2. Le service est affichĂ© Ă  l'extĂ©rieur via ClusterIP. Un port est physiquement installĂ© sur le nƓud, accessible de l'extĂ©rieur avec de lĂ©gĂšres rĂ©serves (prĂ©sence conditionnelle d'une vĂ©ritable adresse IP).
  3. DĂ©terminer le nƓud sur lequel la gousse a poussĂ© dĂ©passe le cadre de notre histoire. Je dirai simplement que vous pouvez « clouer » Ă©troitement le service sur un nƓud ou Ă©crire un petit service side-car qui surveillera l'adresse IP actuelle du service VPN et modifiera les enregistrements DNS enregistrĂ©s auprĂšs des clients - celui qui a assez d'imagination.

Du point de vue du routage, nous pouvons identifier de maniĂšre unique un client VPN par son adresse IP Ă©mise par le serveur VPN. Vous trouverez ci-dessous un exemple primitif de restriction de l'accĂšs d'un tel client aux services, illustrĂ© sur le Redis mentionnĂ© ci-dessus :

apiVersion: crd.projectcalico.org/v1
kind: HostEndpoint
metadata:
  name: vpnclient-eth0
  labels:
    role: vpnclient
    environment: production
spec:
  interfaceName: "*"
  node: kube-02
  expectedIPs: ["172.176.176.2"]
---
apiVersion: crd.projectcalico.org/v1
kind: GlobalNetworkPolicy
metadata:
  name: vpn-rules
spec:
  selector: "role == 'vpnclient'"
  order: 0
  applyOnForward: true
  preDNAT: true
  ingress:
  - action: Deny
    protocol: TCP
    destination:
      ports: [6379]
  - action: Allow
    protocol: UDP
    destination:
      ports: [53, 67]

Ici, la connexion au port 6379 est strictement interdite, mais en mĂȘme temps le fonctionnement du service DNS est prĂ©servĂ©, dont le fonctionnement souffre bien souvent lors de l'Ă©laboration des rĂšgles. Parce que, comme mentionnĂ© prĂ©cĂ©demment, lorsqu'un sĂ©lecteur apparaĂźt, la politique de refus par dĂ©faut lui est appliquĂ©e, sauf indication contraire.

Les résultats de

Ainsi, grùce à l'API avancée de Calico, vous pouvez configurer de maniÚre flexible et modifier dynamiquement le routage dans et autour du cluster. En général, son utilisation peut ressembler à tirer des moineaux avec un canon, et implémenter un réseau L3 avec des tunnels BGP et IP-IP semble monstrueux dans une simple installation Kubernetes sur un réseau plat... Cependant, sinon l'outil semble tout à fait viable et utile .

Il n'est pas toujours possible d'isoler un cluster pour répondre aux exigences de sécurité, et c'est là que Calico (ou une solution similaire) vient à la rescousse. Les exemples donnés dans cet article (avec des modifications mineures) sont utilisés dans plusieurs installations de nos clients dans AWS.

PS

A lire aussi sur notre blog :

Source: habr.com

Achetez un hĂ©bergement fiable pour les sites avec protection DDoS, serveurs VPS VDS đŸ”„ Achetez un hĂ©bergement web fiable avec protection DDoS, serveurs VPS et VDS | ProHoster