Microservices Security – Authorization Best Practices

authorizationmicroservicesSecurity

We are currently working on a micro-service based system. The idea behind it is to split our monolithic system to small domains (micro-service per domain).

All services will be used by our internal applications, but we have plans to expose it to public.

One of the services would be identity management service, which would be responsible for issuing and validating tokens.

For shared references, we are using SharedKernel. One of libraries in shared kernel is a custom AuthorizationAttribute, which will be used by all micro-services. Basically what the attribute does, is forwarding Bearer token to authorization service, and authorization service responds with information such as token validity, user information and a set off allowed endpoints/resources for the given token.

If the current endpoint is not listed, 401 HTTP response is returned.

Now, I have 2 concerns:

  1. Are we on the right track and is this a valid approach? If not, what can be done to improve it?
  2. We are still having problems with UserTypes/Roles concept. We will probably have 3 types of users. Admins, Agents and End-Users and yet again, if some 3rd party company decides to use our API, roles which were created for our needs, might not be suitable for their needs.
    The problem is that not all agents will have set of same permissions. For an example we might have an agent who is responsible for accounting and he would have access only to accounting related micro-services, but we might also have an agent who is responsible only for booking. Should this require us to set a UserType for each agent type, fe. AccountingAgent, BookingAgent etc, and assign multiple UserTypes to user, or there is a simpler approach to solve this?

Best Answer

No, you are not using tokens correctly.

The idea is that you have an Auth service which issues tokens and Resource services which can validate the token and read the claims it contains. So the rather than forwarding the bearer token to the auth service each time the flow should be as follows

  • Client -> Auth : please give me a token, here is my username and pass
  • Auth -> Client : here is a token I have signed it with my private key and it contains the claim "i am an Accounting Agent"

then

  • Client -> Resource : hi, please give me a list of accounts, here is my token
  • Resource -> Client : I have checked the signature on your token using the Auth services public key. so I know I can trust your claim that you are an Accounts Agent. Here is the list of accounts

then

  • Client -> Resource : Please delete this account, here is my token
  • Resource -> Client : sorry Account Agents are not allowed to delete accounts

This flow prevents the Auth service becoming a performance bottleneck and leave the various microservices to decide if Claim X can do Operation Y

Roles

To address your second question about roles and permissions. At the end of the day a service has to have a set of Roles or Permissions that it knows about. eg you have to actually code something like:

If(users.Role != "RoleX")
{
    return "Access Denied!";
}

Rather than have a whole list of different permissions, 'canEditAccounts' ,' canEditCustomers', 'canDeleteAccounts'... etc etc the modern approach is to instead have a shorter list of Roles 'AccountingAgent' which essentially act as a set of permissions.

If a third party consumes your services though they will have to use the roles that the service knows about. This means that they are stuck with the level of granularity that you provide in your Roles.

ie If your Accounting Agent does too little and your Accounting Manager does too much for your third parties needs you are stuck.

One way around this is to have a dynamic mapping between Roles and Permissions. Have your service know about permissions and query what permissions a role has.

You can then allow your third party consumers to create their own roles, selecting the permissions they want each to have

Related Topic