DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Related

  • How To Build Web Service Using Spring Boot 2.x
  • Building REST API Backend Easily With Ballerina Language
  • 7 Microservices Best Practices for Developers
  • What Is API-First?

Trending

  • How to Format Articles for DZone
  • A Deep Dive into Tracing Agentic Workflows (Part 1)
  • Detecting Bugs and Vulnerabilities in Java With SonarQube
  • When Snowflake Lies to You: Understanding False Failures in dbt Pipelines
  1. DZone
  2. Data Engineering
  3. Databases
  4. Multi-tenancy authentication through Kong API Gateway

Multi-tenancy authentication through Kong API Gateway

By 
Cezar Romaniuc user avatar
Cezar Romaniuc
·
Jan. 13, 20 · Tutorial
Likes (2)
Comment
Save
Tweet
Share
16.2K Views

Join the DZone community and get the full member experience.

Join For Free

The API Gateway pattern implements a service that’s the entry point into the microservices based application, from external API clients or consumers.
It is responsible for request routing, API composition, and other edge functions such as authentication.

When working with a microservices architecture, either on a greenfield project or during migration from monolith, a best practice is to start addressing cross-cutting concerns. Authentication is such a concern and in this article we’ll cover the Authentication of a multi-tenancy application.

There are numerous technologies we can use to implement an API Gateway pattern, including off-the-shelf API Gateway products like Kong.


When it receives a request, Kong searches within a routing map that specifies which upstream service to route the request to. This function is identical to the reverse proxy feature provided by web servers such as NGINX. Kong is based on the NGINX HTTP server, and let us configure flexible routing rules that use the HTTP method, headers and path to select the backend/upstream service and it also provides a bundle of plugins that implement edge functions such as authentication: acl and key auth.


Let’t consider the following prerequisites and steps to implement api key based authentication:

  • myService - a microservice that should be private and exposes an endpoint http://myServicePrivateHost:80/api/v1/myServicePath
  • two tenants tenant1.mydomain.com and tenant2.mydomain.com for which we want to authenticate the requests
  • Kong running on http://localhost:8000 for proxying and http://localhost:8001 for Admin API


1. Create a service object, a representation of the upstream microservice

Request:

Shell




x


 
1
curl -X POST \
2
  http://localhost:8001/services \
3
  -H 'Content-Type: application/json' \
4
  -d '{
5
    "host": "myServicePrivateHost",
6
    "name": "myService"
7
}'


 Response:

Shell




x


 
1
{
2
    "host": "myServicePrivateHost",
3
    "created_at": 1577460734,
4
    "connect_timeout": 60000,
5
    "id": "110a66e0-ab86-495d-9fc7-1ade0eea6f41",
6
    "protocol": "http",
7
    "name": "myService",
8
    "read_timeout": 60000,
9
    "port": 80,
10
    "path": null,
11
    "updated_at": 1577460734,
12
    "retries": 5,
13
    "write_timeout": 60000,
14
    "tags": null,
15
    "client_certificate": null
16
}



2. Create a route object for each tenant

  • service id - is extracted from step 1 response
  • hosts - field containing the actual domain, tenant specific
  • route name - must be unique and in this case it is prefixed with the tenant name

Request:

Shell




x


 
1
curl -X POST \
2
  http://localhost:8001/routes \
3
  -H 'Content-Type: application/json' \
4
  -d '{
5
    "protocols": [
6
        "http",
7
        "https"
8
    ],
9
    "service": {
10
        "id": "110a66e0-ab86-495d-9fc7-1ade0eea6f41"
11
    },
12
    "name": "tenant1.routeForMyService",
13
    "preserve_host": false,
14
    "regex_priority": 0,
15
    "strip_path": false,
16
    "paths": [
17
        "/api/v1/myServicePath"
18
    ],
19
    "hosts": [
20
        "tenant1.mydomain.com"
21
    ],
22
    "methods": [
23
        "GET"
24
    ]
25
}'


Note: Perform the same request from the current step and replace tenant1 with tenant2 for the purpose of creating the route for the other tenant.


When a request comes in, Kong will make use of the host header, path and HTTP method in order to select the route. If no route will be found the response will be:

Shell




xxxxxxxxxx
1


 
1
{
2
    "message": "no Route matched with those values"
3
}


At this point we have two unauthenticated routes and we'll create a consumer for each of them. Those consumers can be client applications or users and they can have multiple api keys.


3. Create consumer object for each tenant

Request:

Shell




xxxxxxxxxx
1


 
1
curl --request POST \
2
  --url http://localhost:8001/consumers \
3
  --header 'Content-Type: application/json' \
4
  --data '{"username":"someConsumerForTenant1"}'


Note: Perform the same request from the current step and replace tenant1 with tenant2 for the purpose of creating the consumer for the other tenant.


Now we should group the consumers for a specific tenant (there are also cases where we want to group by a tenant's application as well) and the specified group name will be whitelisted for consuming the api.


4. Create a group for each consumer 

Request:

Shell




xxxxxxxxxx
1


 
1
curl --request POST \
2
  --url http://localhost:8001/consumers/someConsumerForTenant1/acls \
3
  --header 'Content-Type: application/json' \
4
  --data '{"group":"tenant1Group"}'


Note: Perform the same request from the current step and replace tenant1 with tenant2 for the purpose of creating the group for the other tenant.


5. Applying key-auth plugin for the tenant specific route

Request:

Shell




xxxxxxxxxx
1


 
1
curl --request POST \
2
  --url http://localhost:8001/routes/tenant1.routeForMyService/plugins \
3
  --header 'Content-Type: application/json' \
4
  --data '{"name":"key-auth"}'


Note: Perform the same request from the current step and replace tenant1 with tenant2 for the purpose of applying the plugin for the other tenant route.


6. Applying acl plugin for the tenant specific route

Request:

Shell




x


 
1
curl --request POST \
2
  --url http://localhost:8001/routes/tenant1.routeForMyService/plugins \
3
  --header 'Content-Type: application/json' \
4
  --data '{"name":"acl", "config":{"whitelist":["tenant1Group"]}}'


Note: Perform the same request from the current step and replace tenant1 with tenant2 for the purpose of applying the plugin for the other tenant route. 


7. Generate an api key for tenant1:

Request:

Shell




x


 
1
curl --request POST \
2
  --url http://localhost:8001/consumers/someConsumerForTenant1/key-auth \
3
  --header 'Content-Type: application/json' \
4
  --data '{}'


Response:

Shell




xxxxxxxxxx
1


 
1
{
2
    "key": "6DlgBFKA2a0uD9CHVgqQvsZfWsePC0zu",
3
    "created_at": 1577462044,
4
    "consumer": {
5
        "id": "47dd2c7b-8094-4a9f-96f0-15120ddb8a79"
6
    },
7
    "id": "40c69ad1-37f8-4551-ab66-eb3609e78f26"
8
}



8. Access /api/v1/myServicePath for tenant1 without an apikey header:

Request:

Shell




x


 
1
curl --request GET \
2
  --url http://localhost:8000/api/v1/myServicePath \
3
  --header 'host: tenant1.mydomain.com'


Response:

Shell




xxxxxxxxxx
1


 
1
{
2
    "message": "No API key found in request"
3
}



9. Access /api/v1/myServicePath for tenant1 with the corresponding api key generated in step 7:

Request:

Shell




x


 
1
curl --request GET \
2
  --url http://localhost:8000/api/v1/myServicePath \
3
  --header 'apikey: 6DlgBFKA2a0uD9CHVgqQvsZfWsePC0zu' \
4
  --header 'host: tenant1.mydomain.com'


Response:

Shell




xxxxxxxxxx
1


 
1
{
2
    "message": "name resolution failed"
3
}


Note: The response depends on the actual microservice deployed locally. If it's up and running it will return the proper response. In our case the service doesn't exist so it will return 503 service temporary unavailable and the above response.


10. Access /api/v1/myServicePath for tenant2 with the tenant1's api key:

 Response:

Shell




xxxxxxxxxx
1


 
1
{
2
    "message": "You cannot consume this service"
3
}



These steps can be further automated by creating a wrapper over Kong Admin API. It will be in fact a microservice other services (e.g an IAM  - Identity and access management - microservice responsible with authentication and authorization) will communicate with, as a means to generate consumers and api keys for those consumers.

In this way we can leverage Kong API Gateway for centralizing the authentication to our multi-tenancy application.

API authentication Requests shell microservice consumer Web Service application Database Best practice

Published at DZone with permission of Cezar Romaniuc. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • How To Build Web Service Using Spring Boot 2.x
  • Building REST API Backend Easily With Ballerina Language
  • 7 Microservices Best Practices for Developers
  • What Is API-First?

Partner Resources

×

Comments

The likes didn't load as expected. Please refresh the page and try again.

  • RSS
  • X
  • Facebook

ABOUT US

  • About DZone
  • Support and feedback
  • Community research

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 215
  • Nashville, TN 37211
  • [email protected]

Let's be friends:

  • RSS
  • X
  • Facebook