Système d'autorisation et d'authentification pour microservices et consommateurs

15

Nous prévoyons de refaçonner notre système d'entreprise en un système basé sur des micro-services. Ces micro-services seront utilisés par nos propres applications internes à l'entreprise et par des partenaires tiers si nécessaire. Un pour la réservation, un pour les produits, etc.

Nous ne savons pas comment gérer les rôles et les étendues. L'idée est de créer 3 rôles d'utilisateur de base tels que les administrateurs, les agents et les utilisateurs finaux et de laisser les applications grand public affiner les portées si nécessaire.

  • Les administrateurs peuvent créer, mettre à jour, lire et supprimer toutes les ressources par défaut (pour leur entreprise).
  • Les agents peuvent créer, mettre à jour et lire des données pour leur entreprise.
  • Les utilisateurs finaux peuvent créer, mettre à jour, supprimer et lire des données, mais ne peuvent pas accéder aux mêmes points de terminaison que les agents ou les administrateurs. Ils pourront également créer ou modifier des données, mais pas au même niveau que les agents ou les administrateurs. Par exemple, les utilisateurs finaux peuvent mettre à jour ou lire leurs informations de compte, tout comme l'agent pourra le faire pour eux, mais ils ne peuvent pas voir ou mettre à jour les notes d'administration.

Disons que les agents par défaut peuvent créer, lire et mettre à jour chaque ressource pour leur entreprise et que c'est leur portée maximale qui peut être demandée pour leur jeton / session, mais les développeurs de l'application client (consommateur d'API) ont décidé qu'un de leurs agents peut lire et créer uniquement certaines ressources.

Est-il préférable de gérer cela dans notre sécurité interne et de les laisser écrire ces données dans notre base de données, ou de laisser les clients gérer cela en interne en demandant un jeton avec une portée moindre, et de les laisser écrire quel agent aura quelle étendue dans leur base de données ? De cette façon, nous n'aurions à suivre que les portées de jetons.

L'inconvénient est que notre équipe devra également créer des mécanismes d'accès affinés dans nos applications internes.

Avec cette façon de penser, les micro-services et leur système d'autorisation ne devraient pas être dérangés par les besoins des clients, car ils ne sont que des consommateurs et ne font pas partie du système (même si certains de ces consommateurs sont nos propres applications internes)?

Cette délégation est-elle une bonne approche?

Robert
la source

Réponses:

14

L'authentification et l'autorisation sont toujours de bons sujets

Je vais essayer de vous expliquer comment nous traitons les autorisations dans le service multi-locataire actuel que je travaille. L'authentification et l'autorisation sont basées sur des jetons, en utilisant la norme ouverte JSON Web Token. Le service expose une API REST à laquelle tout type de client (applications Web, mobiles et de bureau) peut accéder. Lorsqu'un utilisateur est authentifié avec succès, le service fournit un jeton d'accès qui doit être envoyé à chaque demande au serveur.

Permettez-moi donc de présenter quelques concepts que nous utilisons en fonction de la façon dont nous percevons et traitons les données sur l'application serveur.

Ressource : il s'agit de toute unité ou groupe de données auquel un client peut accéder via le service. À toutes les ressources que nous voulons contrôler, nous attribuons un seul nom. Par exemple, ayant les prochaines règles de point de terminaison, nous pouvons les nommer comme suit:

product

/products
/products/:id

payment

/payments/
/payments/:id

order

/orders
/orders/:id
/orders/:id/products
/orders/:id/products/:id

Disons que jusqu'à présent, nous avons trois ressources à notre service; product, paymentet order.

Action : Il s'agit d'une opération qui peut être effectuée sur une ressource, comme, lire, créer, mettre à jour, supprimer, etc. Il n'est pas nécessaire d'être uniquement les opérations CRUD classiques, vous pouvez avoir une action nommée follow, par exemple, si vous souhaitez exposer un service qui propage une sorte d'informations à l'aide de WebSockets.

Capacité : La capacité d'effectuer un actionsur un resource. Par exemple; lire des produits, créer des produits, etc. Il s'agit essentiellement d'une paire ressource / action. Mais vous pouvez également y ajouter un nom et une description.

Rôle : ensemble de capacités qu'un utilisateur peut posséder. Par exemple, un rôle Cashierpeut avoir les capacités "lire le paiement", "créer un paiement" ou un rôle Sellerpeut avoir les capacités "lire le produit", "lire la commande", "mettre à jour la commande", "supprimer la commande".

Enfin, un utilisateur peut se voir attribuer différents rôles.


Explication

Comme je l'ai déjà dit, nous utilisons le jeton Web JSON et les capacités qu'un utilisateur possède sont déclarées dans la charge utile du jeton. Supposons donc que nous ayons un utilisateur avec les rôles de caissier et de vendeur en même temps, pour un petit magasin de détail. La charge utile ressemblera à ceci:

{
    "scopes": {
        "payment": ["read", "create"],
        "order": ["read", "create", "update", "delete"]
    }
}

Comme vous pouvez le voir dans la scopesréclamation, nous ne précisons pas le nom des rôles (caissier, vendeur), mais uniquement les ressources et les actions impliquées sont spécifiées. Lorsqu'un client envoie une demande à un point de terminaison, le service doit vérifier si le jeton d'accès contient la ressource et l'action requises. Par exemple, une GETdemande au point de terminaison /payments/88aboutira, mais une DELETEdemande au même point de terminaison doit échouer.


  • Comment regrouper et nommer les ressources et comment définir et nommer les actions et les capacités seront une décision prise par les développeurs.

  • Quels sont les rôles et quelles capacités auront ces rôles, sont les décisions prises par les clients.


Bien sûr, vous devez ajouter des propriétés supplémentaires à la charge utile afin d'identifier l'utilisateur et le client (locataire) qui a émis le jeton.

{
    "scopes": {
        ...
    },
    "tenant": "acme",
    "user":"coyote"
}

Avec cette méthode, vous pouvez affiner l'accès de n'importe quel compte d'utilisateur à votre service. Et le plus important, vous n'avez pas à créer divers rôles prédéfinis et statiques, comme Admin, Agents et Utilisateurs finaux comme vous le faites remarquer dans votre question. Un super utilisateur sera un utilisateur qui possède un roleavec tous les resourceset actionsdu service qui lui sont attribués.

Maintenant, que se passe-t-il s'il y a 100 ressources et que nous voulons un rôle qui donne accès à toutes ou presque toutes?. Notre charge utile symbolique serait énorme. Cela est résolu en imbriquant les ressources et en ajoutant simplement la ressource parent dans la portée du jeton d'accès.


L'autorisation est un sujet complexe qui doit être traité en fonction des besoins de chaque application.

miso
la source
Merci pour votre réponse. C'est très utile. J'ai une question concernant plusieurs rôles par utilisateur. Avez-vous déjà rencontré un cas où les autorisations de rôle se chevauchent? Tels que le caissier a payment:[read], le vendeur a payment: [create]. Agrégez-vous les autorisations dans ce cas?
Robert
Si vous avez des rôles avec des capacités répétées (resource/action), vous devez les fusionner. Si les autorisations se chevauchent, vous devez les agréger. L'idée est de définir uniquement les ressources et les actions autorisées dans le jeton, en laissant les rôles comme une abstraction utilisée pour donner aux clients un moyen moins compliqué de gérer l'autorisation.
miso
1
que se passe-t-il si un utilisateur ne peut que prendre des mesures sur les ressources qu'il possède. Comme un compte bancaire par exemple, sûrement "bank_account": ["lire", "update"] ne le précise pas. Aussi, exactement O does se déroule le processus d'autorisation dans un système de microservices? Sur un serveur d'autorisation centralisé, ou chaque service fait-il sa propre autorisation?
rocketspacer
@rocketspacer. C'est pourquoi le jeton a la userpropriété dans sa charge utile. La façon dont je verrouille une ressource appartenant à un utilisateur consiste à mapper la userrevendication à l'URL. Par exemple: /users/coyote/back-accountne serait accessible que par un jeton avec une userrevendication égale à coyote. J'espère que cette aide.
miso
3

Je pense que quoi qu'il en soit, vous souhaiterez que vos services acceptent un jeton d'authentification fourni par un service d'authentification que vous écrivez pour valider les utilisateurs. Il s'agit de la manière la plus simple / sécurisée d'empêcher une mauvaise utilisation de vos microservices. De plus, en général, si vous voulez qu'un client ait une bonne expérience, vous devez implémenter les fonctionnalités critiques vous-même et tester soigneusement pour vous assurer que les fonctionnalités que vous proposez sont bien implémentées.

Étant donné que tous les appelants doivent fournir à vos microservices la preuve qu'ils ont été authentifiés, vous pouvez également lier des autorisations à cette authentification. Si vous donnez la possibilité de lier un utilisateur à un groupe d'accès arbitraire (ou à des groupes si vous voulez avoir de la fantaisie, bien que les autorisations d'ajouter par rapport à soustraire soient plus difficiles à traiter ici.), Il y aura moins de questions provenant de vos clients sur la raison pour laquelle l'utilisateur x a pu effectuer une opération indésirable. Dans tous les cas, quelqu'un doit faire une vérification de la liste d'accès pour chaque service, il peut donc tout aussi bien être vous. C'est quelque chose qui se coderait très facilement au début de tous les services (if ( !TokenAuthorized(this.ServiceName, this.token) { Raise error }) Que vous puissiez aussi bien le faire et suivre vous-même les groupes d'utilisateurs. Il est vrai que vous devrez disposer d'un gestionnaire de groupe d'autorisations et l'intégrer dans l'interface utilisateur de gestion des utilisateurs (utiliser les groupes existants / créer un nouveau groupe pour les autorisations des utilisateurs) .Listez définitivement les utilisateurs liés à un groupe lorsque vous modifiez la définition, pour éviter toute confusion. . Mais ce n'est pas un travail difficile. Ayez simplement des métadonnées pour tous les services et liez la recherche du mappage entre le groupe et le service dans la gestion des jetons d'authentification.

Ok, donc il y a pas mal de détails, mais chacun de vos clients qui veulent cette fonctionnalité devra le coder dans tous les cas, et si vous prenez en charge les autorisations utilisateur à trois niveaux, vous pouvez aussi bien l'étendre à l'accès par utilisateur groupes. Une intersection logique entre les autorisations de groupe de base et les autorisations spécifiques à l'utilisateur serait probablement la bonne agrégation, mais si vous voulez pouvoir ajouter et retirer des autorisations de base, des autorisations de base Admin, Agent, Utilisateur final, vous devrez le faire l'indicateur à trois états usuel dans les groupes d'autorisations: Ajouter une autorisation, Refuser l'autorisation, Autorisation par défaut et combiner les autorisations de manière appropriée.

(Remarque: tout cela devrait se produire sur quelque chose comme SSL ou même SSL bidirectionnel si vous êtes préoccupé par la sécurité des deux extrémités de la conversation. Si vous "divulguez" ces jetons à un attaquant, il est comme s'il " d a craqué un mot de passe.)

BenPen
la source
En pensant à l'infrastructure et à la mise en œuvre, j'ai totalement oublié l'expérience client. J'aime l'idée de créer un ensemble de règles qui conviendront davantage à notre entreprise. Les administrateurs, les agents et les utilisateurs finaux sont trop génériques et nous prévoyons de mettre en œuvre davantage de types d'utilisateurs, qui sont plus descriptifs et liés à notre langage métier et ubiquitaire.
Robert
Je n'ai pas été en mesure de corriger la faute de frappe "anded" dans la dernière phrase parce que je ne pouvais pas le comprendre.
Tulains Córdova
Ce n'est pas nécessairement une faute de frappe, mais je vais être plus clair ..
BenPen
1

Mon avis est que vous avez deux choix ici.

  • Si vous avez juste besoin d'avoir un accès configurable à essentiellement la même application, demandez aux services de vérifier les autorisations et donnez à vos clients une interface qui leur permet de modifier les autorisations accordées à chaque rôle. Cela permet à la plupart des utilisateurs d'utiliser la configuration de rôle par défaut, que les clients «à problème» peuvent modifier les rôles ou créer de nouveaux pour répondre à leurs besoins.

  • Si vos clients développent leurs propres applications, ils doivent introduire leur propre API intermédiaire. Qui se connecte au vôtre en tant qu'administrateur, mais vérifie la demande entrante par rapport à ses propres exigences d'authentification personnalisées avant d'appeler vos services

Ewan
la source
1

Considération de sécurité

Si je comprends bien votre conception, vous avez l'intention de déléguer certains mécanismes de contrôle d'accès aux ressources du côté client, c'est-à-dire qu'une application consommatrice réduit les éléments qu'un utilisateur peut voir. Votre hypothèse est:

les micro-services et leur système d'autorisation ne devraient pas être dérangés par les besoins des clients, car ils ne sont que des consommateurs et ne font pas partie du système

Je vois ici deux problèmes sérieux pour les affaires sérieuses:

  • Que se passe-t-il si un utilisateur voyou (par exemple dans l'une des usines de votre partenaire) procède à une ingénierie inverse de l'application cliente et découvre l'API, contourne les restrictions que son entreprise a imposées au client et utilise ces informations pour nuire à votre entreprise? Votre entreprise demandera des dommages-intérêts, mais la société partenaire affirmera que vous n'avez pas donné les moyens de protéger suffisamment vos données.
  • Habituellement, ce n'est qu'une question de temps que les données sensibles soient utilisées à mauvais escient (ou l'audit découvrira le risque) et votre direction finira par demander un contrôle plus strict de ces données.

C'est pourquoi je vous conseille d'anticiper de tels événements et de répondre aux demandes d'autorisation. Vous êtes dans une phase de réingénierie précoce et il sera beaucoup plus facile de les prendre en compte dans votre architecture (même si vous ne les implémentez pas tous) que plus tard.

Si vous poursuivez votre poste actuel, consultez au moins votre responsable de la sécurité de l'information.

Comment l'implémenter

Vous avez l'astuce:

De cette façon, nous n'aurions à suivre que les portées de jetons.

Ok, vous avez l'intention d'utiliser des jetons généraux choisis par le client. Encore une faiblesse à mes yeux, car certains clients peuvent être hors de votre contrôle.

Je ne sais pas si vous utilisez déjà JWT ou si vous utilisez d'autres techniques. Mais si vous utilisez JWT, vous pourriez avoir un jeton d'identité qui porte l'identité de l'utilisateur (et même un deuxième jeton qui identifie en toute sécurité l'application d'origine, ce qui pourrait vous permettre de différencier le niveau de confiance entre les clients internes et les clients externes ).

Comme vous avez l'intention d'opter pour une architecture de microservice, je voudrais suggérer de faire la différence entre la gestion des utilisateurs et le processus d'authentification (qui devrait fonctionner en tant que service dédié) et le contrôle d'accès (qui est spécifique à chaque microservice et devrait être traités localement par chacun d’eux). Bien sûr, certains clients d'administration devraient donner un aperçu complet de plusieurs services, pour en faciliter l'utilisation).

Christophe
la source
1
Très bon conseil ici. J'aime l'idée avec le deuxième jeton.
Robert
1

Ici, il y a aussi une réponse courte. Vous devez implémenter vous-même toutes les fonctionnalités essentielles que vous souhaitez offrir à vos "clients". Il semble problématique que les clients ajoutent eux-mêmes un comportement fondamental comme les autorisations des utilisateurs, car vous effectuez déjà l'authentification des utilisateurs; si vous laissez le soin au client de l'implémenter, vous pouvez finir par «prendre en charge» plusieurs implémentations du même code d'autorisations. Même si vous ne le "possédez pas", il y aura des bogues dans leur code et vous voulez que vos clients aient la fonctionnalité qu'ils attendaient, dans des limites raisonnables, donc vous soutenez la résolution des problèmes rencontrés par un client. Prendre en charge plusieurs bases de code n'est pas amusant.

BenPen
la source