Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/ivangfr/spring-boot-nginx-keycloak-cluster
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.
https://github.com/ivangfr/spring-boot-nginx-keycloak-cluster
docker java keycloak nginx oauth2-resource-server postgresql spring-boot spring-security spring-web-mvc
Last synced: about 1 month ago
JSON representation
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.
- Host: GitHub
- URL: https://github.com/ivangfr/spring-boot-nginx-keycloak-cluster
- Owner: ivangfr
- Created: 2024-04-18T20:08:18.000Z (9 months ago)
- Default Branch: main
- Last Pushed: 2024-12-04T11:51:07.000Z (about 2 months ago)
- Last Synced: 2024-12-04T12:37:19.378Z (about 2 months ago)
- Topics: docker, java, keycloak, nginx, oauth2-resource-server, postgresql, spring-boot, spring-security, spring-web-mvc
- Language: Shell
- Homepage:
- Size: 1.05 MB
- Stars: 3
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Funding: .github/FUNDING.yml
Awesome Lists containing this project
README
# spring-boot-nginx-keycloak-cluster
The goal of this project is to use [`Nginx`](https://nginx.org/en/) as a reverse proxy and load balancer for a [`Keycloak`](https://www.keycloak.org/) cluster with two instances and a [`Spring Boot`](https://docs.spring.io/spring-boot/index.html) application, called `simple-service`, also with two instances. The `simple-service` app will use `Keycloak` for IAM.
## Proof-of-Concepts & Articles
On [ivangfr.github.io](https://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.
## Additional Readings
- \[**Medium**\] [**Using Nginx to Load Balance Requests to a Spring Boot Web application**](https://medium.com/@ivangfr/using-nginx-to-load-balance-requests-to-a-spring-boot-web-application-83a497a2f8ab)
- \[**Medium**\] [**Using Nginx to Load Balance Requests to a Keycloak Cluster**](https://medium.com/@ivangfr/using-nginx-to-load-balance-requests-to-a-keycloak-cluster-52174c89a0e4)
- \[**Medium**\] [**Nginx Load Balancing Requests to a Keycloak Cluster and a Spring Boot app that uses Keycloak as IAM**](https://medium.com/@ivangfr/nginx-load-balancing-requests-to-a-keycloak-cluster-and-a-spring-boot-app-that-uses-keycloak-as-iam-8e9e8280587d)## Project Diagram
![project-diagram](documentation/project-diagram.jpeg)
## Application
- ### simple-service
`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 a `JWT` access token issued by `Keycloak`. The token must contain the role `APP_USER`.## Prerequisites
- [`Java 21+`](https://www.oracle.com/java/technologies/downloads/#java21)
- Some containerization tool [`Docker`](https://www.docker.com), [`Podman`](https://podman.io), etc.
- [`jq`](https://jqlang.github.io/jq/)## Building simple-service Docker Image
- In a terminal, navigate to `spring-boot-nginx-keycloak-cluster` root folder.
- Run the following script:
```
./docker-build.sh
```## Configure /etc/hosts
Add the line below to `/etc/hosts`
```
127.0.0.1 keycloak-cluster.lb simple-service.lb
```## Starting Environment
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;## Configuring Keycloak
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 the `simple-service` client;
- create `USERS` group;
- assign `APP_USER` client role to `USERS` group;
- create `user-test` user;
- assign `USERS` group to `user-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`.
## Testing the simple-service endpoints
1. Open a new terminal;
2. 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
```3. Try to call the endpoint `GET /secured` without authentication:
```
curl -i http://simple-service.lb/secured
```It should return:
```
HTTP/1.1 401
...
```4. Create an environment variable that contains the `Client Secret` generated by `Keycloak` to `simple-service` at [Configure Keycloak](#configuring-keycloak) step:
```
SIMPLE_SERVICE_CLIENT_SECRET=...
```5. 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
```6. 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
```7. 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"
...
```8. Checking `Keycloak` and `simple-service` Docker container logs
We can verify that `Nginx` is load balancing the requests appropriately when an access token request to `Keycloak` is made. To view the `Keycloak` 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 to `simple-service` endpoints. To view the `simple-service` Docker container logs, execute the following commands in different terminals:
```
docker logs -f simple-service1
docker logs -f simple-service2
```## Useful Links & Commands
- **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 container
```
docker exec -it nginx bash
```
- In the `nginx` Docker container terminal, run:
```
nginx -s reload
```
- To exit, just run the command `exit`.## Shutdown
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
```## Cleanup
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
```