Skip to content

The goal of this project is to create a simple Spring Boot REST API and secure it with Kong using the LDAP Authentication and Basic Authentication plugins. Besides, we will explore more plugins that Kong offers, such as the Rate Limiting and Prometheus plugins.

Notifications You must be signed in to change notification settings

ivangfr/springboot-kong-plugins

Repository files navigation

springboot-kong-plugins

The goal of this project is to create a simple Spring Boot REST API and secure it with Kong using the LDAP Authentication and Basic Authentication plugins. Besides, we will explore more plugins that Kong offers, such as the Rate Limiting and Prometheus plugins.

Proof-of-Concepts & Articles

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.

Additional Readings

Project Diagram

project-diagram

Application

  • simple-service

    Spring Boot Java Web application that exposes two endpoints:

    • /api/public: that can be accessed by anyone; it is not secured.
    • /api/private: that must be accessed only by authenticated users.

Prerequisites

Run application during development using Maven

  • Open a terminal and navigate to the springboot-kong-plugins root folder.

  • Run the command below to start:

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

    curl -i localhost:8080/api/public
    curl -i localhost:8080/api/private
    curl -i localhost:8080/actuator/beans
    curl -i localhost:8080/actuator/health
  • To stop, go to the terminal where the application is running and press Ctrl+C.

Build application Docker Image

  • In a terminal, make sure you are in the springboot-kong-plugins root folder.

  • Build Docker Image

    • JVM
      ./build-docker-images.sh
    • Native
      ./build-docker-images.sh native

Test application Docker Image

  • In a terminal, run the following command:

    docker run --rm -p 8080:8080 --name simple-service ivanfranchin/simple-service:1.0.0
  • Open another terminal and call the application endpoints:

    curl -i localhost:8080/api/public
    curl -i localhost:8080/api/private
    curl -i localhost:8080/actuator/beans
    curl -i localhost:8080/actuator/health
  • To stop, go to the terminal where the application is running and press Ctrl+C.

Initialize Environment

  • In a terminal, make sure you are in the springboot-kong-plugins root folder.

  • Run the following script:

    ./init-environment.sh

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

Import OpenLDAP Users

The LDIF file that we will use, ldap/ldap-mycompany-com.ldif, has already a pre-defined structure for mycompany.com. Basically, it has 2 groups (developers and admin) and 4 users (Bill Gates, Steve Jobs, Mark Cuban and Ivan Franchin). Besides, it is defined that Bill Gates, Steve Jobs and Mark Cuban belong to the developers group, and Ivan Franchin belongs to the admin group.

Bill Gates > username: bgates, password: 123
Steve Jobs > username: sjobs, password: 123
Mark Cuban > username: mcuban, password: 123
Ivan Franchin > username: ifranchin, password: 123

There are two ways to import those users: by running a script or using phpldapadmin.

Import users running a script

  • In another terminal, make sure you are in the springboot-kong-plugins root folder.

  • Run the following script:

    ./import-openldap-users.sh
  • Check users imported using ldapsearch:

    ldapsearch -x -D "cn=admin,dc=mycompany,dc=com" \
      -w admin -H ldap://localhost:389 \
      -b "ou=users,dc=mycompany,dc=com" \
      -s sub "(uid=*)"

Import users using phpldapadmin

  • Access https://localhost:6443

  • Login with the credentials:

    Login DN: cn=admin,dc=mycompany,dc=com
    Password: admin
    
  • Import the file ldap/ldap-mycompany-com.ldif.

  • You should see something like:

    openldap

Kong

In a terminal, follow the steps below to configure Kong.

Check Status

  • Before starting, check if Kong admin API is accessible:

    curl -I http://localhost:8001

    It should return:

    HTTP/1.1 200 OK
    

Add Service

  1. The following call will add the simple-service service:

    curl -i -X POST http://localhost:8001/services \
      -d "name=simple-service" \
      -d "protocol=http" \
      -d "host=simple-service" \
      -d "port=8080"
  2. [Optional] To list all services run:

    curl -i http://localhost:8001/services

Add routes

  1. One default route for the service, no specific path included:

    curl -i -X POST http://localhost:8001/services/simple-service/routes \
      -d "name=simple-service-default" \
      -d "protocols[]=http" \
      -d "hosts[]=simple-service"
  2. Another route specifically for /api/private endpoint (it will be secured and only accessible by LDAP users):

    curl -i -X POST http://localhost:8001/services/simple-service/routes \
      -d "name=simple-service-api-private" \
      -d "protocols[]=http" \
      -d "hosts[]=simple-service" \
      -d "paths[]=/api/private" \
      -d "strip_path=false"
  3. Finally, one route for /actuator/beans endpoint (it will be secured and only accessible by pre-defined users):

    curl -i -X POST http://localhost:8001/services/simple-service/routes \
      -d "name=simple-service-actuator-beans" \
      -d "protocols[]=http" \
      -d "hosts[]=simple-service" \
      -d "paths[]=/actuator/beans" \
      -d "strip_path=false"
  4. [Optional] To list all simple-service routes run:

    curl -i http://localhost:8001/services/simple-service/routes

Call the endpoints

  1. Call the /api/public endpoint:

    curl -i http://localhost:8000/api/public -H 'Host: simple-service'

    It should return:

    HTTP/1.1 200
    It is public.
    
  2. Call the /api/private endpoint:

    curl -i http://localhost:8000/api/private -H 'Host: simple-service'

    It should return:

    HTTP/1.1 200
    null, it is private.
    

    Note: This endpoint is not secured by the application, that is why the response is returned. The idea is to use Kong to secure it. It will be done on the next steps.

  3. Call the /actuator/beans endpoint:

    curl -i http://localhost:8000/actuator/beans -H 'Host: simple-service'

    It should return:

    HTTP/1.1 200
    {"contexts":{"simple-service":{"beans":...
    

    Note: As happened previously with /api/private, /actuator/beans endpoint is not secured by the application. We will use Kong to secure it on the next steps.

Plugins

In this project, we are going to add these plugins: LDAP Authentication, Basic Authentication, Rate Limiting and Prometheus. Please refer to https://konghq.com/plugins for more.

Add LDAP Authentication plugin

The LDAP Authentication plugin will be used to secure the /api/private endpoint.

  1. Add plugin to route simple-service-api-private:

    curl -i -X POST http://localhost:8001/routes/simple-service-api-private/plugins \
      -d "name=ldap-auth" \
      -d "config.hide_credentials=true" \
      -d "config.ldap_host=openldap" \
      -d "config.ldap_port=389" \
      -d "config.start_tls=false" \
      -d "config.base_dn=ou=users,dc=mycompany,dc=com" \
      -d "config.verify_ldap_host=false" \
      -d "config.attribute=cn" \
      -d "config.cache_ttl=60" \
      -d "config.header_type=ldap"
  2. Try to call the /api/private endpoint without credentials:

    curl -i http://localhost:8000/api/private -H 'Host: simple-service'

    It should return:

    HTTP/1.1 401 Unauthorized
    {
       "message":"Unauthorized",
       "request_id":"..."
     }
    
  3. Call the /api/private endpoint using Bill Gates base64-encoded credentials:

    curl -i http://localhost:8000/api/private \
      -H "Authorization:ldap $(echo -n 'Bill Gates':123 | base64)" \
      -H 'Host: simple-service'

    It should return:

    HTTP/1.1 200
    Bill Gates, it is private.
    

Add Basic Authentication plugin

The Basic Authentication plugin will be used to secure the /actuator/beans endpoint.

  1. Add plugin to route simple-service-actuator-beans:

    curl -i -X POST http://localhost:8001/routes/simple-service-actuator-beans/plugins \
      -d "name=basic-auth" \
      -d "config.hide_credentials=true"
  2. Try to call the /actuator/beans endpoint without credentials:

    curl -i http://localhost:8000/actuator/beans -H 'Host: simple-service'

    It should return:

    HTTP/1.1 401 Unauthorized
    {
       "message":"Unauthorized",
       "request_id":"..."
     }
    
  3. Create a consumer:

    curl -i -X POST http://localhost:8001/consumers -d "username=ivanfranchin"
  4. Create a credential for consumer:

    curl -i -X POST http://localhost:8001/consumers/ivanfranchin/basic-auth \
      -d "username=ivan.franchin" \
      -d "password=123"
  5. Call the /api/private endpoint using ivan.franchin credentials:

    curl -i -u ivan.franchin:123 http://localhost:8000/actuator/beans -H 'Host: simple-service'

    It should return:

    HTTP/1.1 200
    {"contentDescriptor":{"providerVersion":...
    
  6. Let's create another consumer just for testing purposes:

    curl -i -X POST http://localhost:8001/consumers -d "username=administrator"
    
    curl -i -X POST http://localhost:8001/consumers/administrator/basic-auth \
      -d "username=administrator" \
      -d "password=123"

Add Rate Limiting plugin

We are going to add the following rate limits:

  • /api/public and /actuator/health: one request per second.
  • /api/private: five requests a minute.
  • /actuator/beans: two requests a minute or 100 requests an hour.
  1. Add plugin to route simple-service-default:

    curl -i -X POST http://localhost:8001/routes/simple-service-default/plugins \
      -d "name=rate-limiting" \
      -d "config.second=1"
  2. Add plugin to route simple-service-api-private:

    curl -i -X POST http://localhost:8001/routes/simple-service-api-private/plugins \
      -d "name=rate-limiting" \
      -d "config.minute=5"
  3. Add plugin to route simple-service-actuator-beans:

    curl -i -X POST http://localhost:8001/routes/simple-service-actuator-beans/plugins \
      -d "name=rate-limiting" \
      -d "config.minute=2" \
      -d "config.hour=100"
  4. Make some calls to these endpoints.

    • Test /api/public:

      curl -i http://localhost:8000/api/public -H 'Host: simple-service'
      curl -i http://localhost:8000/actuator/health -H 'Host: simple-service'
    • Test /actuator/beans:

      curl -i -u ivan.franchin:123 http://localhost:8000/actuator/beans -H 'Host: simple-service'
      curl -i -u administrator:123 http://localhost:8000/actuator/beans -H 'Host: simple-service'
    • Test /api/private:

      curl -i http://localhost:8000/api/private \
        -H "Authorization:ldap $(echo -n 'Bill Gates':123 | base64)" \
        -H 'Host: simple-service'
      
      curl -i http://localhost:8000/api/private \
        -H "Authorization:ldap $(echo -n 'Mark Cuban':123 | base64)" \
        -H 'Host: simple-service'
  5. After exceeding some calls in a minute, you should see:

    HTTP/1.1 429 Too Many Requests
     {
        "message":"API rate limit exceeded",
        "request_id":"..."
     }
    

Add Prometheus plugin

  1. Add plugin to simple-service:

    curl -i -X POST http://localhost:8001/services/simple-service/plugins -d "name=prometheus"
  2. Make some requests to simple-service endpoints.

  3. You can see some metrics:

    curl -i http://localhost:8001/metrics

Shutdown

In a terminal and, inside the springboot-kong-plugins root folder, run the following script:

./shutdown-environment.sh

Cleanup

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

./remove-docker-images.sh

About

The goal of this project is to create a simple Spring Boot REST API and secure it with Kong using the LDAP Authentication and Basic Authentication plugins. Besides, we will explore more plugins that Kong offers, such as the Rate Limiting and Prometheus plugins.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Sponsor this project

 

Packages

No packages published