Retour aux microservices avec Istio. Partie 3

Retour aux microservices avec Istio. Partie 3

Note de traduction.: Première partie Ce cycle était consacré à la découverte des possibilités d'Istio et à leur démonstration en action, la deuxième — une routage finement réglable et la gestion du trafic réseau. Maintenant, nous allons parler de sécurité : pour démontrer les fonctionnalités de base qui y sont liées, l'auteur utilise le service d'identité Auth0, mais d'autres fournisseurs peuvent être configurés de manière similaire.

Nous avons configuré un cluster Kubernetes, dans lequel nous avons déployé Istio et un exemple d'application microservices Sentiment Analysis, démontrant ainsi les capacités d'Istio.

Grâce à Istio, nous avons pu maintenir une petite taille des services, car ils n'ont pas besoin de mettre en œuvre des «couches» telles que les nouvelles tentatives de connexion (Retries), les délais d'attente (Timeouts), les coupe-circuits (Circuit Breakers), le traçage (Tracing) et la surveillance (Monitoring). De plus, nous avons utilisé des techniques avancées de test et de déploiement : test A/B, mirroring et déploiements canari.

Retour aux microservices avec Istio. Partie 3

Dans ce nouvel article, nous allons examiner les couches finales sur le chemin vers la valeur commerciale : l'authentification et l'autorisation — et avec Istio, c'est un pur plaisir !

Authentification et autorisation dans Istio

Je n'aurais jamais cru que je pourrais être inspiré par l'authentification et l'autorisation. Que peut donc offrir Istio, d'un point de vue technologique, pour rendre ces sujets captivants et même plus — pour qu'ils vous inspirent aussi ?

La réponse est simple : Istio déplace la responsabilité de ces capacités de vos services vers le proxy Envoy. Au moment où les requêtes atteignent les services, elles sont déjà authentifiées et autorisées, il vous suffit donc d'écrire du code utile pour l'entreprise.

Ça sonne bien ? Jetons un coup d'œil à l'intérieur !

Authentification avec Auth0

Nous allons utiliser Auth0 comme serveur de gestion d'identité et d'accès, qui a une version d'essai, est intuitivement compréhensible et me plaît tout simplement. Cependant, les mêmes principes peuvent être appliqués à toute autre implémentation OpenID Connect: KeyCloak, IdentityServer et bien d'autres.

Pour commencer, connectez-vous au Auth0 Portal avec votre compte, créez un tenant (tenant — «locataire», unité logique d'isolation, voir plus de détails dans documentation — n.d.t.) et accédez à Applications > Default App, en sélectionnant Domaine, comme indiqué dans la capture d'écran ci-dessous :

Retour aux microservices avec Istio. Partie 3

Indiquez ce domaine dans le fichier resource-manifests/istio/security/auth-policy.yaml (source):

apiVersion: authentication.istio.io/v1alpha1
kind: Policy
metadata:
  name: auth-policy
spec:
  targets:
  - name: sa-web-app
  - name: sa-feedback
  origins:
  - jwt:
      issuer: "https://{YOUR_DOMAIN}/"
      jwksUri: "https://{YOUR_DOMAIN}/.well-known/jwks.json"
  principalBinding: USE_ORIGIN

Avec cette ressource, le Pilot (l’un des trois composants principaux du Control Plane dans Istio — note du traducteur.) configure les Envoy pour authentifier les demandes avant de les rediriger vers les services : sa-web-app et sa-feedback. En même temps, la configuration ne s'applique pas aux Envoy du service sa-frontend, ce qui nous permet de laisser le frontend non authentifié. Pour appliquer la politique (Policy), exécutez la commande :

$ kubectl apply -f resource-manifests/istio/security/auth-policy.yaml
policy.authentication.istio.io “auth-policy” créé

Retournez à la page et effectuez une demande — vous verrez qu'elle se termine avec le statut 401 Unauthorized. Maintenant, redirigeons les utilisateurs du frontend vers l'authentification avec Auth0.

Authentification des demandes avec Auth0

Pour authentifier les demandes de l'utilisateur final, vous devez créer une API dans Auth0 qui représentera les services authentifiés (reviews, details et ratings). Pour créer l'API, allez dans Auth0 Portal > APIs > Create API et remplissez le formulaire :

Retour aux microservices avec Istio. Partie 3

Une information importante ici est Identifier, que nous utiliserons plus tard dans le script. Notons-le comme suit :

  • Audience: {YOUR_AUDIENCE}

Les autres détails nécessaires se trouvent sur le portail Auth0 dans la section Applications — sélectionnez Test Application (créé automatiquement avec l'API).

Ici, nous allons noter :

  • Domaine: {YOUR_DOMAIN}
  • Client Id: {YOUR_CLIENT_ID}

Faites défiler jusqu'au champ de texte Test Application Allowed Callback URLs (URLs autorisées pour le callback), où nous indiquerons l'URL à laquelle l'appel doit être envoyé après la fin de l'authentification. Dans notre cas, c'est : http://{EXTERNAL_IP}/callback

Et pour

Allowed Logout URLs (URLs autorisées pour la déconnexion) ajoutons : http://{EXTERNAL_IP}/logout

Passons au frontend.

Mise à jour du frontend

auth0

Changez de branche . Dans cette branche, le code du frontend a été modifié pour rediriger les utilisateurs vers Auth0 pour l'authentification et utiliser le token JWT dans les demandes aux autres services. Cela a été mis en œuvre de la manière suivante ( référentiel [istio-mastery]analyzeSentence() { fetch('/sentiment', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${auth.getAccessToken()}` // Access Token }, body: JSON.stringify({ sentence: this.textField.getValue() }) }) .then(response => response.json()) .then(data => this.setState(data)); }App.js):

Pour passer le frontend à l'utilisation des données du tenant dans Auth0, ouvrez

Pour traduire le frontend pour qu'il utilise les données du tenant dans Auth0, ouvrez sa-frontend/src/services/Auth.js et remplacez les valeurs que nous avons notées ci-dessus (Auth.js):

const Config = {
    clientID: '{YOUR_CLIENT_ID}',
    domain:'{YOUR_DOMAIN}',
    audience: '{YOUR_AUDIENCE}',
    ingressIP: '{EXTERNAL_IP}' // Utilisé pour la redirection après l'authentification
}

L'application est prête. Indiquez votre Docker ID dans les commandes ci-dessous lors de la construction et du déploiement des modifications apportées :

$ docker build -f sa-frontend/Dockerfile 
 -t $DOCKER_USER_ID/sentiment-analysis-frontend:istio-auth0 
 sa-frontend

$ docker push $DOCKER_USER_ID/sentiment-analysis-frontend:istio-auth0

$ kubectl set image deployment/sa-frontend 
 sa-frontend=$DOCKER_USER_ID/sentiment-analysis-frontend:istio-auth0

Testez l'application ! Vous serez redirigé vers Auth0, où vous devez vous connecter (ou vous inscrire), après quoi vous serez renvoyé à la page à partir de laquelle des requêtes authentifiées seront effectuées. Si vous essayez les commandes curl mentionnées dans les premières parties de l'article, vous obtiendrez le code Code d'état 401, signalant que la demande n'est pas autorisée.

Passons à l'étape suivante : autoriser les requêtes.

Autorisation avec Auth0

L'authentification nous permet de savoir qui est l'utilisateur, mais pour connaître les ressources auxquelles il a accès, l'autorisation est nécessaire. Istio fournit également des outils pour cela.

À titre d'exemple, créons deux groupes d'utilisateurs (voir le schéma ci-dessous) :

  • Utilisateurs (utilisateurs) — ayant accès uniquement aux services SA-WebApp et SA-Frontend ;
  • Modérateurs (modérateurs) — ayant accès aux trois services.

Retour aux microservices avec Istio. Partie 3
Le concept d'autorisation

Pour créer ces groupes, nous utiliserons l'extension Auth0 Authorization et fournirons avec Istio des niveaux d'accès différents.

Installation et configuration de l'autorisation Auth0

Sur le portail Auth0, allez aux extensions (Extensions) et installez Auth0 Authorization. Après l'installation, allez à Authorization Extension, puis allez à la configuration de tenant en cliquant en haut à droite et en choisissant l'option de menu correspondante (Configuration). Activez les groupes (Groups) et cliquez sur le bouton de publication de la règle (Publish rule).

Retour aux microservices avec Istio. Partie 3

Création de groupes

Dans l'Authorization Extension, allez dans Groupes et créez un groupe Modérateurs. Étant donné que nous considérerons tous les utilisateurs authentifiés comme ordinaires, il n'est pas nécessaire de créer un groupe supplémentaire pour eux.

Sélectionnez le groupe Modérateurs, cliquez sur Ajouter des membres, ajoutez votre compte principal. Laissez certains utilisateurs sans groupe pour vous assurer que l'accès leur est refusé. (De nouveaux utilisateurs peuvent être créés manuellement via Auth0 Portal > Users > Create User.)

Ajoutez Group Claim dans le token d'accès

Les utilisateurs ont été ajoutés aux groupes, mais cette information doit également être reflétée dans les jetons d'accès. Pour être conforme à OpenID Connect et en même temps retourner les groupes dont nous avons besoin, le jeton devra ajouter son custom claim. Cela s'implémente via des règles Auth0.

Pour créer une règle, allez sur le portail Auth0 à Rules, cliquez sur Create Rule et choisissez une règle vide parmi les modèles.

Retour aux microservices avec Istio. Partie 3

Copiez le code ci-dessous et enregistrez-le comme une nouvelle règle Add Group Claim (namespacedGroup.js):

function (user, context, callback) {
    context.accessToken['https://sa.io/group'] = user.groups[0];
    return callback(null, user, context);
}

Remarque: ce code prend le premier groupe de l'utilisateur, défini dans l'Extension d'autorisation, et l'ajoute au jeton d'accès comme un custom claim (sous son propre espace de noms, comme le demande Auth0).

Retournez à la page Rules et vérifiez que vous avez deux règles, écrites dans l'ordre suivant :

  • auth0-authorization-extension
  • Add Group Claim

L'ordre est important car le champ de groupe reçoit la règle de manière asynchrone auth0-authorization-extension et est ensuite ajouté comme claim par la deuxième règle. Voici à quoi ressemble le jeton d'accès :

{
 "https://sa.io/group": "Moderators",
 "iss": "https://sentiment-analysis.eu.auth0.com/",
 "sub": "google-oauth2|196405271625531691872"
 // [réduit pour la clarté]
}

Il est maintenant nécessaire de configurer le proxy Envoy pour vérifier l'accès de l'utilisateur, pour ce faire, le groupe sera extrait du claim (https://sa.io/group) dans le jeton d'accès retourné. C'est le sujet de la section suivante de l'article.

Configuration de l'autorisation dans Istio

Pour que l'autorisation fonctionne, il est nécessaire d'activer RBAC pour Istio. Pour cela, nous utiliserons la configuration suivante :

apiVersion: "rbac.istio.io/v1alpha1"
kind: RbacConfig
metadata:
  name: default
spec:
  mode: 'ON_WITH_INCLUSION'                     # 1
  inclusion:
    services:                                   # 2
    - "sa-frontend.default.svc.cluster.local"
    - "sa-web-app.default.svc.cluster.local"
    - "sa-feedback.default.svc.cluster.local" 

Explications :

  • 1 — nous activons RBAC uniquement pour les services et espaces de noms énumérés dans le champ Inclusion;
  • 2 — nous listons nos services.

Appliquons la configuration avec cette commande :

$ kubectl apply -f resource-manifests/istio/security/enable-rbac.yaml
rbacconfig.rbac.istio.io/default créé

Désormais, tous les services nécessitent un contrôle d'accès basé sur les rôles (Role-Based Access Control). En d'autres termes, l'accès à tous les services est interdit et renverra la réponse RBAC: accès refusé. Maintenant, nous allons autoriser l'accès aux utilisateurs autorisés.

Configuration d'accès pour les utilisateurs ordinaires

Tous les utilisateurs doivent avoir accès aux services SA-Frontend et SA-WebApp. Cela s'implémente à l'aide des ressources Istio suivantes :

  • ServiceRole — définit les droits accordés à l'utilisateur ;
  • ServiceRoleBinding — spécifie à qui ce ServiceRole s'applique.

Pour les utilisateurs ordinaires, nous autoriserons l'accès à certains services (servicerole.yaml):

apiVersion: "rbac.istio.io/v1alpha1"
kind: ServiceRole
metadata:
  name: regular-user
  namespace: default
spec:
  rules:
  - services: 
    - "sa-frontend.default.svc.cluster.local" 
    - "sa-web-app.default.svc.cluster.local"
    paths: ["*"]
    methods: ["*"]

Et par le biais de regular-user-binding nous appliquons le ServiceRole à tous les visiteurs de la page (regular-user-service-role-binding.yaml):

apiVersion: "rbac.istio.io/v1alpha1"
kind: ServiceRoleBinding
metadata:
  name: regular-user-binding
  namespace: default
spec:
  subjects:
  - user: "*"
  roleRef:
    kind: ServiceRole
    name: "regular-user"

Cela signifie-t-il que « tous les utilisateurs » inclut les utilisateurs non authentifiés ayant accès à l'application web SA ? Non, la politique vérifiera la validité du jeton JWT.

Appliquons les configurations :

$ kubectl apply -f resource-manifests/istio/security/user-role.yaml
servicerole.rbac.istio.io/regular-user créé
servicerolebinding.rbac.istio.io/regular-user-binding créé

Configuration d'accès pour les modérateurs

Pour les modérateurs, nous souhaitons accorder l'accès à tous les services (mod-service-role.yaml):

apiVersion: "rbac.istio.io/v1alpha1"
kind: ServiceRole
metadata:
  name: mod-user
  namespace: default
spec:
  rules:
  - services: ["*"]
    paths: ["*"]
    methods: ["*"]

Mais nous voulons ces droits uniquement pour les utilisateurs dont le jeton d'accès contient la déclaration https://sa.io/group avec la valeur Modérateurs (mod-service-role-binding.yaml):

apiVersion: "rbac.istio.io/v1alpha1"
kind: ServiceRoleBinding
metadata:
  name: mod-user-binding
  namespace: default
spec:
  subjects:
  - properties:
      request.auth.claims[https://sa.io/group]: "Modérateurs"
  roleRef:
    kind: ServiceRole
name: "mod-user" 

Appliquons les configurations :

$ kubectl apply -f resource-manifests/istio/security/mod-role.yaml
servicerole.rbac.istio.io/mod-user créé
servicerolebinding.rbac.istio.io/mod-user-binding créé

En raison du cache dans les envoy, il peut falloir quelques minutes pour que les règles d'autorisation prennent effet. Après cela, vous pourrez vous assurer que les utilisateurs et les modérateurs ont différents niveaux d'accès.

Conclusion sur cette partie

Sérieusement, avez-vous déjà vu une approche d'authentification et d'autorisation plus simple, sans effort, évolutive et sécurisée ?

Il n'a fallu que trois ressources Istio (RbacConfig, ServiceRole, et ServiceRoleBinding) pour obtenir un contrôle précis sur l'authentification et l'autorisation de l'accès des utilisateurs finaux aux services.

De plus, nous avons externalisé le traitement de ces problèmes à des envoy, obtenant ainsi :

  • une réduction du code standard susceptible de contenir des problèmes de sécurité et des bugs ;
  • la diminution des situations ridicules où un endpoint était accessible de l'extérieur sans en informer.
  • élimination de la nécessité de mettre à jour tous les services à chaque ajout d'un nouveau rôle ou d'un nouveau droit;
  • que les nouveaux services restent simples, sûrs et rapides.

Sortie

Istio permet aux équipes de concentrer leurs ressources sur des tâches importantes pour l'entreprise, sans ajouter de surcharge aux services, les ramenant à leur statut de « micro ».

Cet article (en trois parties) a fourni des connaissances de base et un guide pratique prêt à l'emploi pour commencer à travailler avec Istio dans des projets réels.

P.S. de l'auteur

Lisez aussi dans notre blog :

Source : habr.com

Acheter un hébergement fiable pour les sites avec protection DDoS, serveurs VPS VDS 🔥 Acheter un hébergement fiable pour les sites avec protection DDoS, serveurs VPS VDS | ProHoster