2023.01.13

Kong で実装するアクセス制御とロードバランサー

こんにちは。次世代システム研究室のK.X.D です。

1.はじめに

近年にAPI活用システムが増えていきます。サービス運用に応じて、複数APIシステムを使われることもあります。
各APIシステム管理が困難であり、認証(認可)、レート制御、システムログ収集などの共通処理が集中的に実装されるニーズがありますので、Proxy機能に加えて、APIシステムを簡単に管理できる機能を提供するAPI Gatewayが生まれてます。
今回に市場で上がってるKongのAPI Gatewayを理解するように調べてます。
公式ページはこちらになります。
https://jp.konghq.com/

2.API Gatewayとは

全てサービスのリソースサーバの入り口として役割にしています。
どんなリソースリクエストでも、API Gateway経由にしてリソースアクセスする仕組みです。


※公式Microsoftページより

3.Kongをインストールし、API Gatewayを機能してみる

3-1.Kongをインストール

Kongの公式ドキュメントにインストール方法が書いてあり、こちらを参考にしました。
https://docs.konghq.com/gateway/latest/install/docker/

① Dockerのnetworkを作成する。
docker network create kong-net
② KongのDB Containerを起動する。
 docker run -d --name kong-database \
  --network=kong-net \
  -p 5432:5432 \
  -e "POSTGRES_USER=kong" \
  -e "POSTGRES_DB=kong" \
  -e "POSTGRES_PASSWORD=kongpass" \
  postgres:9.6
③ DBとKongの連携(マイグレーション)
docker run --rm --network=kong-net \
  -e "KONG_DATABASE=postgres" \
  -e "KONG_PG_HOST=kong-database" \
  -e "KONG_PG_PASSWORD=kongpass" \
  -e "KONG_PASSWORD=test" \
 kong/kong-gateway:3.1.1.1 kong migrations bootstrap
④ Kongを起動する
docker run -d --name kong-gateway \
  --network=kong-net \
  -e "KONG_DATABASE=postgres" \
  -e "KONG_PG_HOST=kong-database" \
  -e "KONG_PG_USER=kong" \
  -e "KONG_PG_PASSWORD=kongpass" \
  -e "KONG_PROXY_ACCESS_LOG=/dev/stdout" \
  -e "KONG_ADMIN_ACCESS_LOG=/dev/stdout" \
  -e "KONG_PROXY_ERROR_LOG=/dev/stderr" \
  -e "KONG_ADMIN_ERROR_LOG=/dev/stderr" \
  -e "KONG_ADMIN_LISTEN=0.0.0.0:8001" \
  -e "KONG_ADMIN_GUI_URL=http://localhost:8002" \
  -e KONG_LICENSE_DATA \
  -p 8000:8000 \
  -p 8443:8443 \
  -p 8001:8001 \
  -p 8444:8444 \
  -p 8002:8002 \
  -p 8445:8445 \
  -p 8003:8003 \
  -p 8004:8004 \
  kong/kong-gateway:3.1.1.1

3-2.今回用意したLocal環境 Kong の基本構成

Local環境にインストールしたKong仕組み:
8001ポート:KongのService、Route、Upstream、Pluginなど設定を対応するAdmin APIです。
8002ポート:KongのService、Route、Upstream、Pluginなど設定を対応するDashboardGUIです。
8000ポート:Proxyポート、各APIシステムに繋がってます。

3-3 検証1 KongでMockサービスを作り、JWT認証+ACLアクセス制御を実装する

① Mock の Service を作成する
mockbinmockapiを利用して、仮Upstreamサービスにしています。
curl -i -s -X POST http://localhost:8001/services \
--data name=‘mockbin_service’ \
--data url=‘https://mockbin.org’

HTTP/1.1 201 Created
Date: Thu, 12 Jan 2023 13:24:05 GMT
Content-Type: application/json; charset=utf-8
Connection: keep-alive
Access-Control-Allow-Origin: http://localhost:8002
X-Kong-Admin-Request-ID: ZOsN43v8Z0vShD9r6cFTLP7C3r0jaXhV
vary: Origin
Access-Control-Allow-Credentials: true
Content-Length: 365
X-Kong-Admin-Latency: 15
Server: kong/3.1.1.1-enterprise-edition{“client_certificate”:null,“tls_verify_depth”:null,“created_at”:1673529845,“connect_timeout”:60000,“read_timeout”:60000,“tags”:null,“path”:null,“updated_at”:1673529845,“enabled”:true,“ca_certificates”:null,“retries”:5,“protocol”:“https”,“name”:null,“write_timeout”:60000,“host”:“mockbin.org”,“id”:“c4e6a057-6db2-4ac5-ae19-4d039620ca39”,“port”:443,“tls_verify”:null}
curl -i -s -X POST http://localhost:8001/services \ --data name=‘mockapi_service’ \
--data url=‘https://63c00608e262345656f5c231.mockapi.io’

HTTP/1.1 201 Created
Date: Thu, 12 Jan 2023 13:24:46 GMT
Content-Type: application/json; charset=utf-8
Connection: keep-alive
Access-Control-Allow-Origin: http://localhost:8002
X-Kong-Admin-Request-ID: dBAvTyyXXPEiAQ7T7qOX5E3eaNvrY8WG
vary: Origin
Access-Control-Allow-Credentials: true
Content-Length: 389
X-Kong-Admin-Latency: 12
Server: kong/3.1.1.1-enterprise-edition{“client_certificate”:null,“tls_verify_depth”:null,“created_at”:1673529886,“connect_timeout”:60000,“read_timeout”:60000,“tags”:null,“path”:null,“updated_at”:1673529886,“enabled”:true,“ca_certificates”:null,“retries”:5,“protocol”:“https”,“name”:null,“write_timeout”:60000,
“host”:“63c00608e262345656f5c231.mockapi.io”,“id”:“2b216be2-b4ef-428a-af28-f50e91ca4dc3",“port”:443,“tls_verify”:null}

※https://63c00608e262345656f5c231.mockapi.io:閲覧時点に、無効になる可能性があります。
② ServiceのRouteを作成する。
curl -i -X POST http://localhost:8001/services/c4e6a057-6db2-4ac5-ae19-4d039620ca39/routes \
--data ‘paths[]=/mockbin’ \
--data name=mockbin_route


HTTP/1.1 201 Created
Date: Thu, 12 Jan 2023 13:31:17 GMT
Content-Type: application/json; charset=utf-8
Connection: keep-alive
Access-Control-Allow-Origin: http://localhost:8002
X-Kong-Admin-Request-ID: z3MXxjQGnMJRTqpUFryiqHzvWIMDEUSw
vary: Origin
Access-Control-Allow-Credentials: true
Content-Length: 488
X-Kong-Admin-Latency: 18
Server: kong/3.1.1.1-enterprise-edition

{"headers":null,"request_buffering":true,"response_buffering":true,"hosts":null,"created_at":1673530277,"paths":["/mockbin"],"https_redirect_status_code":426,"preserve_host":false,"name":"mockbin_route","id":"3f66bbf8-540c-45ea-a332-93546e4d3f8a","methods":null,"service":{"id":"c4e6a057-6db2-4ac5-ae19-4d039620ca39"},"regex_priority":0,"tags":null,"path_handling":"v0","destinations":null,"sources":null,"strip_path":true,"snis":null,"updated_at":1673530277,"protocols":["http","https"]}
curl -i -X POST http://localhost:8001/services/2b216be2-b4ef-428a-af28-f50e91ca4dc3/routes \
 --data ‘paths[]=/mockapi’ \
 --data name=mockapi_route

HTTP/1.1 201 Created
Date: Thu, 12 Jan 2023 13:31:34 GMT
Content-Type: application/json; charset=utf-8
Connection: keep-alive
Access-Control-Allow-Origin: http://localhost:8002
X-Kong-Admin-Request-ID: yOuNIy9TCApXPHkY4okiCGyM8xOhDkca
vary: Origin
Access-Control-Allow-Credentials: true
Content-Length: 488
X-Kong-Admin-Latency: 14
Server: kong/3.1.1.1-enterprise-edition

{"headers":null,"request_buffering":true,"response_buffering":true,"hosts":null,"created_at":1673530294,"paths":["/mockapi"],"https_redirect_status_code":426,"preserve_host":false,"name":"mockapi_route","id":"6e7edddb-3821-406c-9efb-dadcfc7eac9b","methods":null,"service":{"id":"2b216be2-b4ef-428a-af28-f50e91ca4dc3"},"regex_priority":0,"tags":null,"path_handling":"v0","destinations":null,"sources":null,"strip_path":true,"snis":null,"updated_at":1673530294,"protocols":["http","https"]}
動作確認:
mockbinを叩く:
curl -i http://localhost:8000/mockapi/requestcurl -i localhost:8000/mockbin/request
mockapiを叩く:
curl -i http://localhost:8000/mockapi/requestcurl -i localhost:8000/mockapi/request
KongのProxyポート経由でmockbin、mockapiにアクセスする設定ができました。

③ KongのJWTプラグインを利用して、API認証を実装する。
– JWTプラグインをインストールします。
curl -X POST http://localhost:8001/plugins/ \
  --data “name=jwt”

{“config”:{“claims_to_verify”:null,“secret_is_base64":false,“anonymous”:null,“key_claim_name”:“iss”,“header_names”:[“authorization”],“cookie_names”:[],“uri_param_names”:[“jwt”],“run_on_preflight”:true,“maximum_expiration”:0},“protocols”:[“grpc”,“grpcs”,“http”,“https”],“service”:null,“ordering”:null,“created_at”:1673531925,“route”:null,“consumer”:null,“tags”:null,“name”:“jwt”,“id”:“62bf0d08-3863-4406-a980-0d89e1e41823”,“enabled”:true}

– mockbin、mockapiを再度叩くと、JWTトークンが付かないでUnauthrizedエラーが発生する。
curl -i localhost:8000/mockbin/request
curl -i localhost:8000/mockapi/request
– JWTトークンのCredentialを定義するために、KongのConsumerを利用します。
KongのConsumerを作成します。


curl -d "username=mock_user&custom_id=58B68029-A02B-4C90-99C9-647B661329CC" http://localhost:8001/consumers/

{"id":"ab6e3cc5-97e8-4c66-910d-277c5f34f3ec","username_lower":"mock_user","custom_id":"58B68029-A02B-4C90-99C9-647B661329CC","tags":null,"type":0,"created_at":1673532751,"username":"mock_user"}
Consumerに対する、JWTトークンのCredentialを作成します。
curl -X POST http://localhost:8001/consumers/ab6e3cc5-97e8-4c66-910d-277c5f34f3ec/jwt \
-H "Content-Type: application/x-www-form-urlencoded"

{"algorithm":"HS256","created_at":1673532759,"rsa_public_key":null,"secret":"Gg1ESSKPhK52NHqiwmTvWHVKihzMDe7w","tags":null,"id":"7fd35737-58c7-4662-847e-d8e12cdf4d1f","consumer":{"id":"ab6e3cc5-97e8-4c66-910d-277c5f34f3ec"},"key":"nnuCZ8JBSxUPhMu0Al5fhaq3sEC1kwei"
algorithm:HS256
secret:Gg1ESSKPhK52NHqiwmTvWHVKihzMDe7w
key:nnuCZ8JBSxUPhMu0Al5fhaq3sEC1kwei

上記の情報でhttp://jwt.ioに入力して、JWTトークンを生成します。


 

JWTプラグインはAuthorization HeaderのBearerトークンでバリデーションを行いますので、
生成したJWTトークンを付けて、正常にAPをI叩くことができます。
curl http://localhost:8000/mockbin/request \
  -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJubnVDWjhKQlN4VVBoTXUwQWw1ZmhhcTNzRUMxa3dlaSJ9.55ytbIId_G6aqDOo98zF0QHx6ZtDjXWNBcti5JlLAYo'
curl http://localhost:8000/mockapi/request \
  -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJubnVDWjhKQlN4VVBoTXUwQWw1ZmhhcTNzRUMxa3dlaSJ9.55ytbIId_G6aqDOo98zF0QHx6ZtDjXWNBcti5JlLAYo'
④ KongのACLプラグインを利用して、アクセス制限を行う
– mockbin ServiceにACLプラグインをインストールします
curl -X POST http://localhost:8001/services/c4e6a057-6db2-4ac5-ae19-4d039620ca39/plugins \
    --data "name=acl"  \
    --data "config.allow=group1" \
    --data "config.allow=group2" \
    --data "config.hide_groups_header=true"

{“config”:{“allow”:[“group1”,“group2"],“deny”:null,“hide_groups_header”:true},“protocols”:[“grpc”,“grpcs”,“http”,“https”],“service”:{“id”:“c4e6a057-6db2-4ac5-ae19-4d039620ca39"},“ordering”:null,“created_at”:1673536365,“route”:null,“consumer”:null,“tags”:null,“name”:“acl”,“id”:“907acc9f-f009-4a42-838b-06d8506b220a”,“enabled”:true}
– mockbin APIを叩くと、JWTが正しくてもアクセス制限されてます。
curl http://localhost:8000/mockbin/request \
  -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJubnVDWjhKQlN4VVBoTXUwQWw1ZmhhcTNzRUMxa3dlaSJ9.55ytbIId_G6aqDOo98zF0QHx6ZtDjXWNBcti5JlLAYo'
– mockapi APIを叩くと、正しいJWTで正常にアクセスできます。
curl http://localhost:8000/mockbin/request \
-H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJubnVDWjhKQlN4VVBoTXUwQWw1ZmhhcTNzRUMxa3dlaSJ9.55ytbIId_G6aqDOo98zF0QHx6ZtDjXWNBcti5JlLAYo'
同じConsumer(クライアント)で、APIサービスを制限できることを実現しました。

3-4.検証2 KongでLoad-Balancerを実現する


※公式Kongページより
- Upstreamsを作成します。
curl -X POST http://localhost:8001/upstreams \
  --data name=loadbalancer_upstream
{"client_certificate":null,"hash_on_header":null,"slots":10000,"hash_on_query_arg":null,"created_at":1673537823,"hash_on_uri_capture":null,"hash_on_cookie":null,"name":"loadbalancer_upstream","id":"c03e9c73-acae-403f-a526-37b4a3a67eb5","hash_fallback":"none","hash_fallback_header":null,"algorithm":"round-robin","hash_fallback_uri_capture":null,"host_header":null,"hash_on_cookie_path":"/","tags":null,"healthchecks":{"threshold":0,"active":{"timeout":1,"unhealthy":{"tcp_failures":0,"timeouts":0,"http_failures":0,"http_statuses":[429,404,500,501,502,503,504,505],"interval":0},"https_verify_certificate":true,"healthy":{"successes":0,"interval":0,"http_statuses":[200,302]},"type":"http","concurrency":10,"headers":null,"http_path":"/","https_sni":null},"passive":{"type":"http","unhealthy":{"tcp_failures":0,"timeouts":0,"http_failures":0,"http_statuses":[429,500,503]},"healthy":{"http_statuses":[200,201,202,203,204,205,206,207,208,226,300,301,302,303,304,305,306,307,308],"successes":0}}},"use_srv_name":false,"hash_fallback_query_arg":null,"hash_on":"none"}
– Upstreamsに紐づくAPIシステムをtargetsで設定します。
curl -X POST http://localhost:8001/upstreams/loadbalancer_upstream/targets \
  --data target='mockbin.org:80'

{"upstream":{"id":"c03e9c73-acae-403f-a526-37b4a3a67eb5"},"target":"mockbin.org:80","tags":null,"id":"9f61bbb9-18f5-4eb5-8f43-502ba1bfa9b3","created_at":1673537845.361,"weight":100}
curl -X POST http://localhost:8001/upstreams/loadbalancer_upstream/targets \
  --data target='63c00608e262345656f5c231.mockapi.io:80'

{"upstream":{"id":"c03e9c73-acae-403f-a526-37b4a3a67eb5"},"target":"63c00608e262345656f5c231.mockapi.io:80","tags":null,"id":"700b7594-4368-4a2b-ad5b-c1ac5e8f2383","created_at":1673537850.499,"weight":100}
– Upstreamsに紐づくServicesを作成します。
curl -i -s -X POST http://localhost:8001/services \
  --data name=loadbalancer_service \
  --data host='loadbalancer_upstream'

HTTP/1.1 201 Created
Date: Thu, 12 Jan 2023 15:43:21 GMT
Content-Type: application/json; charset=utf-8
Connection: keep-alive
Access-Control-Allow-Origin: http://localhost:8002
X-Kong-Admin-Request-ID: XY4felYFCj2UXgfZASoDTqACM4tsFRHy
vary: Origin
Access-Control-Allow-Credentials: true
Content-Length: 391
X-Kong-Admin-Latency: 14
Server: kong/3.1.1.1-enterprise-edition

{"client_certificate":null,"tls_verify_depth":null,"created_at":1673538201,"connect_timeout":60000,"read_timeout":60000,"tags":null,"path":null,"updated_at":1673538201,"enabled":true,"ca_certificates":null,"retries":5,"protocol":"http","name":"loadbalancer_service","write_timeout":60000,"host":"loadbalancer_upstream","id":"60923d4b-71da-4b42-a4c5-1d75299776e5","port":80,"tls_verify":null
– ServicesのRouteを作成します。
curl -i -X POST http://localhost:8001/services/loadbalancer_service/routes \
  --data 'paths[]=/loadbalancer_route' \
  --data name=loadbalancer_route


HTTP/1.1 201 Created
Date: Thu, 12 Jan 2023 15:44:41 GMT
Content-Type: application/json; charset=utf-8
Connection: keep-alive
Access-Control-Allow-Origin: http://localhost:8002
X-Kong-Admin-Request-ID: u7eZ5xBkGUkdIFn3cwOzYwnR7reBB5nk
vary: Origin
Access-Control-Allow-Credentials: true
Content-Length: 504
X-Kong-Admin-Latency: 16
Server: kong/3.1.1.1-enterprise-edition

{"headers":null,"request_buffering":true,"response_buffering":true,"hosts":null,"created_at":1673538281,"paths":["/loadbalancer_route"],"https_redirect_status_code":426,"preserve_host":false,"name":"loadbalancer_route","id":"23208e8e-d004-4192-94e8-9423a16955ce","methods":null,"service":{"id":"60923d4b-71da-4b42-a4c5-1d75299776e5"},"regex_priority":0,"tags":null,"path_handling":"v0","destinations":null,"sources":null,"strip_path":true,"snis":null,"updated_at":1673538281,"protocols":["http","https"]}
– 動作確認:リクエストは2APIシステムに分散されてます。下記をお試しください。
curl http://localhost:8000/loadbalancer_route/request \
-H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJubnVDWjhKQlN4VVBoTXUwQWw1ZmhhcTNzRUMxa3dlaSJ9.55ytbIId_G6aqDOo98zF0QHx6ZtDjXWNBcti5JlLAYo'
Kongがround-robin、lease-connections、consistent-hashingの分散Algoをサーポトしています。

4.まとめ

KongのApi Gatewayを概要的に紹介させていただきました。
Service、Route、Upstream、Pluginの基本リソースとして、豊富なApi Gateway的な機能が実現できます。
特にPluginは要件に応じて、柔軟で独自の物が開発できますが、
短い記事で全て機能紹介できませんですので、ご参考までいただければと思います。


最後に

次世代システム研究室では、グループ全体のインテグレーションを支援してくれるアーキテクトを募集しています。インフラ設計、構築経験者の方、次世代システム研究室にご興味を持って頂ける方がいらっしゃいましたら、ぜひ募集職種一覧からご応募をお願いします。

  • Twitter
  • Facebook
  • はてなブックマークに追加

グループ研究開発本部の最新情報をTwitterで配信中です。ぜひフォローください。

 
  • AI研究開発室
  • 大阪研究開発グループ

関連記事