I am building a system based on microservices. It is a web application connected to different rest APIS. Now I want to implement the authorization system, (not authentication), so basically I want to be able to define, which users on the system can perform which actions.
So I am thinking to implement a role/permission system for that.
However, I have a dilemma about the two different architecture options that come to my mind, I and would like to know your thoughts, advices, pros and cons, to move forward with it.
There will be a specific microservice to handle the user permissions and roles, so basically this microservice will have access to two database tables making the association between the user and roles, and roles and permissions. This is the common part to the two solutions I have considered.
Now both options with pros and cons in my opinion:
1) Keeping for each microservice, a cache table with the user permissions specific to that microservice. So, every time a user wants to perform an action on that microservice (let's say, delete an order on the ordering microservice), the microservice will check that table, granting or not access to the user to perform the action.
Pros: every microservice is really a microservice, an independent service that can work totally autonomously of the rest of the system. If the main microservice handling the user permission crashes and it is not available, the rest of microservices will continue to work.
Cons: If I update the user permissions in the microservice that handles this, I need to send a message to all microservices to update their correspondent permissions tables.
2) Creating a API gateway microservice to act as a middleware between the frontend and the rest of microservices and use graphql in it. Frontend will no longer know about the rest of microservices, only will know about this one.
This microservice will intercept all request from the frontend, check with the user-permissions microservice if the user has permission to do the action, and if so, calling the correspondent microservice.
Pros: All the business logic to decide if the user has or not access is in a single microservice, instead of being duplicated across microservices. Also, authentication only needs to be implemented in the middleware microservice, no need to double check if the user is authenticated on the internal microservices as if we got there, is because we were succesfully authenticated previously.
No need to update cache tables in the internal microservices if the user roles or permissions are updated.
Cons: This defeats the definition of microservice architecture. I.e If the middleware microservice crashes, the whole system will be down.
I would like to know your thoughts!!
Thank you!
Related
First let me explain the problem:
We have an Android app and multiple customers. Each customer has their own endpoint (Kubernetes cluster of microservices basically) that the app should communicate with. To prevent us from having to deploy multiple versions of the app (one for each customer) we are looking for a solution that will use one app but allow for multiple endpoints.
I am interested in knowing if, and if so how, others have solved this.
We have tried:
Automatic endpoint resolution within the app based on user's domain. This fails our requirements because we then need to build a new app for every customer, which is not optimal with 10's of customers appearing every week.
Microservice that gives the user and endpoint based on user's domain. This fails because it creates a Catch 22 problem... how do we know the endpoint to this microservice?
Keycloak User Attributes. We use Keycloak for SSO. Using the REST API in Keycloak requires an admin user, but we do not want to expose such an admin user from any external application.
Manual endpoint insertion in the app. Highly user-unfriendly!
The question in short
What would be the correct way to handle JWT authentication for a user
who is accessing data from microservice A but where microservice A requires data from Microservice B.
The Setup
I am using Auth0 to issue and handle authentication and authorisation.
I have two microservices set up. The user is logged in on the front end and needs to load tenant-based accounting information.
Microservice A is an aggregate service that communicates to multiple different services in order to provide a standardized response for different types of data types.
Microservice B is queried by Microservice A in order to retrieve vehicle information owned by the user.
Which solution would be the correct approach?
Solution A:
The token that was issued to the user when he logged in will be used by MS A to communicate with MS B. MS A is essentially forwarding the token provided by the user.
Solution B:
MS A has its own JWT which has super admin rights to access any resource from MS B. MS A will use this token when accessing resources from MS B and MS A will take responsibility for ensuring that resources not accessible to the user are not returned in the aggregated dataset.
In solution B you put a lot of responsibility on MS A to properly handle the data. In my opinion it's just asking for trouble, eventually someone will manage to call MS A in such a way to get some more data than they can access. So I would go with solution A, or a variant of it. There are a couple ways how tokens can be shared between services - passing the same token, embedding tokens or exchanging tokens. I have written an article about Token Sharing a while back, you can have a look at it.
I think it depends - both options are OK depending on the scenario.
Here are a few things to consider.
Does microservice B do any resource owner authorization e.g. using the sub claim from the users JWT? If so it might be easier to just pass through the user access token. Note: generally I only use data inferred from the JWT for authZ logic. If you need something like the resource owner ID as part of the business logic, you should explicitly include this in the request payload, so that the service can also be consumed by back-end services using M2M tokens.
With Auth0, there's a cost for machine MUAs (monthly unique authentications). This is separate to the cost for user MUAs. For an enterprise account the default is 1000 M2M MUAs. Increasing this number is pretty cheap, but still something to consider. In general you should configure your M2M tokens to have a longer expiration (e.g. 1-2 days) and use token caching. Generally an in-memory cache will suffice, but if you're building serverless apps (e.g. AWS Lambda, Azure Function Apps, etc) you'll probably need a distributed cache. All this is extra work, complexity, and potentially cost (e.g. for distributed cache) for M2M tokens.
There's additional network request (to Auth0) for M2M authentications. This is mitigated through the use of token caching, but something to consider as well.
Is microservice B going to be publicly accessible? If yes, you may have some security considerations as users will be able to call microservice B directly with their access tokens (obtained legitimately), but they might be able to tamper with requests in ways you weren't intending.
The company that I work for use a mix of the 2 approaches you mentioned (which generally depend on the scenario). We have some helper utils for things like token caching etc., which make both approaches easy enough, but if you're going to use M2M tokens you'll probably have a bit of additional work up-front.
One last thing to mention; when implementing 'transitive' services like microservice B, I think it's good to ensure the service is consumable by both user and machine tokens. You're authZ policies might allow for one or the other (or both), but at least you'll have the flexibility to change if/when needed.
The problem to face lies in the design of a RESTful API that can manage requests from multiple roles in an RBAC-based solution.
Currently we have different resources that can be accessed from different users, which can have one or more roles grouped according to their privileges.
The API we're trying to define must be as clear as possible to the client but without the overhead of adding additional metadata to the URL that could damage and even conflict with the REST practices and definitions. Therefore, we must avoid at all costs include information about the roles inside the URL. The plan is to use JWT tokens that carry in their payloads the info needed to know which permissions has the user making the request.
Having raised our current situation, let's provide an example and state the problem to solve:
Suppose we have * financiers * and * providers * as users with some roles who both want to access ** attentions ** (our resource). Should we add before the resource ** attentions ** information about the * user * whose trying to access the resource?
The endpoints in that case should be defined (as an example) as:
https://example.com/api/v1/financiers/:id/attentions
https://example.com/api/v1/providers/:id/attentions
This way we're attempting to inform the respective controllers that we want the ** attentions ** for that specific role / user which are, in some way, a sub-resource of them.
On the other hand, we could simply implement a much simpler endpoint as follows:
https://example.com/api/v1/attentions
The logic about which attentions return from the database should be now implemented in an unique method that must handle this two roles (and potentially new ones that could come up in the following features). All the information needed must be obtained from the payload from the token, exposing a much more generic API and freeing the web client from the responsibility of which endpoint call depending on the role.
I want to highlight that the attentions are managed in a Microservices Architecture and, hence, the logic to retrieve them is gathered in a single service. The cost of the API Gateway to route the two (and potentially more) of the endpoints from the first solution is a variable not to discard in our specific situation.
Having exposed our current situation:
Which we'll be the best approach to handle this issue?
Is there another alternative not contemplated that could ease the role management and provide a clean API to expose to the client?
In the second solution, is correct to return only the attentions accessible to that specific user based on the roles that it has? Isn't it counterintuitive to access an endpoint and only get some of the resources from that collection (and not all) based on its role?
I hope that someone could clarify the approach we're taking as there are little and none literature that I've found regarding this issue.
There there are multiple solutions for such kind of filtration, and developer have to select one depending on given situation.
As per my experience I can list following.
Structure
When data can't be accessed directly and developer has to use a relation (i.e a table JOIN). In that case URL have to include both the main and sub entities. Before going with this approach a good check is to ask, if the same URL can be used with POST ?
Example
If we have to fetch list of roles assigned to a specific user or want to assign additional roles then we can use
GET users/:uid/roles
POST users/:uid/roles
Security
With Multi-tenant systems where each user can have his/her private resources, i.e other users are prohibited from accessing those resources. Developer should save tenancy information and to filter the resources according to current authentication, without bothering client or requiring any additional info in URL
Example
Phone album of the user
GET photos
POST photos
Search
If it is not security or structure related but client still want to filter the result set depending on his scenario. then developer should use query-string for the filtration.
Example
Client have to fetch messages from his/her inbox or outbox or want messages which are not yet read. or he/she want to search his/her inbox
GET messages?folder=inbox
GET messages?folder=inbox&status=unread
GET messages?search=nasir
Would like to get some opinion on designing a system with subscription model using microservice architecture.
We implemented an identity server which authenticates and authorizes
users, and stores their subscription profile. (i.e. resources they can
access like which magazine and issues)
on the resources service, the subscription profile will be used to
filter their eligibility. example, if their subscription starts from
Year 2018, then this will take effect and return only year 2018 data
to the users via REST API.
Is this a standard/proper microservice architecture implementation? or any better ways to design this?
I'd argue no, especially if you want to embrace the principles of microservices - you're storing authorization and application domain specific data in your Identity server. Your IDP should only be concerned with authentication concerns.
I'd suggest a separate service or set of services for managing and retrieving this additional information that is linked to user entities in your IDP via a correlating ID (e.g. subject ID, email address, account code etc). This service would own its own data and be consumed by anything which needs to know about subscriptions and the like.
I have a high-level/conceptual question about Shibboleth.
I'm working on the front-end (running Drupal) of a data-driven web app. End-users interact with the front-end to construct data queries, which makes background requests to a caching/archiving data proxy (the "data retrieval service"), which in turn either delivers data from its cache or goes out and queries still more services ("out there") which have desired data. So far so good... it is ornate, but only as ornate as the problem we're trying to solve.
Here's the wrinkle: Some of services queried by the data retrieval service want to implement user-level authentication, so that some users may access their data, but others cannot. For organizational reasons, our identity and authentication mechanism is likely to be Shibboleth.
So, here's my scenario: a user logs in to the frontend using Shibboleth. Now, can my frontend, and in turn, the data retrieval service, authenticate against against external services as the user? And if so, how does that work in practice (what authentication data gets passed from server to server)?
Yes it can - you service has to exist in the identity provider (how it is set up is up to you)