はじめに
KongのGet Started with Kongを読むと、Kongには認証方式が色々できると書かれていて、Key認証が紹介されている。
で、OAuth認証のやり方はどうするんだろう、と調べていたら、KongのBlogにOAuth認証の手順や、実際に動かした56さんの記事があった。
これらを参考にOAuth認証のやり方を自分なりに整理。なお、KongのインストールやOAuth認証の仕組みの説明は割愛。
基本Blogの設定に従っているが、リソースサーバであるAPIサーバとの接続は56さんの記事の中でGitHubにあげていたサンプルを参考にして、httpsでなくhttpに変更した。
前提条件
- Kong Gatewayはdocker-composeでコンテナとして構築
- APIサーバもコンテナで作成したが、KongからAPIサーバを呼び出せなかった。コンテナ同士で通信する場合、仕掛けが必要?よく分からなかったのでAPIサーバはコンテナを諦め、VagrantでVMを作成した
- OAuth認証は4フローあるが、今回は
Client Credentialsフロー
をターゲットにした。Client Credentialフローの詳細はRFCの和訳の「4.4. Client Credentials Grant」を参照。
APIサーバの設定
最初にProxy先となるAPIサーバを作成
基本はBlogの記事のとおり。
wb01のホスト名でVM作成後、以下を実施。コマンドのみ記載。
~$ mkdir project
~$ cd project
~/project$ yarn init
# 質問には全部デフォルト(リターン)で
https通信しないので、Blogと違って必要最小限のパッケージだけ
~/project$ yarn add express
Blogのとおり、APIサーバ用のJSONデータ用意。
GET /stepcounts
で呼び出す。
{
"alice": [
{ "date": "2021-01-01", "count": 14500 },
{ "date": "2021-01-02", "count": 6500 },
{ "date": "2021-01-03", "count": 28000 }
],
"bob": [
{ "date": "2021-01-01", "count": 900 },
{ "date": "2021-01-02", "count": 1400 },
{ "date": "2021-01-03", "count": 1100 }
],
"clark": [
{ "date": "2021-01-01", "count": 2500 },
{ "date": "2021-01-02", "count": 12000 },
{ "date": "2021-01-03", "count": 9500 }
]
}
56さんの記事を参考にhttpで/stepcounts
のエンドポイント作成
// PATH: project/index.js
const port = 3000
const express = require('express')
const app = express()
const data = require('./data.json')
const getCurrentUser = ({ headers }) => {
return headers['mock-logged-in-as'] ||
headers['x-authenticated-userid']
}
app.get('/stepcounts', (req, res, next) => {
console.log(req.headers)
const user = getCurrentUser(req)
if (!user) {
res.status(401).send('Not authorized')
return
}
res.send(data[user] || [])
})
app.listen(port, () => {
console.log(`Server is listening on http://wb01:${port}`
)
})
サーバ起動
~/project$ node index.js
Server is listening on http://wb01:3000
APIサーバの疎通確認
疎通確認用のクライアントとしてInsomniaでWebアクセスを試す。Postmanでもいいのだが、Header情報の書き換えができなかったりしたため、不便だったので使わず。
index.jsではmock-logged-in-as
でユーザチェックをしているので、Header情報が不足しているとエラーになる。
http://wb01:3000/stepcounts
でmock-logged-in-as
ない場合
mock-logged-in-as
を付与した場合、clarkの値が返ってくる。
Kong GatewayとAPIサーバの配置
ServiceとRouteを登録
サービス名「step-on-api-service」とURL入れる。
特に難しい部分はない。登録済みのServiceがプルダウンから選択可能。
RouteのエンドポイントはBlogだとhttpとhttps両方の設定にしているが、今回はhttpのみで/stepon
をPathとしている。
Kong GatewayとAPIサーバの通信確認
InsomniaからKongのRouteにアクセス。
アクセス先はhttp://localhost:8000/stepon/stepcounts
。Headerにmock-logged-in-as
も必要。
OAuth2プラグインの導入
Service「step-on-api-service」からOAuth2.0
プラグインを追加。Serviceの中でPluginを追加するとGlobal設定されず、Serviceに閉じた範囲で有効になる。
oauthで検索し、OAuth 2.0 Authentification
を選択する。OSS版では使えないプラグインも表示される。
今回はOAuth認証フローのクライアント認証
を試すので、Enable Client Credentials
にチェックを入れる。その他必要な情報を設定する。
すでにOAuth認証が有効になっているので、Access Tokenなしでアクセスしようとするとエラーになる。
OAuth認証を無効にしたい場合、Enabledのボタン押下で無効化できる。
無効化となると、先ほどAccess Tokenなしでエラーになったリクエストが再び成功する。
Client Application(API Consumer)を追加
誰がアクセスできるか設定する。
Client Applicationとしてshoeflyshoeの名前で利用者を登録する
最初にshoeflyshoeさんを登録
次にshowflyshoeさんに認証情報を登録する。クライアントがToken取得する際に必要な情報となる。
Consumersのshoeflyshoeを選択してCredentials情報を登録する。
client_id, client_secretを入力、Client Type
はconfidential
が良さそう。
OAuth2.0のRFCの「2.1. Client Types」に記載あり。
以上の設定でOAuth2.0認証の設定は完了。
今回はClient Credentialsフロー
のみを有効にし、クライアント認証
OAuth2.0認証によるAPIアクセス
Client Credentialsフロー
をやってみる。
アクセスToken取得
以下の2通りのやり方がある。詳細は@TakahikoKawasakiさんのページで説明されている。
- BODY部にclient_id,client_secretを設定
- Head部にBASE64エンコードした情報を設定
Token取得のURLは/oauth2/token
らしい。
grant_typeはclient_credentialsにする(RFC参照)
その1:BODY部にclient_id,client_secretを設定
なお、RFCによれば、Content-Type=application/x-www-form-urlencoded
とあるが、間違って指定してもTokenは取得できた。
その2:Head部にBASE64エンコードした情報を設定
client_idとclient_secretの値を":"でつなぎ、BASE64でエンコードしてToken取得リクエスト。
今回の例で言えばsome_client_id:some_client_secret
をエンコードし、生成されたc29tZV9jbGllbnRfaWQ6c29tZV9jbGllbnRfc2VjcmV0
をHeaderに入れる。先頭にBasic
を入れ忘れないこと。
取得したAccessTokenを使ってAPIサーバにアクセス
AccessTokenが取得できたら、そのTokenを使ってAPIサーバにアクセス。
Tokenの先頭にbearer
が必要。
もしTokenが誤っていたり、有効時間切れの場合はエラーになる、。
まとめ
Kongの各種設定がGUIから可能になって操作性が向上したので、GUIベースの設定方法の紹介です。
他のフローも同様の手順で試すことができるはずなので、そのうち試してみる。とはいえ、OAuth認証難しい。。。