AuthN and AuthZ with traefik for micro-services

Aim of the article:

  1. Deploy API gateway in front of a micro-service (say foo)
  2. Delegate authN to another micro-service (say auth) for all requests
  3. Enable OAuth 2.0 Google authN in the micro-service auth
  4. Forward user info to other micro-services upon successful authN

References:

  1. authlib: https://authlib.org/ I have developed my example on the one provided here https://docs.authlib.org/en/latest/client/frameworks.html
  2. traefik documentation for forwardAuth plugin: https://docs.traefik.io/middlewares/forwardauth/

I recently started learning about how authN and authZ is solved in micro service architecture. Unlike monolith applications where session information is stored and available to be consumed across all APIs, in micro service architecture it is not feasible to store & sync this information per service. Thus, this creates a need for an API gateway via which all API calls to micro services are routed only if user is authenticated.

To achieve the same, I came across traefik which is a light weight reverse proxy & HTTP load-balancer. It provides automatic discovery of services across multiple providers for eg. docker, kubernetes, etc. So, let’s try to develop a small project with AuthZ and AuthN in place using traefik.

Let’s start with writing the services foo & auth:

We create a virtual env for testing where we ensure we add the following packages and then ensure that virtual env is activated:

Now, we add minimal code to service foo:

foo/main.py

Let’s add the logic to service auth also now. Similarly like service foo, we define the main.py where we post creating the app, we wrap it with the OAuth object.

I am using authlib library, documentation for the same can be found here: https://docs.authlib.org/en/latest/client/flask.html

But, before we continue, we need to setup oauth2.0 Google API on GCP console. You can follow Google’s documentation / this medium article to setup the same. We need the following data post setup to get the auth app working:

auth/main.py

You can choose to remove the database part and have the app not store/lookup user/token upon login/authorize. I am trying to cover an exhaustive example to give the complete picture :)

You can run the auth service the same way you ran foo service. To validate the authorization workflow, visit http://localhost/rbac/login on your machine. If all the data provided is correct and localhost is whitelisted in Google console, you should be redirected to Google’s authorization page. Upon successful authZ, you should get a JSON response with token info in header named X-Auth-User.

Adding the API Gateway — traefik in front of our micro services:

We will make use of docker runtime here so that we can make use of autodiscovery of rules by traefik. To do so, we will perform the following steps:

  1. Dockerize both foo and auth service
  2. Add docker-compose.yaml file defining how to bring up the services.
  3. Add labels to the services in docker-compose.yaml which traefik can discover to redirect API calls accordingly

We first ensure that our directory structure looks like the following:

We have already added foo/main.py and auth/main.py above. Let’s see what other files are supposed to look like:

foo/Dockerfile

auth/Dockerfile

To build docker images for these service you can perform the following:

Now, we populate the docker-compose.yaml to define the service deployment

For more documentation on traefik’s forwardauth and rules specified in labels below, refer to the documentation

we are still yet to define traefik.toml for configuring traefik:

And, we are done with the setup now. So, let’s run.

To validate the oauth workflow, go to http://localhost/foo/ on your browser.

NOTE: Remember to either remove the user/token models usage completely or implement the required CRUD methods to enable the successful execution of the apps.

I write about tech