Microservices · Authorisation

Authorisation

There are two parts to allowing access to resources Authentication, the act of ensuring that the entity requesting access is whom they claim to be. This is usually achieved via an account name and some secret information that only the owner of that account should know. And Authorisation, the act of ensuring that the entity is allowed to access a given resource.

This post focuses on the latter, the authorisation of a given entity to access given resources.

Conveying information about a user, the groups they belong to, the permissions they have, for a given resource is the basis for authorisation in computer systems. The method for achieving the goal of passing this information for a distributed system of microservices is the subject of much debate.

There are two schools of thought for the client application, it gets to know the group information, or it has no idea at all.

When the client application knows the group information, queries can be optimised such that queries that would be disallowed by the service are discarded. The downside of this is that anything the client knows can be compromised (not that the server is immune from being compromised). This is known as information leakage, the client applications are providing (potential) attackers with information on how permissions are managed within the system.

Not only is there problems from malicious actors, problems arise from the client developers making errors, change management becomes more difficult, and users can contribute their own unique skills at making mistakes too (we’re all capable of accidentally doing things with applications that were never intended to happen!).

When the client application is blind to this information it needs to make queries on the services, and be able to deal with the fact that some or all of those queries may be denied, for whatever reason.

It should be clear, then, that providing the client with limited information on how permissions are managed within the server side system is a superior option. The general consensus is that the client is given a bearer token, a random number that can be produced whenever access to any resource is requested. The random number has only one constraint, it needs to be unique to this client at this point in time, there cannot be two different clients with the same bearer token, and there cannot be reuse of old tokens in case a client reactivates with the old token.

Within the boundaries of the server side application, however, the groups and permissions information is required to be known, therefore a conversion from the bearer token to something that encodes the perms must occur.

Again there are decisions that must be made, does each service receive the bearer token and lookup if the owner of that token is authorised to access the resource, or does the service receive that information with the request.

If the service receives the client’s bearer token, then the provider of the translation of that token to permissions is going to be thrashed (heavily). Every service in the chain required to satisfy a given request will be asking for the translation.

Providing the service with that information means that the service can determine for itself if the client is authorised to access some or all of its resources.

The solution is two tokens, a slim bearer token for the external client, a fat token for the internal services.

A scaleable solution would look like this. An API that has some middleware that searches a cache for the slim bearer token. If the token exists then the groups and permissions information, which is stored in the cache with the slim bearer token, is placed in a fat token that is passed to the internal services. Else, if the slim bearer token cannot be found the client is redirected to the login page.

The cache is populated with the bearer token (used as the key) and groups/permissions for the client when the client authenticates. Setting a TTL in the cache means that the bearer tokens will go stale after a set period of time, forcing the client to authenticate regularly. This is a write-through approach with TTL attributes (although it could be argued that the lazy loading is achieved by a cache miss causing a fresh login that causes the cache to be updated with the tokens).

Published:
comments powered by Disqus