3 Ways for Container based microservices to verify JWT tokens

Microservices can use JWT tokens to communicate user authroizations and other information between each other. This can be used for both north/south (e.g. frontend to backend) and east/west (e.g. microservice to microservice) communation. Each JWT token has a signitature which needs to be verified using either a public key or shared secret.

Either way there is a certain amount of logic that needs to be preformed on the reciept of each message to validate it. Where to get the key from, possibly caching the key, preforming the validation, returning errors and logging everything in a nice supportable way. Like all logic this will need to be maintained, versioned and the inevitable bugs iorned out.

I have been invovled in many discussions regarding where this logic should live and I am writing this post to help me think through some options.

Option 1 - Use a framework library to embed process into the microservice itself

If we assume that our microservice will be developed in some language, Java/Python/Go/etc. We can simply embed the logic into this application. We could develop a library; possibly we already have a framework library; and this could be a good place to put it. The logic would be versioned along with that library.

Pros

  • Simple to create a library

Cons

  • Microservice container is bigger as it has more logic (If we have 100's of microservices this increases our cost)
  • Complexity of Microservice app is increased
  • Changes to the JWT logic require recompiling and deploying all microservices
  • If we want microservices to use mutiple languages we need to reimplement the same logic in each language and then maintain mutiple versions

Option 2 - Use another container

If we are planning to have a large number of microservices it makes sense to make them as small and as simple as possible. Everytime we put logic into a microservice we increase it's size as well as the effort required to reason about the service.

As well as using http calls, containers can communicate with each other using unix sockets. Rather than embed the logic for checking the JWT token into the container we could also design a custom container we can attach in front of the service which acts like a filter. The containers can connect using a unix socket much like the way the Docker API works.

Compared to the previous method we have some big advantages:

  • Language used for the JWT logic now dosen't need to match the container itself
  • Much easier to redepoy new version of JWT logic - it no longer needs us to recompile and deploy every microservice!
  • We can reuse the JWT logic container all over our microservice platform
  • Microservices are smaller, simplier and easier to reason about
  • We can test the microservice independantly of JWT validation logic

This method could leverage the Kubernetes pod concept.

Option 3 - Establish a private microservice zone and check tokens at the border

I have used an opensource API gateway called kong in the past which has plugins that can validate JWT tokens. This can allow us to completly remove JWT token validation logic from our microservices altogether.

Pros

  • We now only have a single cache
  • JWT Logic changes happen only at the gateway
  • Works seemlsly with non-container things like Lambda

Cons

  • We have had to create a secure microservice zone
  • We have broken the principle of security in depth. One microservice security flaw can give access inside the secure area
  • What if we want to spread our mciroservices globally? It is possible to create this global VPN but might be complex and will give us more to maintain and reason about.
  • Limted by features availiable on our API gateway (unless we role our own central filter)

Conclusion

I find this topic intresting because I think it speaks to the principles behind microservices themselves. In my experience with microservices so far I have created platform libriaries which have slowly grown and weighed me down. I am developing a feeling that generic microservice platform libriaries we require to inject into every microservice we build counteract some of the drivers that led us to choosing microservice arthitectures in the first place.

I'm going to read a lot more about sidecar containers and the sidecar pattern.

Published Date