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 BootWeb Java application that exposes the following endpoints:GET /api/public: This endpoint is not secured; everyone can access it;GET /api/secured: This endpoint is secured and can only be accessed by users who provide aJWTaccess token issued byKeycloak. The token must include the roleAPP_USER.
-
In a terminal, navigate to the
spring-boot-nginx-keycloak-clusterroot folder. -
Run the following script:
./build-docker-images.sh
Add the following line 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.shThis script will start:
- one
PostgreSQLDocker container; - two
KeycloakDocker containers; - two
simple-serviceDocker containers; - one
NginxDocker container;
We can configure a client for simple-service in Keycloak using the Keycloak website at http://keycloak-cluster.lb. However, to keep things simple and fast, we have 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.shThe script will:
- create
company-servicesrealm; - disable the required action
Verify Profile; - create
simple-serviceclient; - create the client role
APP_USERfor thesimple-serviceclient; - create
USERSgroup; - assign
APP_USERclient role toUSERSgroup; - create
user-testuser; - assign
USERSgroup touser-test;
To complete, copy the SIMPLE_SERVICE_CLIENT_SECRET value 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 /securedwithout authentication:curl -i http://simple-service.lb/secured
It should return:
HTTP/1.1 401 ... -
Create an environment variable that contains the
Client Secretgenerated byKeycloaktosimple-serviceat Configure Keycloak step:SIMPLE_SERVICE_CLIENT_SECRET=...
-
Run the command below to get an access token for
user-testuser: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 default expiration period for the access token is
5 minutes. So, wait for this time and then, 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
Keycloakandsimple-serviceDocker container logsWe can verify that
Nginxis appropriately load balancing the requests when an access token request toKeycloakis made. To view theKeycloakDocker container logs, execute the following commands in different terminals:docker logs -f keycloak1 docker logs -f keycloak2
We can also verify that
Nginxis appropriately load balancing requests to thesimple-serviceendpoints. To view thesimple-serviceDocker container logs, execute the following commands in different terminals:docker logs -f simple-service1 docker logs -f simple-service2
-
Keycloak
The
Keycloakwebsite can be accessed at http://keycloak-cluster.lb -
Nginx
If you wish to modify the
Nginxconfiguration file without restarting its Docker container, follow these steps:- Apply the changes in the
nginx/nginx.conffile; - Execute the following command to access the
nginxDocker container:docker exec -it nginx bash - In the
nginxDocker 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, open a terminal, navigate to the spring-boot-nginx-keycloak-cluster root folder, and run the following script:
./shutdown-environment.shTo remove the simple-service Docker image created, open a terminal, navigate to the spring-boot-nginx-keycloak-cluster root folder, and run the following script:
./remove-docker-images.sh