Implementing an auth archtictures with microservices and an API gateway #1
This post tries to present a way on implementing an auth architectue using an API gateway, where multiple services are handled and OAuth/OIDC for securing the system. For an introduction to different ways on authentication and authorization methods, you can read my other post.
What is part of this architecture?
Kong
I am using the open source API gateway Kong, which already has plugin support for several authentication methods. For example there is a plugin for basic key authentication and OAuth 2.0, but there are not suitable for more complex architectures. One problem is the the management of users that are called consumers in Kong. You can find my customized Kong version here, also with a Dockerfile. Then I added the Middleman plugin for Kong to check the authentication and authorization at an own service.
Keycloak
Keycloak is my favourite authentication and authorization tool because of its wide range of functionalities. In this example I am using Keycloak as my authorization server and for identity management. You can find my customized Keycloak version here, also with a Dockerfile.
Ory Ladon
Ladon is a Go library for managing access policies. These policies store permissions based on a subject, action and resource relation. Because of this abstraction, you can use it for many purposes. In this case it used in an Go web server together with an SQL database to act as an authorization service. It stores policies and answers permissions requests. Therefore a user role will be treated as subject, a HTTP method will be treated as an action and a endpoint will be treated as a resource.
How does this architecture work?
This architecture is using a method where the authentication and authorization are done at the central place at the API gateway. Before an icoming request gets directedd to the upstream by Kong, a request to an auth-check service will be made, that contains the whole request information. This service will perform the authentication and authorization. Therefore it checks if an access token exists and blocks if not. If it exists it will validate the token by sending it to the Keycloak token introspection endpoint. If this is also successfull, the user role gets extracted and gets sent to the Authorization storage service Ladon. This service will check if the user role has the needed permissions to access a resource.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
+----------------+
+-----------+ | |
| User | |Secured Service |
+----+------+ | | +------------------+ +----------------+
| +-------+--------+ OAuth/OIDC flow | | | |
|User flows | +----------------------+ Keycloak Service +------+ Datebase |
+------------------------+ | | | | | Users, Clients |
| | | | | +------------------+ +----------------+
| | | | |
| +-----+----------+ | | |
| | Kong +-------------------+-----------+----------------------------+
| +----+-----------+ | |
| | | +-----+-----------+ +-----------------+
| | | | | | |
| | | | Ladon +-------+ Database |
| | | | | | Access Policies |
| | | +-----+-----------+ +-----------------+
| | | |
| | | +-----------------+ |
| +-----+------------+ | | | |
| | Middleman Plugin+----------------------+ Auth Service +------------------+
| +------------------+ | POST with | | POST with request data
| | request data +-----------------+
| | Authentication: Token Validation
| | Authoriztation: Ladon
+------------------------+
Build
You have to build the docker images of each part of the architectures. You can find the repositories here:
Run
If you have built all parts of the architecture, then you can run it with this docker-compose file.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
version: '2'
services:
keycloak-db:
container_name: keycloak-db
image: postgres:latest
environment:
- POSTGRES_DB=keycloak
- POSTGRES_USER=keycloak
- POSTGRES_PASSWORD=password
keycloak:
container_name: keycloak
image: keycloak:latest
links:
- keycloak-db:postgres
environment:
- KEYCLOAK_USER=user
- KEYCLOAK_PASSWORD=password
- PROXY_ADDRESS_FORWARDING=true
depends_on:
- keycloak-db
auth:
container_name: auth
image: auth:latest
ladon:
container_name: ladon
image: ladon
environment:
- POSTGRES_DB=ladon
- POSTGRES_USER=user
- POSTGRES_PASSWORD=password
links:
- ladon-db:ladon-db
ports:
- 8080:8080
depends_on:
ladon-db:
condition: service_healthy
ladon-db:
container_name: ladon-db
image: postgres:latest
environment:
- POSTGRES_DB=ladon
- POSTGRES_USER=user
- POSTGRES_PASSWORD=password
healthcheck:
test: ["CMD", "pg_isready", "-U", "postgres"]
interval: 10s
timeout: 30s
retries: 5
Review
The advantage of this implementation is, that every microservice behind the gateway does not care about the authentication and authorization, which makes them very flexible and independent. This architectures suffers from a lot of requests, because with every incoming request, two request follows before it gets sent to the upstream service. Therefore a shorter solution could be to develop a Kong plugin in Lua, that validates the JWT Token.