AuthN and AuthZ with traefik for micro-services
Aim of the article:
- Deploy API gateway in front of a micro-service (say foo)
- Delegate authN to another micro-service (say auth) for all requests
- Enable OAuth 2.0 Google authN in the micro-service auth
- Forward user info to other micro-services upon successful authN
- authlib: https://authlib.org/ I have developed my example on the one provided here https://docs.authlib.org/en/latest/client/frameworks.html
- 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:
# folder per service
$ mkdir foo auth# setup foo service
$ touch foo/main.py# setup auth service
$ touch auth/main.py
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:
# run the service foo
$ python foo/main.py# validate the service is up and running
$ curl http://localhost/
<p>Hello, I am service foo!</p>
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:
GOOGLE_CLIENT_ID & GOOGLE_CLIENT_SECRET
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:
- Dockerize both foo and auth service
- Add docker-compose.yaml file defining how to bring up the services.
- 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:
RUN pip install Flask>=1.0.0
ADD . /app
CMD ["python", "main.py"]
RUN pip install Flask>=1.0.0 requests==2.22.0 Authlib==0.13
ADD . /app
CMD ["python", "main.py"]
To build docker images for these service you can perform the following:
# foo docker image
cd foo && docker build -t foo:test .# auth docker images
cd auth && docker build -t auth:test .
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.
# deploy the services
cd deployment && docker-compose up -d
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.