Skip to main content

Kong API Gateway การใช้งาน (ตอนที่ 2)

Kongvut Sangkla

Intro

สวัสดีครับ พบกับตอนที่ 2 จากคราวก่อนตอนที่ 1 จะเป็นการแนะนำและการติดตั้งโดยบทความนี้จะพามาลองใช้งาน Kong API Gateway โดยจะอธิบายเพื่อให้เห็นภาพและประโยชน์ในแง่การใช้งาน ซึ่งบทความมี 2 ตอนดังนี้

ทำความเข้าใจเบื้องต้น

ก่อนเริ่มใช้งาน Kong มาทำความเข้าใจหลักการเบื้องต้นก่อน โดยทั่วไป Kong API Gateway จะมีส่วนที่สำคัญ 3 ส่วนที่ผู้ใช้งานมือใหม่ควรทำความเข้าใจคือ

  1. Services คือการกำหนดชื่อของ Resources หรือชื่อของ Service ของ APIs เช่น Service Employees, Service Blog หรือ Service Billing
  2. Routes คือส่วนของ Path ของแต่ละ Endpoint (เป็น Subset ของ Services)
  3. Consumers คือผู้ที่สามารถใช้งาน API ได้ (เป็นแบบ Authenticated endpoints หมายถึงต้องมีการส่งข้อมูลอะไรบางอย่างเช่น API Keys หรือ JWT ยืนยันตัวตนก่อนใช้งานมากับ HTTP Headers)

ตัวอย่าง Use Cases

ตัวอย่างนี้จะใช้ข้อมูล JSON Placeholder API ของ https://jsonplaceholder.typicode.com ซึ่งเป็น Free fake data โดยจะใช้ Kong สร้าง Service 2 แบบดังนี้

  • Authenticated endpoints เข้าถึง API ได้โดยต้องแนบ API Keys หรือ JWT มากับ HTTP Headers

    Imgur

    รูปภาพ อธิบายการทำงานของ Use Case (แบบ Authenticated endpoints)

  • Public endpoints เข้าถึง API ได้โดยไม่ต้องแนบ API Keys หรือ JWT มากับ HTTP Headers

    Imgur

    รูปภาพ อธิบายการทำงานของ Use Case (แบบ Public endpoints)

กำหนด Services

เมื่อทำการ ติดตั้ง Kong และ Konga (ตอนที่ 1) เรียบร้อยแล้วให้ไปที่ URL ของ Konga ดังนี้

ขั้นตอน
ที่เมนู: ไปที่ http://localhost:1337 -> Services -> Add New Service

Imgur

ในหน้า Create Service ให้ระบุข้อมูลดังนี้

ขั้นตอน
เมนู: Services -> Add New Service

กำหนดค่าดังนี้
Name: JSON-Placeholder
Description: API Resource of json placeholder
Protocol: https
Host: jsonplaceholder.typicode.com
Port: 443
Path: /
Retries: 5
Connect timeout: 60000
Write timeout: 60000
Read timeout: 60000
note

ถ้าท่านกำหนดช่อง Url ดังนั้นไม่จำเป็นต้องกำหนด Protocol Host และ Port

สร้าง Routes

กำหนดข้อมูล Routes ของแต่ละ Path

ขั้นตอน
ที่เมนู: Service -> `JSON-Placeholder` (ที่ได้สร้างไว้แล้ว) 
-> Routes -> `Add Route`

Imgur

Users Route

/users

กำหนดค่าดังนี้
Name: Users
Path: /users (หลังระบุแล้วให้กด Enter ที่ช่อง Path)
Path handling: v1
Https redirect status code: 426
Regex priority: 0
Strip Path: No
Protocols: http, https

เพิ่ม Plugin JWT (/users)

เพิ่ม Plugin JWT สำหรับ Authenticated endpoints เข้าถึง API ได้โดยต้องแนบ JWT มากับ HTTP Headers

ขั้นตอน
ที่เมนู: `JSON-Placeholder` -> Users (Route)
-> Plugins -> Add Plugin

Imgur

JWT Plugin
เลือก Authentication: JWT (Add plugin)

กำหนดค่าดังนี้
key claim name: iss
secret is base64: No
run on preflight: Yes
maximum expiration: 0

Todos Route

/todos

กำหนดค่าดังนี้
Name: Todos
Path: /todos (หลังระบุแล้วให้กด Enter ที่ช่อง Path)
Path handling: v1
Https redirect status code: 426
Regex priority: 0
Strip Path: No
Protocols: http, https

เพิ่ม Plugin Key Auth (/todos)

เพิ่ม Plugin Key Auth สำหรับ Authenticated endpoints เข้าถึง API ได้โดยต้องแนบ API Keys มากับ HTTP Headers

ขั้นตอน
ที่เมนู: `JSON-Placeholder` -> Todos (Route)
-> Plugins -> Add Plugin

Imgur

Key Auth Plugin
เลือก Authentication: Key Auth (Add plugin)

กำหนดค่าดังนี้
key names: x-api-key
hide credential: No
key in header: Yes
key in query: No
key in header: No
run on prefligh: Yes

Photos Route

/photos

กำหนดค่าดังนี้
Name: Photos
Path: /photos (หลังระบุแล้วให้กด Enter ที่ช่อง Path)
Path handling: v1
Https redirect status code: 426
Regex priority: 0
Strip Path: No
Protocols: http, https

*ไม่มีการกำหนด Authentication Plugin เนื่องจากเป็นแบบ Public endpoints

Posts Route

/posts

กำหนดค่าดังนี้
Name: Posts
Path: /posts (หลังระบุแล้วให้กด Enter ที่ช่อง Path)
Path handling: v1
Https redirect status code: 426
Regex priority: 0
Strip Path: No
Protocols: http, https

*ไม่มีการกำหนด Authentication Plugin เนื่องจากเป็นแบบ Public endpoints

กำหนด Consumers

ในส่วนนี้จะเป็นการเพิ่ม Consumer User สำหรับ Authentication ของ /users และ /todos

Imgur

เพิ่ม Consumer
ที่เมนู: Consumer -> Create Consumer
username: kongvut (กำหนดชื่อที่ต้องการ)

Authenticated endpoints (API Keys)

Imgur

กำหนด API Keys
ที่เมนู: Consumer -> <ชื่อ Consumer ที่สร้างไว้> -> Credentials (1)
-> API Keys (2) -> Create API Key (3)

กำหนดค่าดังนี้
key: dk627EXCU1lxfRLUVO9W2eJJ090Cxrig (กำหนดค่าที่ต้องการ)

Authenticated endpoints (JWT)

Imgur

กำหนด JWT
ที่เมนู: Consumer -> <ชื่อ Consumer ที่สร้างไว้> -> Credentials (1)
-> JWT (2) -> Create JWT (3)

กำหนดค่าดังนี้
secret: R60LCNzBIRfKpGj43V2usCvhdcS4F2su (กำหนดค่าที่ต้องการ)
Result
{
"key": "W5gjacrhg7zY5FAyE8fq6OlQmDG7641w",
"id": "7be9e6ac-fbc2-4018-b923-814107a4481c",
"algorithm": "HS256",
"created_at": 1633793897,
"secret": "R60LCNzBIRfKpGj43V2usCvhdcS4F2su",
"tags": null,
"rsa_public_key": null,
"consumer": {
"id": "34dbbe8f-4407-41c6-ba84-1536f0a05172"
}
}

เมื่อได้ผลลัพธ์จากข้างบนเราสามารถใช้ Libraries ที่ช่วย Generate JWT ตามรายการดังนี้ https://jwt.io/libraries (แตกต่างกันไปตามภาษา)

ทดสอบ Generate JWT (Manual)

ตัวอย่างนี้จะทดลองใช้ JWT Builder แบบ Manual ของ http://jwtbuilder.jamiekurtz.com โดยกำหนดค่าดังนี้

กำหนดค่าดังนี้
Issuer: W5gjacrhg7zY5FAyE8fq6OlQmDG7641w (key)
Issued At: วันเวลาที่ออก Token
Expiration: วันเวลาที่ Token หมดอายุ
Audience: blog.2my.xyz (ชื่อผู้ที่รับรอง Token)
Subject: kongvut (id หรือ username ของผู้ใช้ Token)

Additional Claims (เพิ่มได้ตามที่ต้องการ)
FirstName: Kongvut
Surname: Sangkla
Email: [email protected]

Signed JSON Web Token
Key: R60LCNzBIRfKpGj43V2usCvhdcS4F2su (secret)
Result
{
"iss": "W5gjacrhg7zY5FAyE8fq6OlQmDG7641w",
"iat": 1633791293,
"exp": 1665327293,
"aud": "blog.2my.xyz",
"sub": "kongvut",
"FirstName": "Kongvut",
"Surname": "Sangkla",
"Email": "[email protected]"
}

//ผลลัพธ์เมื่อกด Generate
//eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJXNWdqYWNyaGc3elk1RkF5RThmcTZPbFFtREc3NjQxdyIsImlhdCI6MTYzMzc5MTI5MywiZXhwIjoxNjY1MzI3MjkzLCJhdWQiOiJibG9nLjJteS54eXoiLCJzdWIiOiJrb25ndnV0IiwiRmlyc3ROYW1lIjoiS29uZ3Z1dCIsIlN1cm5hbWUiOiJTYW5na2xhIiwiRW1haWwiOiJrb25ndnV0QG1zbi5jb20ifQ.oqc58iIBhuJHkI4PtBVD5oO28ZJ47B6uNhUnDoQiOz4

ทดสอบการใช้งาน

ทดสอบการใช้งานจะแบ่งออกเป็น 2 ประเภทดังต่อไปนี้

แบบ Public

ทดสอบเรียก API แบบ GET สำหรับ /photos และ /posts ใช้งานทันที (เนื่องจากไม่ต้องส่ง key สำหรับ Authentication) โดยใช้ Postman

Imgur

แบบ Authentication

ทดสอบเรียก API แบบ GET สำหรับ /todos และ /users (โดยไม่ส่ง key ไปด้วย) จะพบปัญหาไม่สามารถเข้าถึง API ดังนี้

ของ JWT
{
"message": "Unauthorized"
}
ของ API Keys
{
"message": "No API key found in request"
}

ทดสอบส่ง key ไปด้วย

Request ในรูปแบบ JWT
curl --location --request GET 'http://localhost:8000/users' \
--header 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJXNWdqYWNyaGc3elk1RkF5RThmcTZPbFFtREc3NjQxdyIsImlhdCI6MTYzMzc5MTI5MywiZXhwIjoxNjY1MzI3MjkzLCJhdWQiOiJibG9nLjJteS54eXoiLCJzdWIiOiJrb25ndnV0IiwiR2l2ZW5OYW1lIjoiS29uZ3Z1dCIsIlN1cm5hbWUiOiJTYW5na2xhIiwiRW1haWwiOiJrb25ndnV0QG1zbi5jb20ifQ.tHfNdCiYVqFu3XJ1XwZepCGRXgKRwWPk8Ey8GoUDlgM'
Request ในรูปแบบ API Keys
curl --location --request GET 'http://localhost:8000/todos' \
--header 'x-api-key: dk627EXCU1lxfRLUVO9W2eJJ090Cxrig'

ถ้าไม่มีอะไรผิดพลาดคุณจะได้รับผลลัพธ์ข้อมูล Resource ของ /users และ /todos ในรูปแบบ JSON

สรุป

ก็คงพอมองเห็นภาพรวมการใช้งานเบื้องต้น แต่ในการใช้งานจริง ๆ นั้นควรมีการกำหนด Namespace และ API Version ของ API เพื่อให้รองรับการทำงานที่หลากหลาย หรือหากมี Services เพิ่มเติมในอนาคตตัวอย่างเช่น

- http://localhost:8000/api/staff/v1/users
- http://localhost:8000/api/staff/v1/todos
- http://localhost:8000/api/staff/v2/posts
- http://localhost:8000/api/staff/v2/photos

- http://localhost:8000/api/shop/v1/items
- http://localhost:8000/api/shop/v1/categories
- http://localhost:8000/api/shop/v2/promotions

ทั้งนี้รายละเอียดของ Kong ยังมีอยู่อีกเยอะมากแนะนำอ่าน Documents เพิ่มเติมที่ References เนื่องจากจะมีรายละเอียดการทำ Upstream Object สำหรับการทำ Load balance เพื่อให้รองรับ Requests ที่มากขึ้นและการทำ Fail Over เมื่อบาง Service ไม่สามารถเข้าถึงได้จะมี Service อื่นมาทดแทน อีกทั้งยังมีหัวข้ออื่น ๆ ที่น่าสนใจที่ควรอ่านเพิ่มเช่น

  • Path handling: v0, v1
  • Strip Path: การทำ strip เมื่อ matching กับ path
  • Preserve Host: การกำหนด host ที่สามารถใช้ API ได้

References

Loading...