The goal of this project is to use Nginx
as a reverse proxy and load balancer for a Keycloak
cluster with two instances and a Spring Boot
application, called simple-service
, also with two instances. The simple-service
app will use Keycloak
for IAM.
On ivangfr.github.io, I have compiled my Proof-of-Concepts (PoCs) and articles. You can easily search for the technology you are interested in by using the filter. Who knows, perhaps I have already implemented a PoC or written an article about what you are looking for.
- [Medium] Using Nginx to Load Balance Requests to a Spring Boot Web application
- [Medium] Using Nginx to Load Balance Requests to a Keycloak Cluster
- [Medium] Nginx Load Balancing Requests to a Keycloak Cluster and a Spring Boot app that uses Keycloak as IAM
-
Spring Boot
Web Java application that exposes the following endpoints:GET /api/public
: This endpoint is not secured; everybody can access it;GET /api/secured
: This endpoint is secured and can only be accessed by users who provide aJWT
access token issued byKeycloak
. The token must contain the roleAPP_USER
.
-
In a terminal, navigate to the
spring-boot-nginx-keycloak-cluster
root folder. -
Run the following script:
./build-docker-images.sh
Add the line below to /etc/hosts
127.0.0.1 keycloak-cluster.lb simple-service.lb
Open a terminal and inside the spring-boot-nginx-keycloak-cluster
root folder run:
./init-environment.sh
This script will start:
- one
PostgreSQL
Docker container; - two
Keycloak
Docker containers; - two
simple-service
Docker containers; - one
Nginx
Docker container;
We can configure a client for simple-service
in Keycloak
by using Keycloak
website at http://keycloak-cluster.lb. However, to keep things simple and fast, we've created a script for it.
So, in a terminal, make sure you are inside the spring-boot-nginx-keycloak-cluster
root folder, run the script below:
./init-keycloak.sh
The script will:
- create
company-services
realm; - disable the required action
Verify Profile
; - create
simple-service
client; - create the client role
APP_USER
for thesimple-service
client; - create
USERS
group; - assign
APP_USER
client role toUSERS
group; - create
user-test
user; - assign
USERS
group touser-test
;
To complete, copy the SIMPLE_SERVICE_CLIENT_SECRET
value that is shown at the end of the script. It will be needed whenever we call Keycloak
to get a JWT
access token to access simple-service
.
-
Open a new terminal;
-
Call the endpoint
GET /public
:curl -i http://simple-service.lb/public
It should return:
HTTP/1.1 200 ... Hi World, I am a public endpoint
-
Try to call the endpoint
GET /secured
without authentication:curl -i http://simple-service.lb/secured
It should return:
HTTP/1.1 401 ...
-
Create an environment variable that contains the
Client Secret
generated byKeycloak
tosimple-service
at Configure Keycloak step:SIMPLE_SERVICE_CLIENT_SECRET=...
-
Run the command below to get an access token for
user-test
user:USER_TEST_ACCESS_TOKEN="$(curl -s -X POST \ "http://keycloak-cluster.lb/realms/company-services/protocol/openid-connect/token" \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "username=user-test" \ -d "password=123" \ -d "grant_type=password" \ -d "client_secret=$SIMPLE_SERVICE_CLIENT_SECRET" \ -d "client_id=simple-service" | jq -r .access_token)" echo $USER_TEST_ACCESS_TOKEN
-
Call the endpoint
GET /secured
:curl -i http://simple-service.lb/secured -H "Authorization: Bearer $USER_TEST_ACCESS_TOKEN"
It should return:
HTTP/1.1 200 ... Hi user-test, I am a secured endpoint
-
The access token default expiration period is
5 minutes
. So, wait for this time and, using the same access token, try to call the secured endpoint.It should return:
HTTP/1.1 401 ... WWW-Authenticate: Bearer error="invalid_token", error_description="An error occurred while attempting to decode the Jwt: Jwt expired at ...", error_uri="https://tools.ietf.org/html/rfc6750#section-3.1" ...
-
Checking
Keycloak
andsimple-service
Docker container logsWe can verify that
Nginx
is load balancing the requests appropriately when an access token request toKeycloak
is made. To view theKeycloak
Docker container logs, execute the following commands in different terminals:docker logs -f keycloak1 docker logs -f keycloak2
We can also verify that
Nginx
is appropriately load balancing requests tosimple-service
endpoints. To view thesimple-service
Docker container logs, execute the following commands in different terminals:docker logs -f simple-service1 docker logs -f simple-service2
-
Keycloak
The
Keycloak
website can be accessed at http://keycloak-cluster.lb -
Nginx
If you wish to modify the
Nginx
configuration file without restarting its Docker container, follow these steps:- Apply the changes in the
nginx/nginx.conf
file; - Docker exec into the
nginx
Docker containerdocker exec -it nginx bash
- In the
nginx
Docker container terminal, run:nginx -s reload
- To exit, just run the command
exit
.
- Apply the changes in the
To stop and remove docker containers, network and volumes, in a terminal, navigate to the spring-boot-nginx-keycloak-cluster
root folder, run the following script:
./shutdown-environment.sh
To remove the simple-service
Docker image created, in a terminal and inside the spring-boot-nginx-keycloak-cluster
root folder, run the following script:
./remove-docker-images.sh