siddhuoo7 / springboot-kong-keycloak

The goal is to create a Spring Boot app called book-service. It will only be reachable through Kong API gateway. In Kong, we will install kong-oidc plugin that will enable the communication between Kong and Keycloak OpenID Connect Provider. This way, when Kong receives a request to book-service, it will validate together with Keycloak whether it's a valid request or not before redirecting to the upstream service.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

springboot-kong-keycloak

The goal is to create a Spring Boot application to manage books, called book-service and secure it by using Kong API gateway and Keycloak OpenID Connect Provider.

Note: In kubernetes-minikube-environment repository, it's shown how to deploy this project in Kubernetes (Minikube)

Project Diagram

project-diagram

As we can see from the diagram, book-service will only be reachable through Kong API gateway.

In Kong, it's installed kong-oidc plugin that will enable the communication between Kong and Keycloak OpenID Connect Provider.

This way, when Kong receives a request to book-service, it will validate together with Keycloak whether it's a valid request.

Also, before redirecting to the request to the upstream service, a Serverless Function (post-function) will get the access token present in the X-Userinfo header provided by kong-oidc plugin, decoded it, extracts the username and preferred_username, and enriches the request with these two information before sending to book-service

Application

  • book-service

    Spring Boot REST API application to manages books. The API doesn't have any security. book-service uses MongoDB as storage.

    Endpoints

    GET /actuator/health
    GET /api/books
    POST /api/books {"isbn": "...", "title": "..."}
    GET /api/books/{isbn}
    DELETE /api/books/{isbn}
    

Prerequisites

Run application during development using Maven

  • Open a terminal and navigate to springboot-kong-keycloak root folder

  • Run the command below to start mongodb Docker container

    docker run -d --name mongodb -p 27017:27017 mongo:5.0.5
    
  • Run the command below to start book-service

    ./mvnw clean spring-boot:run --projects book-service
    
  • Open another terminal and call application endpoints

    curl -i http://localhost:9080/api/books
    
    curl -i -X POST http://localhost:9080/api/books -H "Content-Type: application/json" \
      -d '{"isbn": "123", "title": "Kong & Keycloak"}'
    
    curl -i http://localhost:9080/api/books/123
    
    curl -i -X DELETE http://localhost:9080/api/books/123
    
    curl -i http://localhost:9080/actuator/health
    
  • To stop

    • book-service, go to the terminal where it's running and press Ctrl+C
    • mongodb Docker container, go to a terminal and run the following command
      docker rm -fv mongodb
      

Build application Docker Image

  • In a terminal, make sure you are in springboot-kong-keycloak root folder

  • Build Docker Image

    ./docker-build.sh
    
    Environment Variable Description
    MONGODB_HOST Specify host of the Mongo database to use (default localhost)
    MONGODB_PORT Specify port of the Mongo database to use (default 27017)

Test application Docker Image

  • In a terminal, create a Docker network

    docker network create springboot-kong-keycloak-net
    
  • Run the command below to start mongodb Docker container

    docker run -d --name mongodb -p 27017:27017 --network springboot-kong-keycloak-net mongo:5.0.5
    
  • Run the following command to start book-service Docker container

    docker run --rm -p 9080:9080 --name book-service -e MONGODB_HOST=mongodb --network springboot-kong-keycloak-net ivanfranchin/book-service:1.0.0
    
  • Open another terminal and call application endpoints

    curl -i http://localhost:9080/api/books
    
    curl -i -X POST http://localhost:9080/api/books -H "Content-Type: application/json" \
      -d '{"isbn": "123", "title": "Kong & Keycloak"}'
    
    curl -i http://localhost:9080/api/books/123
    
    curl -i -X DELETE http://localhost:9080/api/books/123
    
    curl -i http://localhost:9080/actuator/health
    
  • To stop

    • book-service, go to the terminal where it's running and press Ctrl+C
    • mongodb Docker container, go to a terminal and run the following command
      docker rm -fv mongodb
      
    • remove Docker network
      docker network rm springboot-kong-keycloak-net
      

Build Kong Docker Image with kong-oidc plugin

  • In a terminal, make use you are in springboot-kong-keycloak root folder

  • Run the command below

    docker build -t kong:2.7.0-centos-oidc docker/kong
    

Start Environment

  • In a terminal, make use you are in springboot-kong-keycloak root folder

  • Run the following script

    ./start-docker-containers.sh
    
  • Wait for Docker containers to be up and running. To check it, run

    docker ps -a
    

Note: book-service application is running as a Docker container. The container does not expose any port to HOST machine. So, it cannot be accessed directly, forcing the caller to use Kong as gateway server in order to access it.

Configure Keycloak

  • Open a new terminal and make sure you are in springboot-kong-keycloak root folder

  • Run the following script to configure Keycloak for book-service application

    ./init-keycloak.sh
    

    This script creates:

    • company-services realm;
    • book-service client;
    • user with username ivan.franchin and password 123.
  • The book-service client secret (BOOK_SERVICE_CLIENT_SECRET) is shown at the end of the execution. It will be used in the next step

  • You can check the configuration in Keycloak by accessing http://localhost:8080. The credentials are admin/admin.

Configure Kong

  • In a terminal, make sure you are in springboot-kong-keycloak root folder

  • Create an environment variable that contains the Client Secret generated by Keycloak to book-service at Configure Keycloak step

    BOOK_SERVICE_CLIENT_SECRET=...
    
  • Run the following script to configure Kong for book-service application

    ./init-kong.sh $BOOK_SERVICE_CLIENT_SECRET
    

    This script creates:

    • service to book-service;
    • route to /actuator path;
    • route to /api path;
    • add kong-oidc plugin to route of /api path. It will authenticate users against Keycloak OpenID Connect Provider;
    • add serverless function (post-function) plugin to route of /api path. It gets the access token present in the X-Userinfo header provided by kong-oidc plugin, decoded it, extracts the username and preferred_username, and enriches the request with these two information before sending to book-service.

Testing

  • Try to call the public GET /actuator/health endpoint

    curl -i http://localhost:8000/actuator/health -H 'Host: book-service'
    

    It should return

    HTTP/1.1 200
    {"status":"UP"}
    
  • Try to call the private GET /api/books endpoint without access token

    curl -i http://localhost:8000/api/books -H 'Host: book-service'
    

    It should return

    HTTP/1.1 401 Unauthorized
    no Authorization header found
    
  • Get ivan.franchin access token

    ACCESS_TOKEN=$(./get-access-token.sh $BOOK_SERVICE_CLIENT_SECRET) && echo $ACCESS_TOKEN
    
  • Call again the private GET /api/books endpoint using the access token

    curl -i http://localhost:8000/api/books -H 'Host: book-service' \
      -H "Authorization: Bearer $ACCESS_TOKEN"
    

    It should return

    HTTP/1.1 200
    []
    
  • You can try other endpoints using access token

    Create book

    curl -i -X POST http://localhost:8000/api/books -H 'Host: book-service' \
      -H "Authorization: Bearer $ACCESS_TOKEN" \
      -H "Content-Type: application/json" -d '{"isbn": "123", "title": "Kong & Keycloak"}'
    

    Get book

    curl -i http://localhost:8000/api/books/123 -H 'Host: book-service' \
      -H "Authorization: Bearer $ACCESS_TOKEN"
    

    Delete book

    curl -i -X DELETE http://localhost:8000/api/books/123 -H 'Host: book-service' \
      -H "Authorization: Bearer $ACCESS_TOKEN"
    

Useful Links & Commands

  • MongoDB

    List books

    docker exec -it mongodb mongo bookdb
    db.books.find()
    

    Type exit to get out of MongoDB shell

  • jwt.io

    With jwt.io you can inform the JWT token received from Keycloak and the online tool decodes the token, showing its header and payload.

Shutdown

Go to the terminal where you run the script start-docker-containers.sh and press q to stop and remove all containers

Cleanup

To remove the Docker image created by this project, go to a terminal and, inside springboot-kong-keycloak root folder, run the script below

./remove-docker-images.sh

References

About

The goal is to create a Spring Boot app called book-service. It will only be reachable through Kong API gateway. In Kong, we will install kong-oidc plugin that will enable the communication between Kong and Keycloak OpenID Connect Provider. This way, when Kong receives a request to book-service, it will validate together with Keycloak whether it's a valid request or not before redirecting to the upstream service.


Languages

Language:Shell 52.2%Language:Java 44.6%Language:Lua 2.4%Language:Dockerfile 0.8%