Our team has decided to move to a microservice approach for newly developed features. We've decided to keep a database/datastore per service and to split the services along the business function they perform. As we move this direction we're creating the services as necessary. This means that not only have we created a new service for this new functionality but we may be creating a new service for functionality and data that already exist within the system (within the monolithic application that is being deconstructed).
After working on our first service we've come up with an interesting dilemma. How do we secure data based on users' relationships? This is not security based on authentication or authorization. We're currently using a token passed from our SSO provider to insure authentication and are developing JWTs to add authorization.
I'm going to describe a basic scenario:
Suppose we have a business object which is owned by a user (or group). A lot of microservice architecture examples use orders, etc. Say we have a user, U1, which has created an
order object and we have another user which is a manager, M1, which oversees this user. Also, we have other users, U2, U3, and U4, which are part of group, G1. User U1 and manager M1 are not members of this group.
Here are some questions we would want answered:
- Manager, M1, logs in and should see his downline employee's
orderobjects, but no other manager's downline information.
- Members of G1 should be able to see each others
Clarifying the scenario some:
The goal is to be able to have a user identified (the logged in user or given id) and filter any data within the service to what that user is permissible to see. i.e. A user may have the role "orders" and is able to utilize the service (orders_read, orders_write), but shouldn't have access to objects outside of his relationship to other users (can see his and those he manages). Even if there were a permission called "orders_supervise" the user inheriting this role needs to have context as to whom he is supervising. This is important when we're talking about scenarios involving data that is sensitive nature, a manager viewing their employee's salary or performance review.
Assume that our monolithic application structure has defined groups of users and relationships between users. Without going in depth on the data structures, it could be assumed that there are linking tables for these structures. For groups a linking table would have a group identifier and a person identifier. For relationships the table could be between person identifiers that make up some type of relationship.
Another method of handling it, and this is the way it is done in one of our legacy applications, is to have a column on the person for each relationship. For U1 they would have M1's id in their
Depending on the question above the monolithic application could use a query that joined across these tables. The query would produce a projection of data which was filtered via the join to either linking tables in order to answer the above questions. The database in the application contains all relevant data to answer these questions.
This approach is how we currently function. It produces results very quickly since the data is filtered at the database level. The relational database allows the normalized data to be updated in a quick fashion which would filter through to allow any changes to be reflected pretty quickly in the answers to the questions.
Framing this in a microservice architecture
When our team is looking at this scenario in a microservice architecture we're considering different business capabilities: relationship management, group membership, and orders (not to mention users or authentication, etc).
If we were to place these concerns into two services (or three) with the order information separated from the relationship or membership data how do we handle security based on these relationships?
Is this where we would be duplicating data between services and data stores? As in, should we be including group data within the orders microservice? This doesn't seem correct as it violates a separation of concerns. However, it does support having a reactive services where this one service isn't dependent on another.
Thinking of the solution where duplication of data is the way to go, this could get messy for this common data structure. If our system is dealing with business objects that are mainly subjected to security based on relationships between users and groups it would seem that almost every microservice would have this data by default. How does this duplicated data get sync'd? Aside from a technical solution (redis) is there a service design pattern we should be following?
The question of how to perform data security based on relationships between users and groups seems to not be answered in a well defined manner in any pattern we've researched. Topics such as authentication and authorization are fairly well covered. It seems that we can't be the first to ask this question. Are we framing the question wrong, coming at it from a bad perspective? Does a microservice architecture pattern already address this concern?