Kong GatewayのAdmin APIはKong GatewayをAPIで操作することが出来る強力な機能であるが、強力が故に保護したいと考えることもあると思う。
前段にWAF/LBを置いて保護することも出来るが、設定次第ではKong Gateway自身でAdmin APIを保護することも出来る。
ここではそのやり方を紹介する。
仕組み
まず基礎知識としてKong Gatewayで提供されるProxy機能とAdmin API機能は同一のバイナリで提供され、待受ポートによって役割を変えている。
また、Admin APIはどのIPで待ち受けるかはkong.confのadmin_listen
で指定する。
これを組み合わせると以下のような感じでProxy経由の通信のみ受け付け、その他の呼び出しは受け付けないようにすることが出来る。
更にはProxy経由なので、PluginなどのKong Gatewayの機能も付与することが出来る。
これによってAdmin APIに認証を追加したり、レート制限を掛けたり、様々な設定を追加することが可能となる。
検証
ここではdockerを使って起動し、動作確認してみる。
以下の手順でKong Gatewayを立ち上げる。
- DockerのNetworkを作成
- Postgresの起動
- DBの初期化
- Admin APIのためのService/Route設定をDBに書き込み
- Kong Gatewayを起動
Kong Gatewayの起動前にService/Route設定をDBに書き込んでいるのは、起動したタイミングで既にAdmin API用のServiceとRouteがないとAPIを叩こうにも叩きようがなくなるためである。
PostgresとKong Gatewayが接続できるようNetworkを作成する。
docker network create kong-net
Postgresを起動する。
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:16
利用するKongのバージョンを環境変数に設定後、DBを初期化する。
VERSION=3.9.0.0
docker run --rm --network=kong-net \
-e "KONG_DATABASE=postgres" \
-e "KONG_PG_HOST=kong-database" \
-e "KONG_PG_PASSWORD=kongpass" \
kong/kong-gateway:$VERSION kong migrations bootstrap
次にAdmin APIのService/Routeを定義する。
DB lessモードで起動する時に使うフォーマットで定義ファイルを作成する。
cat <<EOF > ./admin-api.yaml
_format_version: "3.0"
_transform: true
services:
- name: admin-api-service
url: http://localhost:8001
routes:
- name: admin-api-route
paths:
- /admin-api
EOF
ここでは以下の仕様とした。
- Service:
- ホスト:
http://localhost:8001
- ホスト:
- Routes:
- パス:
/admin-api
- パス:
これにより、Proxyの/admin-api
にアクセスするとAdmin APIが利用できるようになる。
作成したYAMLを使ってDBに設定を反映する。
これにはkong config db_import
コマンドを使う。
docker run --rm --network=kong-net \
-v ./admin-api.yaml:/tmp/admin-api.yaml \
-e "KONG_DATABASE=postgres" \
-e "KONG_PG_HOST=kong-database" \
-e "KONG_PG_PASSWORD=kongpass" \
kong/kong-gateway:$VERSION kong config db_import /tmp/admin-api.yaml
なお、KongのService/Route設定を読ますのにdeclarative_configが使えそうと思ってしまうが、これはdatabase=offを指定した時のみ動作し、今回はDBありで検証しているため利用できない。
設定を反映したらKong Gatewayを起動する。
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_ADMIN_LISTEN=localhost:8001" \
-p 8000:8000 \
-p 8001:8001 \
kong/kong-gateway:$VERSION
KONG_ADMIN_LISTEN=localhost:8001
を指定し、Admin APIのアクセス元を同一コンテナ内からのアクセスに限定している。
なお、ポート8001はProxy経由で使うので公開する必要はないが、外部からアクセスできないことを検証するために空けている。
以上で起動手順は終了となる。
確認
dockerの仕組みの話なので説明は割愛するが、dockerでポートをマッピングしてlocalhostにアクセスした時、ネットワークをブリッジしてアクセスするためコンテナ側から見るとlocalhostにはならない。
そのためlocalhost:8001
にアクセスしてもadmin_listen
で指定したアドレスと一致せずAdmin APIにはアクセスできない。
$ curl localhost:8001
curl: (52) Empty reply from server
Proxy経由でアクセスしてみる。
$ curl localhost:8000/admin-api
{"plugins":{"enabled_in_cluster":[],"available_on_server":{"redirect":true,"standard-webhooks":true,"ai-response-transformer":true,"ai-request-transformer":true,"ai-prompt-guard":true,
:(省略)
Proxy経由でのみアクセスできた。
追加で、Admin APIにレート制限を掛けてみる。
ADMIN_API=http://localhost:8000/admin-api
curl -X POST $ADMIN_API/services/admin-api-service/plugins \
--data "name=rate-limiting" \
--data "config.minute=3"
config.minute=3
を指定し、1分間のアクセスの上限を3回まで
この状態でAdmin APIにcurlで5回連続でアクセスし、-wオプションを使ってステータスコードだけ表示する。
for((i=0;i<5;i++)); do curl -o /dev/null -s -w "%{http_code}\n" localhost:8000/admin-api; done
結果は以下となった。
200
200
200
429
429
4回目以降は429となってアクセスが禁止され、Admin APIにレート制限によって保護されたことが確認できた。
以上よりAdmin APIをKong Gatewayを使って保護できることが確認できた。