Software security is a complex problem, and is becoming even more complex using microservices where each service has to deal with security, David Borsos explained at the recent Microservices Conference in London, during his presentation evaluating four end-user authentication options within a microservice based systems.
In a traditional monolithic architecture, a single server holds all user data and can verify and create an http session when a user has been authenticated. In a microservices architecture, a user interacts with a collection of services, each with a potential need of knowing who the user is. A naive solution is to apply the same pattern in a microservices system as in a monolithic system, but then the problem of how to give all services access to the user data arises. When using a shared user database, updating the schema becomes a hard problem since all services must be upgraded at the same time. When distributing the same data to all services, there is the problem of how to make each service know when a user is authenticated.
Looking into different solutions, Borsos notes that a single sign-on (SSO) solution may look as a good idea, but it means that every public facing service must talk to the authentication service giving quite chatty traffic. It’s also fairly complex to implement. On the other hand the security is as good as the chosen SSO, and the user login state is opaque, preventing an attacker from inferring any useful information from the state.
With a distributed session solution, information about the user authentication is stored in a shared data store, often just a simple distributed hash map keyed by the user session. When a user accesses a microservice, user data can then be fetched from the data store. Another advantage to this solution is that the user login state is opaque. When using a distributed database, it’s also a highly available and scalable solution. Downsides include the fact that the data store should be protected and therefore only accessible over a secure connection, and that the implementation of the solution often has a rather high complexity.
Using client-side tokens the user is authenticated and a token is created on the client side. This token is signed by an authentication service and must contain enough information so that the user identity can be established in all microservices. The token is attached to each request, giving a service the possibility to verify the user. The security is relatively good with this solution, but one big problem is the difficulty of logging out. Ways to mitigate this include using short-lived tokens and frequent checks with the authentication service. Using client-side tokens, Borsos prefers the use of JSON Web Tokens (JWT), among other things for its simplicity and good library support.
Using a client-side token together with an API gateway means that all requests are going through a gateway, effectively hiding the microservices. On a request the gateway transforms the original user token to an internal session ID token. Logout is not a problem here because the gateway can revoke the user’s token when logged out. Even though the library support is good the implementation can be complex.
As a general recommendation Borsos suggests using client-side tokens, using JWT, and an API gateway because it’s generally easier, simpler to implement and has good performance. SSO might work but he thinks it should be avoided. Using distributed sessions can be interesting, especially in use cases where the technologies needed are already in use. He emphasizes though the importance of considering the importance of logout when choosing a solution.
Next year’s Microservices Conference in London is scheduled for November 6-7, 2017.