Kongで WebAPIゲートウェイを作ります。
こんにちは。
「Kongインストール(前編)」でインストールを、
「Kongインストール(中編)」で、リバースプロキシとしての設定をそれぞれやりました。
ここでは Kongを通して使えるようになった WebAPIにユーザー認証を付け加えようと思います。
ドキュメントはこちらで。
Key Authentication
Kongでユーザー認証機能を提供することにより、WebAPIを提供しているサーバーではユーザー認証をせずとも良くなります。
その分コンピューターリソースを WebAPIでのサービス提供に割くことができ、かつ開発コストも下げるのだとドキュメントにはあります。
自分でプログラミング言語を使って開発してみると分かるんですが、ユーザー認証機能って結構難しいです。
それにユーザー管理という運用負荷も見過ごせません。
ドキュメントでは「キーによる認証」と言っていますが、ユーザーとパスワードによる認証と考えて良さそうです。
認証を有効にする範囲によって 3種類の方式が書かれていました。
1. Global key authentication
Kongで扱うAPI全体にかけるもの
2. Service based key authentication
サービスに対してかけるもの
3. Route based key authentication
ルートに対してかけるもの
それぞれで機能が変わるわけではなく、あくまでどこに限定して認証を有効にするかだけの違いのようです。
試しに Global key authentication を設定してみます。
これも Kongの管理用WebAPIを叩きますので、Kongのサーバーにリモートログインしてのローカル作業になります。
具体的には上記ドキュメントの「Set up consumers and keys」って段落からになります。
まず Consumer(WebAPIを利用するユーザーのような概念)を登録しなければなりません。
ドキュメントの例そのままに「ルカ」っちゅ〜人を登録します。
subro@UbuntuServer2204:~$ curl -i -X POST http://localhost:8001/consumers/ --data username=luka
HTTP/1.1 201 Created
Date: Mon, 19 Dec 2022 11:15:11 GMT
Content-Type: application/json; charset=utf-8
Connection: keep-alive
Access-Control-Allow-Origin: *
Content-Length: 116
X-Kong-Admin-Latency: 58
Server: kong/3.1.1
{"username":"luka","created_at":1671448511,"id":"186d67f0-4425-4a75-a2e0-f6db61414c25","tags":null,"custom_id":null}
できました。
ルカというと、私はスザンヌ・ヴェガを連想します。
次にパスワードに相当するものと思いますが keyというものをこの consumer(luka)に登録するようです。
但しドキュメントによりますと Kongが自動割当するセキュアなキーが望ましいとあり、明示的にやるのはテストの時だけにしなさいよとのこと。
ですのでこの作業は割愛します。
「Global key authentication」段落に移ります。
ここでは key authentication を有効にするため、プラグインを導入するようです。
subro@UbuntuServer2204:~$ curl -X POST http://localhost:8001/plugins/ --data "name=key-auth" --data "config.key_names=apikey"
{"consumer":null,"tags":null,"created_at":1671449109,"id":"43f2dcd8-660c-4759-8fa6-7b8444dd5389","route":null,"name":"key-auth","service":null,"enabled":true,"config":{"run_on_preflight":true,"key_in_header":true,"key_in_query":true,"key_in_body":false,"hide_credentials":false,"anonymous":null,"key_names":["apikey"]},"protocols":["grpc","grpcs","http","https"]}
これで入ったのかな?
認証なしに、中編で作った WebAPIを叩いてみます。
subro@UbuntuServer2204:~$ curl -i http://localhost:8000/message/ubuntu
HTTP/1.1 401 Unauthorized
Date: Mon, 19 Dec 2022 11:27:22 GMT
Content-Type: application/json; charset=utf-8
Connection: keep-alive
WWW-Authenticate: Key realm="kong"
Content-Length: 45
X-Kong-Response-Latency: 2
Server: kong/3.1.1
{
"message":"No API key found in request"
}
おぉ「401 Unauthorized」になってしまいました。
間違ったキーを使って叩きます。
subro@UbuntuServer2204:~$ curl -i http://localhost:8000/message/ubuntu -H 'apikey:bad-key'
HTTP/1.1 401 Unauthorized
Date: Mon, 19 Dec 2022 11:33:19 GMT
Content-Type: application/json; charset=utf-8
Connection: keep-alive
Content-Length: 52
X-Kong-Response-Latency: 4
Server: kong/3.1.1
{
"message":"Invalid authentication credentials"
}
しっかりとガードされて、以前まで使えていた WebAPIを使えなくなってしまいました。
では、今度は認証されるケースを、と思いましたがキーが分からん…。
Kongが複雑なキーを自動設定してくれているはずですが、それは何なのだろう?
これについては上記のドキュメントではなく、キー認証のドキュメントにありました。
Key Authentication
このドキュメントの「Create a Key」の段落に書いてあります。
lukaに自動で作成されるキーを登録します。
subro@UbuntuServer2204:~$ curl -X POST http://localhost:8001/consumers/luka/key-auth
{"ttl":null,"created_at":1671591673,"key":"K9w3fw2HNPV69km0038qJXAqtAIudmim","consumer":{"id":"186d67f0-4425-4a75-a2e0-f6db61414c25"},"tags":null,"id":"994308a2-c78d-434d-9950-ecdbaefb8430"}
できました。
レスポンスの JSONデータの中、
"key":"K9w3fw2HNPV69km0038qJXAqtAIudmim"
これがキーですね。
今度はキーを使って WebAPIを叩いてみます。
subro@UbuntuServer2204:~$ curl -i http://localhost:8000/message/ubuntu -H 'apikey: K9w3fw2HNPV69km0038qJXAqtAIudmim'
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Content-Length: 29
Connection: keep-alive
Access-Control-Allow-Origin: *
X-Powered-By: Express
X-Content-Type-Options: nosniff
ETag: W/"1d-K1fwK4lTUzQi5xe6WTtLu/eiIh0"
Date: Wed, 21 Dec 2022 03:06:49 GMT
X-Kong-Upstream-Latency: 4
X-Kong-Proxy-Latency: 1
Via: kong/3.1.1
{"message":"Ubuntuっすわ"}
おぉ、レスポンスボディにあの脳天気な結果が!
という訳で、Kongを使って認証機能のない WebAPIで認証をさせることに成功しました。
めでたし、めでたし。
他に負荷分散や流量制限などの機能もありますが、使われている技術や仕組みはそれ程難解なものではなく、リバースプロキシやロードバランサーの知識があれば利用することはそんなに難しい事はないと思います。
そしてエンタープライズ版であれば GUIで設定ができますので、導入障壁は大分低くなるかと。
導入することによるコストダウンは比較的容易に実現できるような気がしました。
しかし、散在する WebAPIを纏めることによって利便性を図ったりコストダウンに繋げようとするには、IT環境全体に対する大きな方針が必要です。
末端のエンジニアではなくシステム部門か、部門長や果ては CIOといった人達の仕事と思われ、末端のエンジニアからのボトムアップで導入するものではないような気がしますね。
OSS版でも十分に効果が得られるものではあるので、末端のエンジニアが導入を画策する場合はスモールスタートして、周りを巻き込んでいくという戦略がよろしいかと思います。