通過實例理解API網關的主要功能特性
在當今的技術領域中,“下云”的概念正逐漸抬頭,像David Heinemeier Hansson[1](37signals公司的聯合創始人, Ruby on Rails的Creator)就直接將公司所有的業務都從公有云搬遷到了自建的數據中心[2]中。雖說大多數企業不會這么“極端”,但隨著企業對云原生架構采用的廣泛與深入,不可避免地面臨著對云服務的依賴。云服務在過去的幾年中被廣泛應用于構建靈活、可擴展的應用程序和基礎設施,為企業提供了許多便利和創新機會。然而,隨著業務規模的增長和數據量的增加,云服務的成本也隨之上升。企業開始意識到,對云服務的依賴已經成為一個值得重新評估的議題。云服務的開銷可能占據了企業可用的預算的相當大部分。為了保持競爭力并更好地控制成本,企業需要尋找方法來減少對云服務的依賴,尋找更經濟的解決方案,同時確保仍能獲得所需的性能、安全性和可擴展性。
在這樣的背景下,我們的關注點是選擇一款適宜的API網關,從主流功能特性的角度來評估候選者的支持。API網關作為現代云原生應用架構中的關鍵組件,扮演著連接前端應用和后端服務的中間層,負責管理、控制和保護API的訪問。它的功能特性對于確保API的安全性、可靠性和可擴展性至關重要。
盡管API網關并不是一個新鮮事物了,但對于那些長期依賴于云供應商的服務的人來說,它似乎變得有些“陌生”。因此,本文旨在幫助我們重新理解API網關的主要特性,并獲得對API網關選型的能力,以便在停止使用云供應商服務之前,找到一個合適的替代品^_^。
1. API網關回顧
API網關是現代應用架構中的關鍵組件之一,它的存在簡化了應用程序的架構,并為客戶端提供一個單一的訪問入口,并進行相關的控制、優化和管理。API網關可以幫助企業實現微服務架構、提高系統的可擴展性和安全性,并提供更好的開發者體驗和用戶體驗。
1.1 API網關的演化
隨著互聯網的快速發展和企業對API的需求不斷增長,API網關作為一種關鍵的中間層技術逐漸嶄露頭角并經歷了一系列的演進和發展。這里將API網關的演進歷史粗略分為以下幾個階段:
- API網關之前的早期階段
在互聯網發展的早期階段,大多數應用程序都是以單體應用的形式存在[3]。后來隨著應用規模的擴大和業務復雜性的增加,單體應用的架構變得不夠靈活和可擴展,面向服務架構(Service-Oriented Architecture,SOA)逐漸興起,企業開始將應用程序拆分成一組獨立的服務。這個時期,每個服務都是獨立對外暴露API,客戶端也是通過這些API直接訪問服務,但這會導致一些安全性、運維和擴展性的問題。之后,企業也開始意識到需要一種中間層來管理和控制這種客戶端到服務的通信行為,并確保服務的可靠性和安全性,于是開始有了API網關的概念。
- API網關的興起
早期的API網關,其主要功能就是單純的路由和轉發。API網關將請求從客戶端轉發到后端服務,并將后端服務的響應返回給客戶端。在這個階段,API網關的功能非常簡單,主要用于解決客戶端和后端服務之間的通信問題。
- API網關的成熟
隨著微服務架構的興起和API應用的不斷發展,企業開始將應用程序進一步拆分成更小的、獨立部署的微服務。每個對外暴露的微服務都有自己的API,并通過API網關進行統一管理和訪問。API網關在微服務架構中的作用變得更加重要,它的功能也逐漸豐富起來了。
在這一階段,它不僅負責路由和轉發請求,API網關還增加了安全和治理的功能,可以滿足幾個不同領域的微服務需求。比如:API網關可以通過身份認證、授權、訪問控制等功能來保護API的安全;通過基于重試、超時、熔斷的容錯機制等來對API的訪問進行治理;通過日志記錄、基于指標收集以及Tracing等對API的訪問進行觀測與監控;支持實時的服務發現等。
API網關(圖來自網絡)
- API網關的云原生化
隨著云原生技術的發展,如容器化和服務網格(Service Mesh)等,API網關也在不斷演進和適應新的環境。在云原生環境中,API網關實現了與容器編排系統(如Kubernetes)和服務網格集成,其自身也可以作為一個云原生服務來部署,以實現更高的可伸縮性、彈性和自動化。同時,新的技術和標準也不斷涌現,如GraphQL和gRPC等,API網關也增加了對這些新技術的集成和支持。
1.2 API網關的主要功能特性
從上面的演化歷史我們看到:API網關的演進使其從最初簡單的請求轉發角色,逐漸成為整個API管理和微服務架構中的關鍵組件。它不僅扮演著API管理層與后端服務層之間的適配器,也是云原生架構中不可或缺的基礎設施,使微服務管理更加智能化和自動化。下面是現代API網關承擔的主要功能特性,我們后續也會基于這些特性進行示例說明:
- 請求轉發和路由
- 身份認證和授權
- 流量控制和限速
- 高可用與容錯處理
- 監控和可觀測性
2. 那些主流的API網關
下面是來自CNCF Landscape[4]中的主流API網關集合(截至2023.11月),圖中展示了關于各個網關的一些細節,包括star數量和背后開發的公司或組織:
圖片
主流的API網關還有各大公有云提供商的實現,比如:Amazon的API Gateway[5]、Google Cloud的API Gateway[6]以及上圖中的Azure API Management等,但它們不在我們選擇范圍之內;雖然被CNCF收錄,但多數API網關受到的關注并不高,超過1k star的不到30%,這些不是很受關注或dev不是那么active的項目也無法在生產環境擔當關鍵角色;而像APISIX[7]、Kong[8]這兩個受關注很高的網關,它們是建構在Nginx之上實現的,技術棧與我們不契合;而像EMISSARY INGRESS[9]、Gloo等則是完全云原生化或者說是Kubernetes Native的,無法在無Kubernetes的基于VM或裸金屬的環境下部署和運行。
好吧,剩下的只有幾個Go實現的API Gateway了,在它們之中,我們選擇用Tyk API網關[10]來作為后續API功能演示的示例。
注:這并不代表Tyk API網關就要比其他Go實現的API Gateway優秀[11],只是它的資料比較齊全,適合在本文中作演示罷了。
3. API網關主要功能特性示例(Tyk API網關版本)
3.1 Tyk API網關簡介
記得在至少5年前就知道Tyk API網關[12]的存在,印象中它是使用Go語言開發的早期的那批API網關之一。Tyk從最初的純開源項目,到如今由背后商業公司支持,以Open Core模式開源[13]的網關,一直保持了active dev的狀態。經過多年的演進,它已經一款功能強大的開源兼商業API管理和網關解決方案[14],提供了全面的功能和工具,幫助開發者有效地管理、保護和監控API。同時,Tyk API網關支持多種安裝部署方式,即可以單一程序的方式放在物理機或VM上運行,也可以支持容器部署,通過docker-compose[15]拉起,亦可以通過Kubernetes Operator[16]將其部署在Kubernetes中,這也讓Tyk API網關具備了在各大公有云上平滑遷移的能力。
圖片
關于Tyk API網關開源版本的功能詳情[17],可以點擊左邊超鏈接到其官網查閱,這里不贅述。
3.2 安裝Tyk API網關
下面我們就來安裝一下Tyk API網關,我們直接在VM上安裝,VM上的環境是CentOS 7.9。Tyk API提供了很多中安裝方法,這里使用CentOS的yum包管理工具安裝Tyk API網關[18],大體步驟如下(演示均以root權限操作)。
3.2.1 創建tyk gateway軟件源
默認的yum repo中是不包含tyk gateway的,我們需要在/etc/yum.repos.d下面創建一個新的源,即新建一個tyk_tyk-gateway.repo文件,其內容如下:
[tyk_tyk-gateway]
name=tyk_tyk-gateway
baseurl=https://packagecloud.io/tyk/tyk-gateway/el/7/$basearch
repo_gpgcheck=1
gpgcheck=0
enabled=1
gpgkey=https://packagecloud.io/tyk/tyk-gateway/gpgkey
sslverify=1
sslcacert=/etc/pki/tls/certs/ca-bundle.crt
metadata_expire=300
[tyk_tyk-gateway-source]
name=tyk_tyk-gateway-source
baseurl=https://packagecloud.io/tyk/tyk-gateway/el/7/SRPMS
repo_gpgcheck=1
gpgcheck=0
enabled=1
gpgkey=https://packagecloud.io/tyk/tyk-gateway/gpgkey
sslverify=1
sslcacert=/etc/pki/tls/certs/ca-bundle.crt
metadata_expire=300
接下來我們執行下面命令來創建tyk_tyk-gateway這個repo的YUM緩存:
$yum -q makecache -y --disablerepo='*' --enablerepo='tyk_tyk-gateway'
導入 GPG key 0x5FB83118:
用戶ID : "https://packagecloud.io/tyk/tyk-gateway (https://packagecloud.io/docs#gpg_signing) <support@packagecloud.io>"
指紋 : 9179 6215 a875 8c40 ab57 5f03 87be 71bd 5fb8 3118
來自 : https://packagecloud.io/tyk/tyk-gateway/gpgkey
repo配置和緩存完畢后,我們就可以安裝Tyk API Gateway了:
$yum install -y tyk-gateway
安裝后的tky-gateway將以一個systemd daemon服務[19]的形式存在于主機上,程序意外退出或虛機重啟后,該服務也會被systemd自動拉起。通過systemctl status命令可以查看服務的運行狀態:
# systemctl status tyk-gateway
● tyk-gateway.service - Tyk API Gateway
Loaded: loaded (/usr/lib/systemd/system/tyk-gateway.service; enabled; vendor preset: disabled)
Active: active (running) since 日 2023-11-19 20:22:44 CST; 12min ago
Main PID: 29306 (tyk)
Tasks: 13
Memory: 19.6M
CGroup: /system.slice/tyk-gateway.service
└─29306 /opt/tyk-gateway/tyk --conf /opt/tyk-gateway/tyk.conf
11月 19 20:34:54 iZ2ze18rmx2avqb5xgb4omZ tyk[29306]: time="Nov 19 20:34:54" level=error msg="Connection to Redis faile...b-sub
11月 19 20:35:04 iZ2ze18rmx2avqb5xgb4omZ tyk[29306]: time="Nov 19 20:35:04" level=error msg="cannot set key in pollerC...ured"
11月 19 20:35:04 iZ2ze18rmx2avqb5xgb4omZ tyk[29306]: time="Nov 19 20:35:04" level=error msg="Redis health check failed...=main
Hint: Some lines were ellipsized, use -l to show in full.
3.2.2 安裝redis
我們看到tyk-gateway已經成功啟動,但從其服務日志來看,它在連接redis時報錯了!tyk gateway默認將數據存儲在redis中,為了讓tyk gateway正常運行,我們還需要安裝redis!這里我們使用容器的方式安裝和運行一個redis服務:
$docker pull redis:6.2.14-alpine3.18
$docker run -d --name my-redis -p 6379:6379 redis:6.2.14-alpine3.18
e5d1ec8d5f5c09023d1a4dd7d31d293b2d7147f1d9a01cff8eff077c93a9dab7
拉取并運行redis后,我們通過redis-cli驗證一下與redis server的連接:
# docker run -it --rm redis:6.2.14-alpine3.18 redis-cli -h 192.168.0.24
192.168.0.24:6379>
我們看到可以正常連接!但此時Tyk Gateway仍然無法與redis正常連接,我們還需要對Tyk Gateway做一些配置調整!
3.2.3 配置Tyk Gateway
yum默認將Tyk Gateway安裝到/opt/tyk-gateway下面,這個路徑下的文件布局如下:
$tree -F -L 2 .
.
├── apps/
│ └── app_sample.json
├── coprocess/
│ ├── api.h
│ ├── bindings/
│ ├── coprocess_common.pb.go
│ ├── coprocess_mini_request_object.pb.go
│ ├── coprocess_object_grpc.pb.go
│ ├── coprocess_object.pb.go
│ ├── coprocess_response_object.pb.go
│ ├── coprocess_return_overrides.pb.go
│ ├── coprocess_session_state.pb.go
│ ├── coprocess_test.go
│ ├── dispatcher.go
│ ├── grpc/
│ ├── lua/
│ ├── proto/
│ ├── python/
│ └── README.md
├── event_handlers/
│ └── sample/
├── install/
│ ├── before_install.sh*
│ ├── data/
│ ├── init_local.sh
│ ├── inits/
│ ├── post_install.sh*
│ ├── post_remove.sh*
│ ├── post_trans.sh
│ └── setup.sh*
├── middleware/
│ ├── ottoAuthExample.js
│ ├── sampleMiddleware.js
│ ├── samplePostProcessMiddleware.js
│ ├── samplePreProcessMiddleware.js
│ ├── testPostVirtual.js
│ ├── testVirtual.js
│ └── waf.js
├── policies/
│ └── policies.json
├── templates/
│ ├── breaker_webhook.json
│ ├── default_webhook.json
│ ├── error.json
│ ├── monitor_template.json
│ └── playground/
├── tyk*
└── tyk.conf
其中tyk.conf就是tyk gateway的配置文件,我們先看看其默認的內容:
$cat /opt/tyk-gateway/tyk.conf
{
"listen_address": "",
"listen_port": 8080,
"secret": "xxxxxx",
"template_path": "/opt/tyk-gateway/templates",
"use_db_app_configs": false,
"app_path": "/opt/tyk-gateway/apps",
"middleware_path": "/opt/tyk-gateway/middleware",
"storage": {
"type": "redis",
"host": "redis",
"port": 6379,
"username": "",
"password": "",
"database": 0,
"optimisation_max_idle": 2000,
"optimisation_max_active": 4000
},
"enable_analytics": false,
"analytics_config": {
"type": "",
"ignored_ips": []
},
"dns_cache": {
"enabled": false,
"ttl": 3600,
"check_interval": 60
},
"allow_master_keys": false,
"policies": {
"policy_source": "file"
},
"hash_keys": true,
"hash_key_function": "murmur64",
"suppress_redis_signal_reload": false,
"force_global_session_lifetime": false,
"max_idle_connections_per_host": 500
}
我們看到:storage下面存儲了redis的配置信息,我們需要將redis的host配置修改為我們的VM地址:
"host": "192.168.0.24",
然后重啟Tyk Gateway服務:
$systemctl daemon-reload
$systemctl restart tyk-gateway
之后,我們再查看tyk gateway的運行狀態:
systemctl status tyk-gateway
● tyk-gateway.service - Tyk API Gateway
Loaded: loaded (/usr/lib/systemd/system/tyk-gateway.service; enabled; vendor preset: disabled)
Active: active (running) since 一 2023-11-20 06:54:07 CST; 41s ago
Main PID: 20827 (tyk)
Tasks: 15
Memory: 24.8M
CGroup: /system.slice/tyk-gateway.service
└─20827 /opt/tyk-gateway/tyk --conf /opt/tyk-gateway/tyk.conf
11月 20 06:54:07 iZ2ze18rmx2avqb5xgb4omZ tyk[20827]: time="Nov 20 06:54:07" level=info msg="Loading API configurations...=main
11月 20 06:54:07 iZ2ze18rmx2avqb5xgb4omZ tyk[20827]: time="Nov 20 06:54:07" level=info msg="Tracking hostname" api_nam...=main
11月 20 06:54:07 iZ2ze18rmx2avqb5xgb4omZ tyk[20827]: time="Nov 20 06:54:07" level=info msg="Initialising Tyk REST API ...=main
11月 20 06:54:07 iZ2ze18rmx2avqb5xgb4omZ tyk[20827]: time="Nov 20 06:54:07" level=info msg="API bind on custom port:0"...=main
11月 20 06:54:07 iZ2ze18rmx2avqb5xgb4omZ tyk[20827]: time="Nov 20 06:54:07" level=info msg="Checking security policy: ...fault
11月 20 06:54:07 iZ2ze18rmx2avqb5xgb4omZ tyk[20827]: time="Nov 20 06:54:07" level=info msg="API Loaded" api_id=1 api_n...ip=--
11月 20 06:54:07 iZ2ze18rmx2avqb5xgb4omZ tyk[20827]: time="Nov 20 06:54:07" level=info msg="Loading uptime tests..." p...k-mgr
11月 20 06:54:07 iZ2ze18rmx2avqb5xgb4omZ tyk[20827]: time="Nov 20 06:54:07" level=info msg="Initialised API Definition...=main
11月 20 06:54:07 iZ2ze18rmx2avqb5xgb4omZ tyk[20827]: time="Nov 20 06:54:07" level=warning msg="All APIs are protected ...=main
11月 20 06:54:07 iZ2ze18rmx2avqb5xgb4omZ tyk[20827]: time="Nov 20 06:54:07" level=info msg="API reload complete" prefix=main
Hint: Some lines were ellipsized, use -l to show in full.
從服務日志來看,現在Tyk Gateway可以正常連接redis并提供服務了!我們也可以通過下面的命令驗證網關的運行狀態:
$curl localhost:8080/hello
{"status":"pass","version":"5.2.1","description":"Tyk GW","details":{"redis":{"status":"pass","componentType":"datastore","time":"2023-11-20T06:58:57+08:00"}}}
“/hello”是Tyk Gateway的內置路由,由Tyk網關自己提供服務。
到這里Tyk Gateway的安裝和簡單配置就結束了,接下來,我們就來看看API Gateway的主要功能特性,并借助Tyk Gateway來展示一下這些功能特性。
注:查看Tyk Gateway的運行日志,可以使用journalctl -u tyk-gateway -f命令實時follow最新日志輸出。
3.3 功能特性:請求轉發與路由
請求轉發和路由是API Gateway的主要功能特性之一,API Gateway可以根據請求的路徑、方法、查詢參數等信息將請求轉發到相應的后端服務,其內核與反向代理類似,不同之處在于API Gateway增加了“API”這層抽象,更加專注于構建、管理和增強API。
下面我們來看看Tyk如何配置API路由,我們首先創建一個新API。
3.3.1 創建一個新API
Tyk開源版支持兩種創建API的方式,一種是通過調用Tyk的控制類API[20],一種則是通過傳統的配置文件,放入特定目錄下[21]。無論哪種方式添加完API,最終都要通過Tyk Gateway熱加載(hot reload)或重啟才能生效。
注:Tyk Gateway的商業版本提供Dashboard,可以以圖形化的方式管理API,并且商業版本的API定義會放在Postgres或MongoDB中,我們這里用開源版本,只能手工管理了,并且API定義只能放在文件中。
下面,我們就來在Tyk上創建一個新的API路由,該路由示例的示意圖如下:
圖片
在未添加新API之前,我們使用curl訪問一下該API路徑:
$curl localhost:8080/api/v1/no-authn
Not Found
Tyk Gateway由于找不到API路由,返回Not Found。接下來,我們采用調用tyk gateway API的方式來添加路由:
$curl -v -H "x-tyk-authorization: {tyk gateway secret}" \
-s \
-H "Content-Type: application/json" \
-X POST \
-d '{
"name": "no-authn-v1",
"slug": "no-authn-v1",
"api_id": "no-authn-v1",
"org_id": "1",
"use_keyless": true,
"auth": {
"auth_header_name": "Authorization"
},
"definition": {
"location": "header",
"key": "x-api-version"
},
"version_data": {
"not_versioned": true,
"versions": {
"Default": {
"name": "Default",
"use_extended_paths": true
}
}
},
"proxy": {
"listen_path": "/api/v1/no-authn",
"target_url": "http://localhost:18081/",
"strip_listen_path": true
},
"active": true
}' http://localhost:8080/tyk/apis | python -mjson.tool
* About to connect() to localhost port 8080 (#0)
* Trying ::1...
* Connected to localhost (::1) port 8080 (#0)
> POST /tyk/apis HTTP/1.1
> User-Agent: curl/7.29.0
> Host: localhost:8080
> Accept: */*
> x-tyk-authorization: {tyk gateway secret}
> Content-Type: application/json
> Content-Length: 797
>
} [data not shown]
* upload completely sent off: 797 out of 797 bytes
< HTTP/1.1 200 OK
< Content-Type: application/json
< Date: Wed, 22 Nov 2023 05:38:40 GMT
< Content-Length: 53
<
{ [data not shown]
* Connection #0 to host localhost left intact
{
"action": "added",
"key": "no-authn-v1",
"status": "ok"
}
從curl返回結果我們看到:API已經被成功添加。這時tyk gateway的安裝目錄/opt/tyk-gateway的子目錄apps下會新增一個名為no-authn-v1.json的配置文件,這個文件內容較多,有300行,這里就不貼出來了,這個文件就是新增的no-authn API的定義文件[22]。
不過此刻,Tyk Gateway還需熱加載后才能為新的API提供服務,調用下面API可以觸發Tyk Gateway的熱加載:
$curl -H "x-tyk-authorization: {tyk gateway secret}" -s http://localhost:8080/tyk/reload/group | python -mjson.tool
{
"message": "",
"status": "ok"
}
注:即便觸發熱加載成功,但如果body中的json格式錯,比如多了一個結尾逗號,Tyk Gateway是不會報錯的!
API路由創建完畢并生效后,我們再來訪問一下API:
$ curl localhost:8080/api/v1/no-authn
{
"error": "There was a problem proxying the request"
}
我們看到:Tyk Gateway返回的已經不是“Not Found”了!現在我們創建一下no-authn這個API服務,考慮到適配更多后續示例,這里建立這樣一個http server:
// api-gateway-examples/httpserver
func main() {
// 解析命令行參數
port := flag.Int("p", 8080, "Port number")
apiVersion := flag.String("v", "v1", "API version")
apiName := flag.String("n", "example", "API name")
flag.Parse()
// 注冊處理程序
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Println(*r)
fmt.Fprintf(w, "Welcome api: localhost:%d/%s/%s\n", *port, *apiVersion, *apiName)
})
// 啟動HTTP服務器
addr := fmt.Sprintf(":%d", *port)
log.Printf("Server listening on port %d\n", *port)
log.Fatal(http.ListenAndServe(addr, nil))
}
我們啟動一個該http server的實例:
$go run main.go -p 18081 -v v1 -n no-authn
2023/11/22 22:02:42 Server listening on port 18081
現在我們再通過tyk gateway調用一下no-authn這個API:
$curl localhost:8080/api/v1/no-authn
Welcome api: localhost:18081/v1/no-authn
我們看到這次路由通了!no-authn API返回了期望的結果!
3.3.2 負載均衡
如果no-authn API存在多個服務實例,Tyk Gateway也可以將請求流量負載均衡到多個no-authn服務實例上去,下圖是Tyk Gateway進行請求流量負載均衡[23]的示意圖:
要實現負責均衡,我們需要調整no-authn API的定義,這次我們直接修改/opt/tyk-gateway/apps/no-authn-v1.json,變更的配置主要有三項:
// /opt/tyk-gateway/apps/no-authn-v1.json
"proxy": {
"preserve_host_header": false,
"listen_path": "/api/v1/no-authn",
"target_url": "", // (1) 改為""
"disable_strip_slash": false,
"strip_listen_path": true,
"enable_load_balancing": true, // (2) 改為true
"target_list": [ // (3) 填寫no-authn服務實例列表
"http://localhost:18081/",
"http://localhost:18082/",
"http://localhost:18083/"
],
修改完配置后,調用Tyk的控制類API使之生效,然后我們啟動三個no-authn的API實例:
$go run main.go -p 18081 -v v1 -n no-authn
$go run main.go -p 18082 -v v1 -n no-authn
$go run main.go -p 18083 -v v1 -n no-authn
接下來,我們多次調用curl訪問no-authn API:
$curl localhost:8080/api/v1/no-authn
Welcome api: localhost:18081/v1/no-authn
$curl localhost:8080/api/v1/no-authn
Welcome api: localhost:18082/v1/no-authn
$curl localhost:8080/api/v1/no-authn
Welcome api: localhost:18083/v1/no-authn
$curl localhost:8080/api/v1/no-authn
Welcome api: localhost:18081/v1/no-authn
$curl localhost:8080/api/v1/no-authn
Welcome api: localhost:18082/v1/no-authn
$curl localhost:8080/api/v1/no-authn
Welcome api: localhost:18083/v1/no-authn
我們看到:Tyk Gateway在no-authn API的各個實例之間做了等權重的輪詢。如果我們停掉實例3,再來訪問該API,我們將得到下面結果:
$curl localhost:8080/api/v1/no-authn
Welcome api: localhost:18081/v1/no-authn
$curl localhost:8080/api/v1/no-authn
Welcome api: localhost:18082/v1/no-authn
$curl localhost:8080/api/v1/no-authn
Bad Request
$curl localhost:8080/api/v1/no-authn
Welcome api: localhost:18081/v1/no-authn
$curl localhost:8080/api/v1/no-authn
Welcome api: localhost:18082/v1/no-authn
$curl localhost:8080/api/v1/no-authn
Bad Request
注:Tyk Gateway商業版通過Dashboard支持配置帶權重的RR負載均衡算法[24]。
我們看到:實例3已經下線,但Tyk Gateway并不會跳過該已經下線的實例,這在生產環境會給客戶端帶來不一致的響應。
3.3.3 服務實例存活檢測(uptime test)
Tyk Gateway在開啟負載均衡的時候,也提供了對后端服務實例的存活檢測機制,當某個服務實例down了后,負載均衡機制會繞過該實例將請求發到下一個處于存活狀態的實例;而當down機實例恢復后,Tyk Gateway也能及時檢測到服務實例上線,并將其加入流量負載調度。
支持存活檢測(uptime test)的API定義配置如下:
// /opt/tyk-gateway/apps/no-authn-v1.json
"uptime_tests": {
"disable": false,
"poller_group":"",
"check_list": [
{
"url": "http://localhost:18081/"
},
{
"url": "http://localhost:18082/"
},
{
"url": "http://localhost:18083/"
}
],
"config": {
"enable_uptime_analytics": true,
"failure_trigger_sample_size": 3,
"time_wait": 300,
"checker_pool_size": 50,
"expire_utime_after": 0,
"service_discovery": {
"use_discovery_service": false,
"query_endpoint": "",
"use_nested_query": false,
"parent_data_path": "",
"data_path": "",
"port_data_path": "",
"target_path": "",
"use_target_list": false,
"cache_disabled": false,
"cache_timeout": 0,
"endpoint_returns_list": false
},
"recheck_wait": 0
}
}
"proxy": {
... ...
"enable_load_balancing": true,
"target_list": [
"http://localhost:18081/",
"http://localhost:18082/",
"http://localhost:18083/"
],
"check_host_against_uptime_tests": true,
... ...
}
我們新增了uptime_tests的配置,uptime_tests的check_list中的url的值要與proxy中target_list中的值完全一樣,這樣Tyk Gateway才能將二者對應上。另外proxy的check_host_against_uptime_tests要設置為true。
這樣配置并生效后,等我們將服務實例3停掉后,后續到no-authn的請求就只會轉發到實例1和實例2了。而當恢復實例3運行后,Tyk Gateway又會將流量分擔到實例3上。
3.3.4 動態負載均衡
上面負載均衡示例中target_list中的目標實例的IP和端口的手工配置的,而在云原生時代,我們經常會基于容器承載API服務實例,當容器因故退出,并重新啟動一個新容器時,IP可能會發生變化,這樣上述的手工配置就無法滿足要求,這就對API Gateway提出了與服務發現組件集成的要求:通過服務發現組件動態獲取服務實例的訪問列表,進而實現動態負載均衡[25]。
Tyk Gateway內置了主流服務發現組件(比如Etcd、Consul、ZooKeeper等)的對接能力,鑒于環境所限,這里就不舉例了,大家可以在Tyk Gateway的服務發現示例文檔頁面[26]找到與不同服務發現組件對接時的配置示例。
3.3.5 IP訪問限制
針對每個API,API網關還提供IP訪問限制的特性,比如Tyk Gateway就提供了IP白名單[27]和IP黑名單[28]功能,通常二選一開啟一種限制即可。
以白名單為例,即凡是在白名單中的IP才被允許訪問該API。下面是白名單配置樣例:
// /opt/tyk-gateway/apps/no-authn-v1.json
"enable_ip_whitelisting": true,
"allowed_ips": ["12.12.12.12", "12.12.12.13", "12.12.12.14"],
生效后,當我們訪問no-authn API時,會得到下面錯誤:
$curl localhost:8080/api/v1/no-authn
{
"error": "access from this IP has been disallowed"
}
如果開啟的是黑名單,那么凡是在黑名單中的IP都被禁止訪問該API,下面是黑名單配置樣例:
// /opt/tyk-gateway/apps/no-authn-v1.json
"enable_ip_blacklisting": true,
"blacklisted_ips": ["12.12.12.12", "12.12.12.13", "12.12.12.14", "127.0.0.1"],
生效后,當我們訪問no-authn API時,會得到如下結果:
$curl 127.0.0.1:8080/api/v1/no-authn
{
"error": "access from this IP has been disallowed"
}
到目前為止,我們的API網關和定義的API都處于“裸奔”狀態,因為沒有對客戶端進行身份認證,任何客戶端都可以訪問到我們的API,顯然這不是我們期望的,接下來,我們就來看看API網關的一個重要功能特性:身份認證與授權。
3.4 功能特性:身份認證和授權
在《通過實例理解Go Web身份認證的幾種方式[29]》一文中,我們提到過:建立全局的安全通道是任何身份認證方式的前提。
3.4.1 建立安全通道,卸載TLS證書
Tyk Gateway支持在Gateway層面統一配置TLS證書[30],同時也起到在Gateway卸載TLS證書的作用:
圖片
這次我們要在tyk.conf中進行配置,才能在Gateway層面生效。這里我們借用《通過實例理解Go Web身份認證的幾種方式[31]》一文中生成的幾個證書(大家可以在https://github.com/bigwhite/experiments/tree/master/authn-examples/tls-authn/make_certs下載),并將它們放到/opt/tyk-gateway/certs/下面:
$ls /opt/tyk-gateway/certs/
server-cert.pem server-key.pem
然后,我們在/opt/tyk-gateway/tyk.conf文件中增加下面配置:
// /opt/tyk-gateway/tyk.conf
"http_server_options": {
"use_ssl": true,
"certificates": [
{
"domain_name": "server.com",
"cert_file": "./certs/server-cert.pem",
"key_file": "./certs/server-key.pem"
}
]
}
之后,重啟tyk gateway服務,使得tyk.conf的配置修改生效。
注:在/etc/hosts中設置server.com為127.0.0.1。
現在我們用之前的http方式訪問一下no-authn的API:
$curl server.com:8080/api/v1/no-authn
Client sent an HTTP request to an HTTPS server.
由于全局啟用了HTTPS,采用http方式的請求將被拒絕。我們換成https方式訪問:
// 不驗證服務端證書
$curl -k https://server.com:8080/api/v1/no-authn
Welcome api: localhost:18081/v1/no-authn
// 驗證服務端的自簽證書
$curl --cacert ./inter-cert.pem https://server.com:8080/api/v1/no-authn
Welcome api: localhost:18081/v1/no-authn
3.4.2 Mutual TLS雙向認證
在《通過實例理解Go Web身份認證的幾種方式[32]》一文中,我們介紹的第一種身份認證方式就是TLS雙向認證,那么Tyk Gateway對MTLS的支持如何呢?Tyk官方文檔[33]提到它既支持client mTLS[34],也支持upstream mTLS[35]。
我們更關心的是client mTLS,即客戶端在與Gateway建連后,Gateway會使用Client CA驗證客戶端的證書!我最初認為這個Client CA的配置是在tyk.conf中,但找了許久,也沒有發現配置Client CA的地方。
在no-authn API的定義文件(no-authn-v1.json)中,我們做如下配置改動:
"use_mutual_tls_auth": true,
"client_certificates": [
"/opt/tyk-gateway/certs/inter-cert.pem"
],
但使用下面命令訪問API時報錯:
$curl --key ./client-key.pem --cert ./client-cert.pem --cacert ./inter-cert.pem https://server.com:8080/api/v1/no-authn
{
"error": "Certificate with SHA256 bc8717c0f2ea5a0b81813abb3ec42ef8f9bf60da251b87243627d65fb0e3887b not allowed"
}
如果將"client_certificates"的配置中的inter-cert.pem改為client-cert.pem,則是可以的,但個人感覺這很奇怪,不符合邏輯,將tyk gateway的文檔、issue甚至代碼翻了又翻,也沒找到合理的配置client CA的位置。
Tyk Gateway支持多種身份認證方式[36],下面我們來看一種使用較為廣泛的方式:JWT Auth。
主要JWT身份認證方式的原理和詳情,可以參考我之前的文章《通過實例理解Go Web身份認證的幾種方式[37]》。
3.4.3 JWT Token Auth
下面是我為這個示例做的一個示意圖:
圖片
這是我們日常開發中經常遇到的場景,即通過portal用用戶名和密碼登錄后便可以拿到一個jwt token,然后后續的訪問功能API的請求僅攜帶該jwt token即可。API Gateway對于portal/login API不做任何身份認證;而對后續的功能API請求,通過共享的secret(也稱為static secret)對請求中攜帶的jwt token進行簽名驗證。
portal/login API由于不進行authn,這樣其配置與前面的no-authn API幾乎一致,只是API名稱、路徑和target_list有不同:
// apps/portal-login-v1.json
{
"name": "portal-login-v1",
"slug": "portal-login-v1",
"listen_port": 0,
"protocol": "",
"enable_proxy_protocol": false,
"api_id": "portal-login-v1",
"org_id": "1",
"use_keyless": true,
... ...
"proxy": {
"preserve_host_header": false,
"listen_path": "/api/v1/portal/login",
"target_url": "",
"disable_strip_slash": false,
"strip_listen_path": true,
"enable_load_balancing": true,
"target_list": [
"http://localhost:28084"
],
"check_host_against_uptime_tests": true,
... ...
}
對應的portal login API也不復雜:
// api-gateway-examples/portal-login/main.go
package main
import (
"log"
"net/http"
"time"
"github.com/golang-jwt/jwt/v5"
)
func main() {
// 創建一個基本的HTTP服務器
mux := http.NewServeMux()
username := "admin"
password := "123456"
key := "iamtonybai"
// for uptime test
mux.HandleFunc("/health", func(w http.ResponseWriter, req *http.Request) {
w.WriteHeader(http.StatusOK)
})
// login handler
mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
// 從請求頭中獲取Basic Auth認證信息
user, pass, ok := req.BasicAuth()
if !ok {
// 認證失敗
w.WriteHeader(http.StatusUnauthorized)
return
}
// 驗證用戶名密碼
if user == username && pass == password {
// 認證成功,生成token
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
"username": username,
"iat": jwt.NewNumericDate(time.Now()),
})
signedToken, _ := token.SignedString([]byte(key))
w.Write([]byte(signedToken))
} else {
// 認證失敗
http.Error(w, "Invalid username or password", http.StatusUnauthorized)
}
})
// 監聽28084端口
err := http.ListenAndServe(":28084", mux)
if err != nil {
log.Fatal(err)
}
}
運行該login API服務后,我們用curl命令獲取一下jwt token:
$curl -u 'admin:123456' -k https://server.com:8080/api/v1/portal/login
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE3MDA3NTEyODEsInVzZXJuYW1lIjoiYWRtaW4ifQ.-wC8uPsLHDxSXcEMxIxJ8O2l3aWtWtWKvhtmuHmgIMA
現在我們再來建立protected API:
// apps/protected-v1.json
{
"name": "protected-v1",
"slug": "protected-v1",
"listen_port": 0,
"protocol": "",
"enable_proxy_protocol": false,
"api_id": "protected-v1",
"org_id": "1",
"use_keyless": false, // 設置為false, gateway才會進行jwt的驗證
... ...
"enable_jwt": true, // 開啟jwt
"use_standard_auth": false,
"use_go_plugin_auth": false,
"enable_coprocess_auth": false,
"custom_plugin_auth_enabled": false,
"jwt_signing_method": "hmac", // 設置alg為hs256
"jwt_source": "aWFtdG9ueWJhaQ==", // 設置共享secret: base64("iamtonybai")
"jwt_identity_base_field": "username", // 設置代表請求中的用戶身份的字段,這里我們用username
"jwt_client_base_field": "",
"jwt_policy_field_name": "",
"jwt_default_policies": [
"5e189590801287e42a6cf5ce" // 設置security policy,這個似乎是jwt auth必須的
],
"jwt_issued_at_validation_skew": 0,
"jwt_expires_at_validation_skew": 0,
"jwt_not_before_validation_skew": 0,
"jwt_skip_kid": false,
... ...
"version_data": {
"not_versioned": true,
"default_version": "",
"versions": {
"Default": {
"name": "Default",
"expires": "",
"paths": {
"ignored": null,
"white_list": null,
"black_list": null
},
"use_extended_paths": true,
"extended_paths": {
"persist_graphql": null
},
"global_headers": {
"username": "$tyk_context.jwt_claims_username" // 設置轉發到upstream的請求中的header字段username
},
"global_headers_remove": null,
"global_response_headers": null,
"global_response_headers_remove": null,
"ignore_endpoint_case": false,
"global_size_limit": 0,
"override_target": ""
}
}
},
... ...
"enable_context_vars": true, // 開啟上下文變量
"config_data": null,
"config_data_disabled": false,
"tag_headers": ["username"], // 設置header
... ...
}
這個配置就相對復雜許多,也是翻閱了很長時間資料才驗證通過的配置。JWT Auth必須有關聯的policy設置,我們在tyk gateway開源版中要想設置policy,需要現在tyk.conf中做如下設置:
// /opt/tyk-gateway/tyk.conf
"policies": {
"policy_source": "file",
"policy_record_name": "./policies/policies.json"
},
而policies/policies.json的內容如下:
// /opt/tyk-gateway/policies/policies.json
{
"5e189590801287e42a6cf5ce": {
"rate": 1000,
"per": 1,
"quota_max": 100,
"quota_renewal_rate": 60,
"access_rights": {
"protected-v1": {
"api_name": "protected-v1",
"api_id": "protected-v1",
"versions": [
"Default"
]
}
},
"org_id": "1",
"hmac_enabled": false
}
}
上述設置完畢并重啟tyk gateway生效后,且protected api服務也已經啟動時,我們訪問一下該API服務:
$curl -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE3MDA3NTEyODEsInVzZXJuYW1lIjoiYWRtaW4ifQ.-wC8uPsLHDxSXcEMxIxJ8O2l3aWtWtWKvhtmuHmgIMA" -k https://server.com:8080/api/v1/protected
invoke protected api ok
我們看到curl發出的請求成功通過了Gateway的驗證!并且通過protected API輸出的請求信息來看,Gateway成功解析出username,并將其作為Header中的字段傳遞給了protected API服務實例:
http.Request{Method:"GET", URL:(*url.URL)(0xc0002f6240), Proto:"HTTP/1.1", ProtoMajor:1, ProtoMinor:1, Header:http.Header{"Accept":[]string{"*/*"}, "Accept-Encoding":[]string{"gzip"}, "Authorization":[]string{"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE3MDA3NTEyODEsInVzZXJuYW1lIjoiYWRtaW4ifQ.-wC8uPsLHDxSXcEMxIxJ8O2l3aWtWtWKvhtmuHmgIMA"}, "User-Agent":[]string{"curl/7.29.0"}, "Username":[]string{"admin"}, "X-Forwarded-For":[]string{"127.0.0.1"}}, Body:http.noBody{}, GetBody:(func() (io.ReadCloser, error))(nil), ContentLength:0, TransferEncoding:[]string(nil), Close:false, Host:"localhost:28085", Form:url.Values(nil), PostForm:url.Values(nil), MultipartForm:(*multipart.Form)(nil), Trailer:http.Header(nil), RemoteAddr:"[::1]:55583", RequestURI:"/", TLS:(*tls.ConnectionState)(nil), Cancel:(<-chan struct {})(nil), Response:(*http.Response)(nil), ctx:(*context.cancelCtx)(0xc0002e34f0)}
如果不攜帶Authorization頭字段或jwt的token是錯誤的,那么結果將如下所示:
$ curl -k https://server.com:8080/api/v1/protected
{
"error": "Authorization field missing"
}
$ curl -k -H "Authorization: Bearer xxx" https://server.com:8080/api/v1/protected
{
"error": "Key not authorized"
}
一旦通過API Gateway的身份認證,上游的API服務就會拿到客戶端身份,有了唯一身份后,就可以進行授權操作[38]了,其實policy設置本身也是一種授權訪問控制。Tyk Gateway自身也支持RBAC等模型[39],也支持與OPA(open policy agent)等的集成,但更多是在商業版的tyk dashboard下完成的,這里也就不重點說明了。
下面的Gateway的幾個主要功能特性由于試驗環境受限以及文章篇幅考量,我不會像上述例子這么細致的說明了,只會簡單說明一下。
3.5 功能特性:流量控制與限速
Tyk Gateway內置提供了強大的流量控制功能,可以通過全局級別和API級別的限速[40]來管理請求流量。此外,Tyk Gateway 還支持請求配額(request quota)[41]來限制每個用戶或應用程序在一個時間周期內的請求次數。
流量不僅和請求速度和數量有關系,與請求的大小也有關系,Tyk Gateway還支持在全局層面和API層面設置Request的size limit[42],以避免超大包對網關運行造成不良影響。
3.6 功能特性:高可用與容錯處理
在許多情況下,我們要為客戶確保服務水平(service level),比如:最大往返時間、最大響應時延等。Tyk Gateway提供了一系列功能,可幫助我們確保網關的高可用運行和SLA服務水平。
Tyk支持健康檢查[43],這對于確定Tyk Gateway的狀態極為重要,沒有健康檢查,就很難知道網關的實際運行狀態如何。
Tyk Gateway還內置了斷路器(circuit breaker)[44],這個斷路器是基于比例的,因此如果y個請求中的x請求都失敗了,斷路器就會跳閘,例如,如果x = 10,y = 100,則閾值百分比為10%。當失敗比例到達10%時,斷路器就會切斷流量,同時跳閘還會觸發一個事件,我們可以記錄和處理該事件。
當upstream的服務響應遲遲不歸時,Tyk Gateway還可以設置強制超時[45],可以確保服務始終在給定時間內響應。這在高可用性系統中非常重要,因為在這種系統中,響應性能至關重要,這樣才能干凈利落地處理錯誤。
3.7 功能特性:監控與可觀測性
微服務時代,可觀測性對運維以及系統高可用的重要性不言而喻。Tyk Gateway在多年的演化過程中,也逐漸增加了對可觀測的支持,
可觀測主要分三大塊:
- log
Tyk Gateway支持設置輸出日志的級別(log level),默認是info級別。Tyk輸出的是結構化日志,這使得它可以很好的與其他日志收集查詢系統集成,Tyk支持與主流的日志收集工具對接[46],包括:logstash、sentry、Graylog、Syslog等。
- metrics
度量數據是反映網關系統健康狀況、錯誤計數和類型、IT基礎設施(服務器、虛擬機、容器、數據庫和其他后端組件)及其他流程的硬件資源數據的重要參考。運維團隊可以通過使用監控工具來利用實時度量的數據[47],識別運行趨勢、在系統故障時設置警報、確定問題的根本原因并緩解問題。
Tyk Gateway內置了對主流metrics采集方案Prometheus+Grafana的支持[48],可以在網關層面以及對API進行實時度量數據采集和展示。
- tracing
Tyk Gateway從5.2版本開始支持了與服務Tracing界的標準:OpenTelemetry的集成[49],這樣你可以使用多種支持OpenTelemetry的Tracing后端,比如Jaeger、Datadog等。Tracing可在Gateway層面開啟,也可以延展到API層面。
4. 小結
本文對已經相對成熟的API網關技術做了回顧,對API網關的演進階段、主流特性以及當前市面上的主流API網關進行了簡要說明,并以Go實現的Tyk Gateway社區開源版為例,以示例方式對API網關的主要功能做了介紹。
總體而言,Tyk Gateway是一款功能強大,社區相對活躍并有商業公司支持的產品,文檔很豐富,但從實際使用層面,這些文檔對Tyk社區版本的使用者來說并不友好,指導性不足(更多用商業版的Dashboard說明,與配置文件難于對應),就像本文例子中那樣,為了搞定JWT認證,筆者著實花了不少時間查閱資料,甚至閱讀源碼。
Tyk Gateway的配置設計平坦,沒有層次和邏輯,感覺是隨著時間隨意“堆砌”上去的。并且配置文件更新時,如果出現格式問題,Tyk Gateway并不報錯,讓人難于確定配置是否真正生效了,只能用Tyk Gateway的控制API[50]去查詢結果來驗證,非常繁瑣低效。
本文涉及的源碼可以在這里[51]下載,文中涉及的一些tyk gateway api和security policy的配置也可以在其中查看。
5. 參考資料
- Leaving the Cloud[52] - https://37signals.com/podcast/leaving-the-cloud/
- The Past, Present, and Future of API Gateways[53] - https://www.infoq.com/articles/past-present-future-api-gateways/
- How moving from AWS to Bare-Metal saved us 230,000/yr[54] - https://blog.oneuptime.com/moving-from-aws-to-bare-metal/
- A Comprehensive Guide to API Gateways, Kubernetes Gateways, and Service Meshes[55] - https://navendu.me/posts/gateway-and-mesh/
- Use API gateways in microservices[56] - https://learn.microsoft.com/en-us/azure/architecture/microservices/design/gateway
- The Tyk API Gateway and Postman[57] - https://blog.postman.com/the-tyk-api-gateway-and-postman/
- Getting Started with Tyk API Gateway with Keycloak[58] - https://javascript.plainenglish.io/getting-started-to-tyk-api-gateway-with-keycloak-16307435584a
- Observing your API traffic with Tyk, Elasticsearch & Kibana[59] - https://medium.com/@asoorm/observing-your-api-metrics-with-tyk-elasticsearch-kibana-74e8fd946c39
- Set up JWT token in tyk gateway[60] - https://community.tyk.io/t/set-up-jwt-token-in-tyk-gateway/6572/9
參考資料
[1] David Heinemeier Hansson: https://dhh.dk/
[2] 將公司所有的業務都從公有云搬遷到了自建的數據中心: https://37signals.com/podcast/leaving-the-cloud/
[3] 以單體應用的形式存在: https://tonybai.com/2023/10/09/service-weaver-coding-in-monolithic-deploy-in-microservices/
[4] CNCF Landscape: https://https://landscape.cncf.io
[5] Amazon的API Gateway: https://aws.amazon.com/cn/api-gateway/
[6] Google Cloud的API Gateway: https://cloud.google.com/api-gateway
[7] APISIX: https://apisix.apache.org/
[8] Kong: https://konghq.com/
[9] EMISSARY INGRESS: https://github.com/emissary-ingress/emissary
[10] Tyk API網關: https://tyk.io/blog/res-api-management-vendor-comparisons/
[11] 不代表Tyk API網關就要比其他Go實現的API Gateway優秀: https://tyk.io/blog/enter-the-leader-tyk-recognised-as-a-leader-in-gartners-2023-magic-quadrant-for-api-management/
[12] Tyk API網關: https://github.com/TykTechnologies/tyk
[13] Open Core模式開源: https://opensource.com/article/21/11/open-core-vs-open-source
[14] 開源兼商業API管理和網關解決方案: https://tyk.io/docs/tyk-oss-gateway/
[15] docker-compose: https://tonybai.com/2021/11/26/build-all-in-one-runtime-environment-with-docker-compose
[16] Kubernetes Operator: https://tonybai.com/2022/08/15/developing-kubernetes-operators-in-go-part1
[17] Tyk API網關開源版本的功能詳情: https://tyk.io/docs/tyk-oss-gateway/
[18] 使用CentOS的yum包管理工具安裝Tyk API網關: https://tyk.io/docs/tyk-oss/ce-redhat-rhel-centos/
[19] systemd daemon服務: https://tonybai.com/2016/12/27/when-docker-meets-systemd/
[20] 調用Tyk的控制類API: https://tyk.io/docs/getting-started/create-api/#tutorial-create-an-api-with-the-tyk-gateway-api
[21] 通過傳統的配置文件,放入特定目錄下: https://tyk.io/docs/getting-started/create-api/#tutorial-create-an-api-in-file-based-mode
[22] API的定義文件: https://tyk.io/docs/tyk-gateway-api/api-definition-objects/
[23] 請求流量負載均衡: https://tyk.io/docs/planning-for-production/ensure-high-availability/load-balancing/
[24] 支持配置帶權重的RR負載均衡算法: https://tyk.io/docs/planning-for-production/ensure-high-availability/load-balancing/
[25] 動態負載均衡: https://tyk.io/docs/planning-for-production/ensure-high-availability/service-discovery/
[26] 服務發現示例文檔頁面: https://tyk.io/docs/planning-for-production/ensure-high-availability/service-discovery/examples/
[27] IP白名單: https://tyk.io/docs/tyk-apis/tyk-gateway-api/api-definition-objects/ip-whitelisting/
[28] IP黑名單: https://tyk.io/docs/tyk-apis/tyk-gateway-api/api-definition-objects/ip-blacklisting/
[29] 通過實例理解Go Web身份認證的幾種方式: https://tonybai.com/2023/10/23/understand-go-web-authn-by-example
[30] 統一配置TLS證書: https://tyk.io/docs/basic-config-and-security/security/tls-and-ssl/
[31] 通過實例理解Go Web身份認證的幾種方式: https://tonybai.com/2023/10/23/understand-go-web-authn-by-example/
[32] 通過實例理解Go Web身份認證的幾種方式: https://tonybai.com/2023/10/23/understand-go-web-authn-by-example
[33] Tyk官方文檔: https://tyk.io/docs/basic-config-and-security/security/mutual-tls/
[34] client mTLS: https://tyk.io/docs/basic-config-and-security/security/mutual-tls/client-mtls
[35] upstream mTLS: https://tyk.io/docs/basic-config-and-security/security/mutual-tls/upstream-mtls
[36] Tyk Gateway支持多種身份認證方式: https://tyk.io/docs/apim-best-practice/api-security-best-practice/authentication/
[37] 通過實例理解Go Web身份認證的幾種方式: https://tonybai.com/2023/10/23/understand-go-web-authn-by-example/
[38] 授權操作: https://tonybai.com/2023/11/04/understand-go-web-authz-by-example/
[39] 支持RBAC等模型: https://tyk.io/docs/tyk-dashboard/rbac/#understanding-the-concept-of-users-and-permissions
[40] 全局級別和API級別的限速: https://tyk.io/docs/basic-config-and-security/control-limit-traffic/rate-limiting/
[41] 支持請求配額(request quota): https://tyk.io/docs/basic-config-and-security/control-limit-traffic/request-quotas/
[42] 設置Request的size limit: https://tyk.io/docs/basic-config-and-security/control-limit-traffic/request-size-limits/
[43] Tyk支持健康檢查: https://tyk.io/docs/planning-for-production/ensure-high-availability/health-check/
[44] 內置了斷路器(circuit breaker): https://tyk.io/docs/planning-for-production/ensure-high-availability/circuit-breakers/
[45] 設置強制超時: https://tyk.io/docs/planning-for-production/ensure-high-availability/enforced-timeouts/
[46] Tyk支持與主流的日志收集工具對接: https://tyk.io/docs/log-data/#logging
[47] 使用監控工具來利用實時度量的數據: https://tyk.io/docs/planning-for-production/monitoring/
[48] 對主流metrics采集方案Prometheus+Grafana的支持: https://tyk.io/blog/service-level-objectives-for-your-apis-with-tyk-prometheus-and-grafana/
[49] 支持了與服務Tracing界的標準:OpenTelemetry的集成: https://tyk.io/docs/product-stack/tyk-gateway/advanced-configurations/distributed-tracing/open-telemetry/open-telemetry-overview/
[50] Tyk Gateway的控制API: https://tyk.io/docs/tyk-gateway-api/
[51] 這里: https://github.com/bigwhite/experiments/tree/master/api-gateway-examples
[52] Leaving the Cloud: https://37signals.com/podcast/leaving-the-cloud/
[53] The Past, Present, and Future of API Gateways: https://www.infoq.com/articles/past-present-future-api-gateways/
[54] How moving from AWS to Bare-Metal saved us 230,000/yr: https://blog.oneuptime.com/moving-from-aws-to-bare-metal/
[55] A Comprehensive Guide to API Gateways, Kubernetes Gateways, and Service Meshes: https://navendu.me/posts/gateway-and-mesh/
[56] Use API gateways in microservices: https://learn.microsoft.com/en-us/azure/architecture/microservices/design/gateway
[57] The Tyk API Gateway and Postman: https://blog.postman.com/the-tyk-api-gateway-and-postman/
[58] Getting Started with Tyk API Gateway with Keycloak: https://javascript.plainenglish.io/getting-started-to-tyk-api-gateway-with-keycloak-16307435584a
[59] Observing your API traffic with Tyk, Elasticsearch & Kibana: https://medium.com/@asoorm/observing-your-api-metrics-with-tyk-elasticsearch-kibana-74e8fd946c39
[60] Set up JWT token in tyk gateway: https://community.tyk.io/t/set-up-jwt-token-in-tyk-gateway/6572/9
[61] “Gopher部落”知識星球: https://public.zsxq.com/groups/51284458844544
[62] 鏈接地址: https://m.do.co/c/bff6eed92687