Get Started - Explore Workspaces - Create a Shared Service Across Workspaces

Introduction

Kong Enterprise ships with a novel Workspaces implementation, allowing Kong Admins to segment Admin API configuration & traffic domains. Workspaces are useful in a wide range of scenarios; for instance, in multi-team setups, where multiple teams share the same Kong cluster.

In previous Kong Enterprise versions, these teams would be able to access each other’s Admin API entities, which might be undesirable for many reasons; in Kong Enterprise 0.33 it’s possible for teams to have their own private, segmented spaces, while still sharing the same Kong cluster.

Workspaces

Kong Enterprise includes Workspaces (via the Kong Manager or Admin API), where you can organize your Kong Enterprise implementation for scale across teams. Key features include:

  • Simplify team management by creating default roles for each workspace, and custom roles as needed
  • Easily create new users, assign them to workspaces, and even brand with colors/images if needed
  • Organize your services, plugins, consumer management, and more according to your exact specification
  • Use Enhanced RBAC to restrict your teams’ access to see only see what they need to, and only what they should.
  • Appoint workspace-specific admins to maintain governance while avoiding becoming bottle-necked by a single administrator.

Learning Lab

With workspaces, you can organize your Kong Enterprise implementation for scale across teams. In this learning lab, you will:

  1. Create 3 workspaces with 1 shared service
  2. Create 3 different routes types for the shared service
  3. Verify access to each route to the shared service

High Level Tasks

  • Step 0: Review: Setup the environment
  • Step 1: List workspaces and its entities
  • Step 2: Create 3 different workspaces
  • Step 3: Create 1 shared service and add it to these workspaces
  • Step 4: Add a routes for shared service to each workspace
  • Step 5: Verify the service is shared between workspaces

The Topics and Tasks are as follows.


Step 0: Review: Setup the environment

Let’s setup the environment that will load the following

  1. Creates a Docker Network called kong-net
  2. Installs and starts the database
  3. Prepares your database (Kong migration)
  4. Installs and starts Kong with environment variables and configurations

Launch Setup Script

Run this script in the terminal to setup your environment (~30 seconds).

launch.sh

Step 1: List workspaces and its entities

List workspaces and its entities

http get :8001/workspaces

Response

HTTP/1.1 200 OK
{  
"data": [  
{  
"config": {  
"portal": true  
},  
"created_at": 1546437794000,  
"id": "6d9e2ec6-4a99-4ba6-9fe0-a8b0c9f0b617",  
"meta": {},  
"name": "**default**"  
}  
],  
"total": 1  
}

List entities in the default workspace

http GET :8001/workspaces/default/entities

Response

HTTP/1.1 200 OK
{  
"data": [  
{  
"entity_id": "b8c5a2a3-7308-49cf-a481-f3f716f74501",  
"entity_type": "rbac_roles",  
"unique_field_name": "name",  
"unique_field_value": "super-admin",  
"workspace_id": "6d9e2ec6-4a99-4ba6-9fe0-a8b0c9f0b617",  
"workspace_name": "default"  
},  
{  
"entity_id": "b8c5a2a3-7308-49cf-a481-f3f716f74501",  
"entity_type": "rbac_roles",  
"unique_field_name": "id",  
"unique_field_value": "b8c5a2a3-7308-49cf-a481-f3f716f74501",  
"workspace_id": "6d9e2ec6-4a99-4ba6-9fe0-a8b0c9f0b617",  
"workspace_name": "default"  
},  
{  
"entity_id": "354f3cd0-3302-4007-94b2-aca1ce4dd721",  
"entity_type": "rbac_roles",  
"unique_field_name": "name",  
"unique_field_value": "admin",  
"workspace_id": "6d9e2ec6-4a99-4ba6-9fe0-a8b0c9f0b617",  
"workspace_name": "default"  
}

Step 2: Create 3 different workspaces

http POST :8001/workspaces \
name=teamA
http POST :8001/workspaces \
name=teamB
http POST :8001/workspaces \
name=teamC

List workspaces.

How many workspaces are there? Why is there an extra one?

http get :8001/workspaces

Response

HTTP/1.1 200 OK  
...
{
"data": [  
{  
"config": {  
"portal": false  
},  
"created_at": 1547034980000,  
"id": "a2f991c2-98c8-43b3-b626-1a6268925f08",  
"meta": {},  
"name": "**teamC**"  
},  
{  
"config": {  
"portal": false  
},  
"created_at": 1547034977000,  
"id": "34b5fb87-5f9b-470f-a591-b0b25e8a5c32",  
"meta": {},  
"name": "**teamB**"  
},  
{  
"config": {  
"portal": true  
},  
"created_at": 1547034938000,  
"id": "27ead2dc-31b7-48dd-9ad8-5249bef6642f",  
"meta": {},  
"name": "**default**"  
},  
{  
"config": {  
"portal": false  
},  
"created_at": 1547034972000,  
"id": "e22ac4e2-e023-4efb-be7e-68beda0c7c5a",  
"meta": {},  
"name": "**teamA**"  
}  
],  
"total": 4
}

Step 3: Create 1 shared service and add it to these workspaces

Add a shared entity to each of the workspaces

Having teamA, teamB, and teamC workspaces set up, add some entities to each of them.

Let’s add a shared service- represented by the Service Kong entity and then add different routes associated with this upstream service.

Create the shared service

Add a service to Kong named shared-service that will proxy request going to the URL httpbin.org/ Run this command to add the service:

http post :8001/services \
url=http://httpbin.org/ \
name=shared-service

Response

HTTP/1.1 201 Created  
{  
"connect_timeout": 60000,  
"created_at": 1546439401,  
"host": "httpbin.org",  
"id": "365b8798-96a6-46de-96b8-0c38a70526b9",  
"name": "shared-service",  
"path": "/",  
"port": 80,  
"protocol": "http",  
"read_timeout": 60000,  
"retries": 5,  
"updated_at": 1546439401,  
"write_timeout": 60000  
}

Verify entity you just created

Notice the endpoint /services does not include a workspace prefix—which is how one specifies the workspace under which a given API call applies to. In such cases, the call applies to the default workspace. Confirm that by listing all entities under the default workspace:

http get :8001/workspaces/default/entities

Response

The response should look similar to this. Entities not relevant for this example are redacted. Notice that our shared-service is on the list.

**HTTP/1.1 200 OK**  
...  
{  
"entity_id": "ffa49a62-d471-426e-b24a-648641b38d64",  
"entity_type": "basicauth_credentials",  
"unique_field_name": "id",  
"unique_field_value": "ffa49a62-d471-426e-b24a-648641b38d64",  
"workspace_id": "27ead2dc-31b7-48dd-9ad8-5249bef6642f",  
"workspace_name": "default"  
},  
{  
"entity_id": "4a9b8e08-1bae-4aab-ba03-441662f5733a",  
"entity_type": "services",  
"unique_field_name": "name",  
"unique_field_value": "**shared-service**",  
"workspace_id": "27ead2dc-31b7-48dd-9ad8-5249bef6642f",  
"workspace_name": "**default**"  
},  
{  
"entity_id": "4a9b8e08-1bae-4aab-ba03-441662f5733a",  
"entity_type": "services",  
"unique_field_name": "id",  
"unique_field_value": "4a9b8e08-1bae-4aab-ba03-441662f5733a",  
"workspace_id": "27ead2dc-31b7-48dd-9ad8-5249bef6642f",  
"workspace_name": "default"  
}  
],  
"total": 113

Set Variable

Set variable for the $shared_service for later use

shared_service variable

shared_service=$(http get :8001/services/shared-service | python -c "import sys, json; print json.load(sys.stdin)['id']")

Note: If you do not set this variable, run the following command to get the id string for the shared-service. Replace any $share_service variable below with this id string

http get :8001/services/shared-service

Add shared service to workspace teams

The next step is to add the shared service to the team workspaces. This can be done as follows.

http post :8001/workspaces/teamA/entities \
entities=$shared_service

Response

**HTTP/1.1 201 Created**  
...  
[  
{  
"connect_timeout": 60000,  
"created_at": 1547035900,  
"host": "httpbin.org",  
"id": "4a9b8e08-1bae-4aab-ba03-441662f5733a",  
"name": "shared-service",  
"path": "/",  
"port": 80,  
"protocol": "http",  
"read_timeout": 60000,  
"retries": 5,  
"updated_at": 1547035900,  
"write_timeout": 60000  
}  
]
http post :8001/workspaces/teamB/entities \
entities=$shared_service  
http post :8001/workspaces/teamC/entities \
entities=$shared_service

Verify shared service is added to for each workspace

Run the following command to verify the service for teamA.
Repeat this command for teamB and teamC

http :8001/teamA/services

Response

The response should look similar to this. Notice the id. This will be the same for teamB and teamC.

**HTTP/1.1 200 OK**  
...  

{  
"data": [  
{  
"connect_timeout": 60000,  
"created_at": 1547035900,  
"host": "httpbin.org",  
"id": "**4a9b8e08-1bae-4aab-ba03-441662f5733a**",  
"name": "shared-service",  
"path": "/",  
"port": 80,  
"protocol": "http",  
"read_timeout": 60000,  
"retries": 5,  
"updated_at": 1547035900,  
"write_timeout": 60000  
}  
],  
"next": null  
}

Step 4: Add a routes for the shared service

Add route to shared service

The next step is to set up each team’s routes to the shared service. For example, teamA, teamB, and teamC have routes /headers, /ip, and /user-agent, respectively.

Note: the service.id is set to the variable you created previously. If this variable was not set make sure you use the service.id which is a string that looks like this 4a9b8e08-1bae-4aab-ba03-441662f5733a

Team A

http POST :8001/teamA/routes \
paths[]=/headers \
service.id=$shared_service \
strip_path=false -f

Response

HTTP/1.1 201 Created  
...  
{  
"created_at": 1547037399,  
"hosts": null,  
"id": "14af8345-31ff-4a5e-90a0-f3df4026a440",  
"methods": null,  
"paths": [  
"**/headers**"  
],  
"preserve_host": false,  
"protocols": [  
"http",  
"https"  
],  
"regex_priority": 0,  
"service": {  
"id": "4a9b8e08-1bae-4aab-ba03-441662f5733a"  
},  
"strip_path": false,  
"updated_at": 1547037399  
}

Team B

http POST :8001/teamB/routes \
paths[]=/ip \
service.id=$shared_service \
strip_path=false -f

Response

HTTP/1.1 201 Created
...  
{  
"created_at": 1547037557,  
"hosts": null,  
"id": "0dca33f5-91b7-4f28-85c9-2c877d5404dd",  
"methods": null,  
"paths": [  
"**/ip**"  
],  
"preserve_host": false,  
"protocols": [  
"http",  
"https"  
],  
"regex_priority": 0,  
"service": {  
"id": "4a9b8e08-1bae-4aab-ba03-441662f5733a"  
},  
"strip_path": false,  
"updated_at": 1547037557  
}

Team C

http POST :8001/teamC/routes \
paths[]=/user-agent \
service.id=$shared_service \
strip_path=false -f  

Response

**HTTP/1.1 201 Created**  
...  
{  
"created_at": 1547037636,  
"hosts": null,  
"id": "d58cf4e7-9f88-4a31-b526-1fc206cac616",  
"methods": null,  
"paths": [  
"**/user-agent****"**  
],  
"preserve_host": false,  
"protocols": [  
"http",  
"https"  
],  
"regex_priority": 0,  
"service": {  
"id": "4a9b8e08-1bae-4aab-ba03-441662f5733a"  
},  
"strip_path": false,  
"updated_at": 1547037636  
}

Step 5: Verify the service is shared between workspaces

Now you have all teams with their routes sharing the same service.
To make sure it is set up correctly, list the routes in each workspace.

Team A

Verify teamA has a /headers route pointing to the shared service.

http :8001/teamA/routes

Response

HTTP/1.1 200 OK  
...  

{  
"data": [  
{  
"created_at": 1547037399,  
"hosts": null,  
"id": "14af8345-31ff-4a5e-90a0-f3df4026a440",  
"methods": null,  
"paths": [  
"/headers"  
],  
"preserve_host": false,  
"protocols": [  
"http",  
"https"  
],  
"regex_priority": 0,  
"service": {  
"id": "4a9b8e08-1bae-4aab-ba03-441662f5733a"  
},  
"strip_path": false,  
"updated_at": 1547037399  
}  
],  
"next": null  
}

Team B

Verify teamB has a /ip route pointing to the shared service.

http :8001/teamB/routes

Response

HTTP/1.1 200 OK  
...  

{  
"data": [  
{  
"created_at": 1547037399,  
"hosts": null,  
"id": "14af8345-31ff-4a5e-90a0-f3df4026a440",  
"methods": null,  
"paths": [  
"/ip"  
],  
"preserve_host": false,  
"protocols": [  
"http",  
"https"  
],  
"regex_priority": 0,  
"service": {  
"id": "4a9b8e08-1bae-4aab-ba03-441662f5733a"  
},  
"strip_path": false,  
"updated_at": 1547037399  
}  
],  
"next": null  
}

Team C

Verify teamC has a /user-agent route pointing to the shared service.

http :8001/teamC/routes

Response

HTTP/1.1 200 OK  
...  

{  
"data": [  
{  
"created_at": 1547037399,  
"hosts": null,  
"id": "14af8345-31ff-4a5e-90a0-f3df4026a440",  
"methods": null,  
"paths": [  
"/user-agent"  
],  
"preserve_host": false,  
"protocols": [  
"http",  
"https"  
],  
"regex_priority": 0,  
"service": {  
"id": "4a9b8e08-1bae-4aab-ba03-441662f5733a"  
},  
"strip_path": false,  
"updated_at": 1547037399  
}  
],  
"next": null  
}

GREAT!

With this setup, Teams A, B, and C only have access to their own Routes entities through the Admin API.

In subsequent learning labs, you’ll configure RBAC for additional control such as granular read/write/delete/update rights assigned to workspaces. This allows for flexible intra and inter-team permission schemes.


What Next? Learning Challenge

Create an entity with the same name in different workspaces

​Given the following High Level Tasks, try to complete the learning challenge.

Introduction

Entities in different workspaces can have the same name! Different teams—belonging to different workspaces—are allowed to give any name to their entities. To provide an example of that, say that Teams A, B, and C want a particular consumer named guest—a different consumer for each team, sharing the same username.

High Level Tasks

  1. Create consumer with username=guest for each of the workspaces (provide different password for each user guest)
  2. Add this user to basic-authentication plugin
  3. Verify guest user has access to its respective workspace.

With this, Teams A, Team B, and Team C will have the freedom to operate their guest consumer independently, choosing authentication plugins or doing any other operation that is allowed in the non-workspaced Kong world.

Edit this page