SOA / Microservices: comment gérer les autorisations dans les communications interservices?

18

Premier plan

Nous passons d'une plate-forme monolithique à une architecture davantage orientée services. Nous appliquons des principes DDD très basiques et divisons notre domaine dans différents contextes bornés. Chaque domaine est distribué et expose un service via une API web (REST).

En raison de la nature de notre entreprise, nous avons des services tels que les réservations , les services , les clients , les produits , etc.

Nous avons également mis en place un Identity Server (basé sur Thinktecture Identity Server 3) dont le rôle principal est de:

  • Centraliser l'authentification (compte tenu des informations d'identification, il émet des jetons)
  • Ajoutez des revendications dans les jetons tels que: les étendues du client (par client, je veux dire l'application qui fait la demande), l'identifiant du client (par client, je veux dire la personne qui utilise l'application)

Nous avons également introduit le rôle d'une passerelle API qui centralise l'accès externe à nos services. API Gateway fournit des fonctionnalités qui ne nécessitent pas une connaissance approfondie des domaines internes tels que:

  • Proxy inverse: achemine les demandes entrantes vers le service interne approprié
  • Gestion des versions: une version de la passerelle API correspond à différentes versions des services internes
  • Authentification: les demandes des clients incluent le jeton émis par Identity Server et la passerelle API valide le jeton (assurez-vous que l'utilisateur est bien celui qui le dit)
  • Limitation: limiter le nombre de demandes par client

Autorisation

En ce qui concerne l'autorisation, celle-ci n'est pas gérée dans l'API Gateway mais dans les services internes lui-même. Nous effectuons actuellement 2 principaux types d'autorisations:

  • Autorisation basée sur les étendues client. Exemple: un client (application externe consommant nos API) a besoin de la portée "bookings" pour accéder aux points de terminaison de l'API Bookings service
  • Autorisation basée sur le client. Exemple: uniquement si un client (personne physique utilisant l'application) participant à une réservation peut accéder au point de terminaison GET / réservations à partir du service Réservations

Pour pouvoir gérer l'autorisation dans les services internes, l'API Gateway transfère simplement le jeton (lors du routage de la demande vers le service interne) qui comprend à la fois des informations sur le client (l'application qui fait la demande) et le client en tant que réclamation (dans les cas où une personne est connectée dans l'application client).

Description du problème

Jusqu'ici tout va bien jusqu'à ce que nous introduisions la communication interservices (certains services peuvent communiquer avec d'autres services pour obtenir des données).

Question

Comment aborder l'autorisation dans les communications interservices?

Options envisagées

Pour discuter des différentes options, j'utiliserai l'exemple de scénario suivant:

  • Nous avons une application externe appelée ExternalApp qui accède à notre API ( ExternalApp peut être vu comme le client ) afin de construire le flux de réservation
  • ExternalApp a besoin d'accéder au service de réservations , c'est pourquoi nous accordons à ExternalApp la portée "réservations"
  • En interne (c'est quelque chose de complètement transparent pour ExternalApp ) le service Réservations accède au service Services pour obtenir les services par défaut d'une réservation comme les vols, les assurances ou la location de voiture

Lorsque vous discutez de ce problème en interne, plusieurs options sont apparues, mais nous ne savons pas quelle option est la meilleure:

  1. Lorsque Bookings communique avec les services , il doit simplement transmettre le jeton d'origine qu'il a reçu de la passerelle API (indiquant que le client est le ExternalApp )
    • Implications: nous pourrions avoir besoin d'accorder des étendues à ExternalApp qui n'auraient pas dû être accordées. Exemple: ExternalApp peut avoir besoin d'avoir à la fois la portée "réservations" et "services" alors que seule la portée "réservations" aurait pu suffire
  2. Lorsque Bookings communique avec les services , il transmet un jeton indiquant que le client est devenu Bookings (au lieu de ExternalApp ) + il ajoute une réclamation indiquant que Bookings emprunte l'identité du client d'origine ExternalApp
    • En incluant également les informations selon lesquelles le client d'origine est l'application externe, le service Services pourrait également faire une logique telle que le filtrage de certains services en fonction de l'appelant d'origine (par exemple, pour les applications internes, nous devrions renvoyer tous les combats, pour les applications externes seulement certaines)
  3. Les services ne devraient pas communiquer entre eux (nous ne devrions donc même pas être confrontés à cette question)

Merci d'avance pour votre contribution.

Josep Serra
la source
1
Comment avez-vous résolu ce problème ? Nous sommes dans une situation similaire.
Varun Mehta
+1: Je suis intéressé par la façon dont vous résolvez enfin votre problème.
Dypso
Pour faire le point 3 - les services ne communiquent pas entre eux, vous avez besoin d'une interface utilisateur composite. Voir particular.net/blog/secret-of-better-ui-composition
stevie_c

Réponses:

3

Je vous conseille d'avoir un canal de communication interne entre les microservices.

Par exemple, utiliser un courtier de messages comme RabbitMQ en interne pour envoyer / recevoir ou publier / souscrire les messages entre microservices.

Ensuite, votre premier utilisateur face au service "dans votre exemple, le service de réservation" sera chargé de valider le jeton et d'autoriser le client à effectuer cette opération spécifique en communiquant avec IdentityServer.

Ensuite, il communiquera avec le service Services via Message Broker et dans ce cas, il n'est pas nécessaire de valider à nouveau le jeton.

Je suppose que ce modèle sera plus simple et vous donnera de meilleures performances.

Wahid Bitar
la source