Amélioration de la sécurité des microservices avec Istio

salut! Je m'appelle Ilya, je travaille en tant qu'ingénieur DevOps dans l'équipe de développement. Nous utilisons activement une approche de microservices et, en raison des spécificités de notre travail, la sécurité de la communication interservices est importante pour nous. Dans cet article, je souhaite décrire le fonctionnement d'Istio et vous montrer comment utiliser certaines de ses fonctionnalités de sécurité par exemple. J'espère que cela sera utile pour résoudre vos problèmes. Bonne lecture!







À quoi sert un réseau de service?



Le service mesh, dans ce cas Istio, est une liaison pour tout ce qui est nécessaire pour gérer et configurer la communication interservices: routage, authentification, autorisation, traçage, contrôle d'accès, et bien plus encore. Et bien qu'il existe de nombreuses bibliothèques open source pour implémenter ces fonctions directement dans le code du service, avec Istio, vous pouvez obtenir tout de même sans rien ajouter au service lui-même.



Composants 



Article écrit pour istio 1.6


À propos des changements
Istio , . , , - , , . , , Istio 1.4   v1beta1 , Istio RBAC. 1.5 , Pilot, Galley Citadel istiod. - . .



Istio est logiquement divisé en un plan de données et un plan de contrôle.

Le plan de données est un ensemble de serveurs proxy (Envoy) ajoutés au pod sous la forme de side-cars. Ces proxys fournissent et contrôlent toutes les communications réseau entre les microservices et sont configurés à partir du plan de contrôle.



Le plan de gestion (istiod) fournit la découverte de services, la configuration et la gestion des certificats. Il convertit les objets Istio en configurations compatibles Envoy et les distribue dans le plan de données.







Composants de maillage de service Istio



Vous pouvez ajouter l'envoyé au module d'application soit manuellement, soit en configurant l'ajout automatique à l'aide du webhook Mutating Admission, qu'Istio ajoute lors de son installation. Pour ce faire, placez le libellé istio-injection = enabled sur l'espace de noms nécessaire.



En plus du side-car proxy avec envoyé, Istio ajoutera un conteneur d'initialisation spécial au pod qui redirigera le trafic de combat vers le conteneur avec envoyé. Mais comment y parvenir? Dans ce cas, il n'y a pas de magie, et ceci est implémenté en installant des règles iptables supplémentaires dans l'espace de noms réseau du pod.



À propos de la consommation des ressources
, 100 Istio ~2-3 , envoy 40 , CPU 5%-7% pod.



Voyons en pratique comment un side-car capture le trafic entrant et sortant d'un conteneur. Pour ce faire, examinons plus en détail l'espace réseau d'un pod avec le side-car ajouté par Istio. 



Stand de démonstration
Kubernetes Istio. 

Kubernetes minikube:



Linux:
curl -Lo minikube https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64 && chmod +x minikube
sudo mkdir -p /usr/local/bin/
sudo install minikube /usr/local/bin/

minikube start --driver=<driver_name> // --driver=none        .




MacOS:
brew install minikube
minikube start --driver=<driver_name>






Istio demo :



curl -L https://istio.io/downloadIstio | sh -
cd istio-1.6.3
export PATH=$PWD/bin:$PATH
istioctl install --set profile=demo


: productpage details. Istio .



kubectl label namespace default istio-injection=enabled
kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml








Voyons une liste de conteneurs pour l'application productpage:



kubectl -n default get pods productpage-v1-7df7cb7f86-ntwzz -o jsonpath="{.spec['containers','initContainers'][*].name}"
productpage 
istio-proxy 
istio-init


En plus de la page produit elle-même, le sidecar istio-proxy (le même envoyé) et le conteneur d'initialisation istio-init fonctionnent dans le pod.



Vous pouvez consulter les règles iptables configurées dans l'espace pod à l'aide de l'utilitaire nsenter. Pour ce faire, nous devons trouver le pid du processus de conteneur:



docker inspect k8s_productpage --format '{{ .State.Pid }}'
16286


Maintenant, nous pouvons voir les règles iptables définies dans ce conteneur.







Vous pouvez voir que presque tout le trafic entrant et sortant est maintenant intercepté et redirigé vers les ports sur lesquels l'envoyé l'attend déjà. 



Activer le chiffrement mutuel du trafic



Les objets Policy et MeshPolicy ont été supprimés d'istio 1.6. Au lieu de cela, il est suggéré d'utiliser l'objet PeerAuthentication


Istio vous permet de crypter tout le trafic entre les conteneurs, et les applications elles-mêmes ne sauront même pas qu'elles communiquent via tls. Ceci est fait par Istio lui-même prêt à l'emploi avec littéralement un manifeste, car les certificats clients sont déjà montés dans le side-car proxy. 



L'algorithme est le suivant: 



  1. Les mandataires d'envoi côté client et côté serveur s'authentifient mutuellement avant d'envoyer des requêtes;

  2. Si la vérification réussit, le proxy client crypte le trafic et l'envoie au proxy serveur;

  3. Le côté serveur proxy décrypte le trafic et le redirige localement vers le service de destination réel.



Vous pouvez activer mTLS à différents niveaux:



  • Au niveau de l'ensemble du réseau;

  • Au niveau de l'espace de noms;

  • Au niveau d'un pod spécifique. 



Modes de fonctionnement:



  • PERMIS: le trafic chiffré et en texte brut est autorisé;

  • STRICT: seul TLS est autorisé;

  • DESACTIVER: seul le texte brut est autorisé.



Examinons le service de détails du pod de page produit en utilisant curl sans TLS activé et voyons ce qui arrive aux détails en utilisant tcpdump:



Demande:







Dump traffic:







Tout le corps et les en-têtes sont parfaitement lisibles en texte brut.



Activez tls. Pour ce faire, créez un objet de type PeerAuthentication dans l'espace de noms avec nos pods.



apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
  name: default
  namespace: default
spec:
  mtls:
    mode: STRICT


Exécutons à nouveau la demande depuis la page du produit vers les détails et voyons ce que nous obtenons: Le







trafic est crypté



S'identifier



Les objets ClusterRbacConfig, ServiceRole et ServiceRoleBinding ont été supprimés avec la mise en œuvre de la nouvelle stratégie d'autorisation. À la place, il est proposé d'utiliser l'objet AuthorizationPolicy.


À l'aide de politiques d'autorisation, Istio peut configurer une application pour accéder à une autre. De plus, contrairement aux stratégies de réseau Kubernetes pures, cela fonctionne au niveau L7. Par exemple, pour le trafic http, vous pouvez affiner les méthodes de requête et les chemins.



Comme nous l'avons vu dans l'exemple précédent, par défaut, l'accès est ouvert à tous les pods de l'ensemble du cluster.



Maintenant, nous allons désactiver toutes les activités dans l'espace de noms par défaut à l'aide du fichier yaml suivant:



apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: deny-all
  namespace: default
spec:
  {}


Et essayez d'accéder au service de détails:



curl details:9080
RBAC: access denied


Génial, maintenant notre demande échoue.



Maintenant, configurons l'accès de sorte que seule une demande GET passe et uniquement le long du chemin / details, et que toutes les autres demandes soient rejetées. Il existe plusieurs options pour cela:



  • Vous pouvez configurer que les demandes avec des en-têtes spécifiques passent;

  • Par le compte de service de l'application;

  • Par adresse IP sortante;

  • Par l'espace de noms sortant;

  • Par revendications dans le jeton JWT.



Le plus simple à maintenir consiste à configurer l'accès au compte de service de l'application, car aucune préconfiguration n'est requise pour cela, car l'application de démonstration bookinfo est déjà livrée avec un compte de service créé et monté.



Pour utiliser des stratégies d'autorisation basées sur des comptes de service, vous devez activer l'authentification mutuelle TLS.


Mettre en place une nouvelle politique d'accès:



apiVersion: "security.istio.io/v1beta1"
kind: "AuthorizationPolicy"
metadata:
  name: "details-viewer"
  namespace: default
spec:
  selector:
    matchLabels:
      app: details
  rules:
  - from:
    - source:
        principals: ["cluster.local/ns/default/sa/bookinfo-productpage"]
    to:
    - operation:
        methods: ["GET"]
        paths: ["/details/*"]


Et nous essayons de tendre la main à nouveau:



root@productpage-v1-6b64c44d7c-2fpkc:/# curl details:9080/details/0
{"id":0,"author":"William Shakespeare","year":1595,"type":"paperback","pages":200,"publisher":"PublisherA","language":"English","ISBN-10":"1234567890","ISBN-13":"123-1234567890"}


Tout fonctionne. Essayons d'autres méthodes et façons:



root@productpage-v1-6b64c44d7c-2fpkc:/# curl -XPOST details:9080/details/0
RBAC: access denied
root@productpage-v1-6b64c44d7c-2fpkc:/# 
root@productpage-v1-6b64c44d7c-2fpkc:/# curl -XGET details:9080/ping
RBAC: access denied


Conclusion



En conclusion, je note que les opportunités envisagées ne représentent qu'une fraction de ce qu'Istio peut faire. Dès la sortie de l'emballage, nous avons reçu et configuré le chiffrement et l'autorisation du trafic interservices, mais au prix de l'ajout de composants supplémentaires et, par conséquent, d'une consommation de ressources supplémentaire. 



Merci à tous!



All Articles