27

In the systems, there may be data that is restricted in nature. Sometimes access to specific entities should be easily restricted or granted based on user or group membership.

What is the best way to implement this in the microservice architecture?

#1

Should access control, managing permissions etc. be the responsibility of the microserive itself? Developers will have to implement access control, store, and update permissions for every service. Seems like not very robust and error-prone approach.

#2

Create dedicated microservice handling permission management? This service will be called by other microserives to check access permissions for each entity and filtering entities before returning results. Centralized permissions storage and management is an advantage but microservice will have to make a call to "Permission Service" for each entity to check access rights what may have a negative influence on performance. And developers still have to integrate access checks into their services what leaves space for an error.

#3

Make access control responsibility of the API Gateway or Service Mesh. It is possible to think of an implementation that will automatically filter responses of all services. But in the case when the microservice returns list of entities permissions should be checked for each entity. Still a potential performance problem.

Example

Consider the following synthetic example. Healthcare system dealing with test results, X-Ray images etc. Health information is very sensitive and should not be disclosed.

Test results should be available only to:

  • patient
  • doctor
  • laboratory

Attending doctor may send the patient to another specialist. A new doctor should have access to test results too. So access can be granted dynamically.

So each entity (e.g. test results, X-Ray image) has a set of rules what users and groups are allowed to access it.

Imagine there is a microservice called "Test Results Service" dealing with test results. Should it be responsible for access control, manage permissions etc.? Or permissions management should be extracted to separate microservice?

Healthcare system may also handle visits to a doctor. Information about patient's visit to the doctor should be available to:

  • patient
  • doctor
  • clinic receptionist

This is the example of a different entity type that requires entity level access restriction based on user or group membership.

It is easy to imagine even more examples when entity level access control is required.

Eugene Khyst
  • 9,236
  • 7
  • 38
  • 65
  • 1
    Maybe example is too complicated. Consider easier one. A chat application. Every user can view only messages addressed to him or to group he belong. Messages microservice provided a way to get all messages. What is the best way to check weather user are allowed to view messages or not to avoid situation when user issues a call to get all messages of different user? It seems reasonable to make data security a responsibility of Messages MS itself. But now imagine we have new microservice responsible for handling its data security. Then 1 more MS etc. – Eugene Khyst Dec 17 '17 at 13:58

3 Answers3

18

I came to the following generic solution.

  1. ACL security model is used. Each object in the system has associated set of permissions. Permissions defines who and what actions can perform on the object.
  2. Microservices are responsible for entity-level authorization and filter objects in responses based on permissions of the objects.
  3. Central Access Control Service is responsible for the creation, update, and deletion of permissions for all objects in the system. Access Control Service database is the primary store of objects' permissions.
  4. Permissions stored in microservices databases are synchronized with Access Control Service database using event-carried state transfer. Every time, permissions are changed an event is sent to the message broker. Microservices can subscribe to these events to synchronize permissions.
  5. API Gateway can be used as the additional protection layer. API Gateway can call Access Control Service directly (RPC) to check response objects' permissions or load recently revoked permissions.

Design features:

  1. A way to uniquely identify each object in the system is required (e.g. UUID).
  2. Permissions synchronization in microservices are eventual consistent. In case of partitioning between message broker and microservice permissions will not be synchronized. It may be a problem with revocation of the permissions. The solution to this problem is a separate topic.
Eugene Khyst
  • 9,236
  • 7
  • 38
  • 65
  • i have the same problem of yours. but i am stuck in the idea that my users are all saved in another service db. so to perform entity level permission for each user a microservice has to know about the user as well and ultimately users have to be synchronized across all services? – Ahmed Nawaz Khan Dec 03 '19 at 12:18
  • 2
    All microservices need to synchronize permissions, not users. Permission is something like "USER 1 can READ and WRITE DOCUMENT 2". Here we need only user ID. The userID for example can be extracted from "sub" claim of a JWT payload. – Eugene Khyst Dec 04 '19 at 07:19
  • many thanks. i just eliminated the central service, performed permissions on microservice level (with users given to each) and then i synchronize users service with all other microservies through a cron job – Ahmed Nawaz Khan Dec 04 '19 at 11:01
0

Looks like security is a part of business logic here. In both examples. Then security could be a part of data scheme. For example,
Patient can see his tests:
select * from test_result where patient_id=*patient_id*
Doctor can see all test from his medical department:
select * from test_result where branch_id=*doctor_branch*

I believe that to have separate MS for access control is a really bad idea and could lead serious performance problems. Just imagine situation that somebody with zero entity access tries to fetch all entities each time :) You will always need to handle larger result sets than actually needed.

Bullet-tooth
  • 782
  • 1
  • 10
  • 16
  • There might be tens or hundreds of microservices in the system. If developers will have to implement data security for each service the errors are possible. And when it comes to sensitive data (like health information) it is better to have a robust solution that minimizes human mistake. But I totally agree that it is better to filter results inside of the service to avoid performance issues. Maybe it makes sense to also add centralized access permission check on top of it. It comes with some development overhead but takes best from both options. – Eugene Khyst Dec 18 '17 at 09:29
-2

Firstly, this is very bad idea to have a separate (per microservice) security model. It should be single always cross-cutting all application, because it can lead to a hell with access management, permissions granting and mapping between entities in different microservices.

In second, I assume that you are wrong with understanding how to organize microservices..? You should dedicate the principle of splitting functionality into microservices: by features, by domain, etc. Look at Single Responsibility, DDD and other approaches which helps you to achieve clear behavior of your MS.

So, in best case, you should have to:

  • Choose right security model ABAC or RBAC - there are a lot of other options, but looking at your example I guess the ABAC is the best one
  • Create separate MS for access management - the main responsibility of this MS is a CRUD and assignment of groups/roles/permissions/attributes to the people accounts.
  • Create separate MS for providing only permitted health information.

In third, how it works?:

  1. With ABAC you can setup hierarchical roles/permissions (based on groups/attributes) - it helps you to resolve a delegation path of who is permitted to the data
  2. Setup authorization (via auth-MS) and store the list of permissions (in session, cookies, etc)
  3. Check access for a given user for a needed data in health-info-MS. Here we have several options how to do this:

    • If you use memory-grids (hazelcast, coherence), you can easily create filters with predicates based on security attributes.

    • If you're using SQL (hibernate, plain SQL, etc.) you should generate queries to return only permitted data - add security specific criteria to the where clause

Few more details about SQL queries with security check in where: before the SQL execution (if hibernate & spring is easy to do with spring-method-auth hook) you should resolve all permissions assigned to a user - you can do this with call to auth-MS.

Example

We created CRUD permissions for TestResult entity - VIEW, EDIT, DELETE.

The role DOCTOR can see any TestResults - so, it has VIEW permission

The role PATIENT can see only his/her TestResults

So, you create a business rules which provide the correct where clause for each business role (DOCTOR, PATIENT, LAB, etc.) and at the end the SQL request would be like:

For patient who has assigned VIEW permission:

select * from test_result where id=*patient_id* and 1=1

For patient who hasn't assigned VIEW permission:

select * from test_result where id=*patient_id* and 1!=1

NOTE: In business rules we can add 1=1 or 1!=1 to permit/restrict query result

  • Theoretically, each entity may have different access rules (policies). It means that these rules have to be stored somewhere. Here we have 2 options: store rules in MS DB or store all rules along with IDs of entities in the central AccessManagement MS DB. First solution leads to duplication of access control schema in micorservices DBs what is also error-prone and second has potential performance issue because a call to AccessManagement MS must be done for each entity fetched from MS DB. What I'm trying to figure out, does a smart compromise between these solutions exist? – Eugene Khyst Dec 17 '17 at 14:55