株式会社 日立製作所 茂木昂士
はじめに
OAuth/OpenID Connect では、アクセストークンを発行する Token リクエストの際に、リクエストを送信したクライアントが正しいか確認するためにクライアント認証を行っています。Keycloak の Client 画面で Credentials タブを開くと、Client Authenticator
にデフォルトでClient Id and Secret
というものが選択されています。これは、Client ID 及び Client Secret によってクライアントを認証するというものです。RFC7523 : JSON Web Token (JWT) Profile for OAuth 2.0 Client Authentication and Authorization Grantsでは、この Client ID と Client Secret による認証に代わる方法として、署名した JWT によるクライアント認証の方法が定義されています。
今回は Keycloak を利用して、JWT によるクライアント認証を試してみたいと思います。
Keycloak での設定
まず、Keycloak で JWT を署名するための鍵を生成します。Client の Credentials タブを開き、Client Authenticator
の項目でSigned Jwt
を選ぶと、Generate new keys and certificate
と Import Certificate
というボタンが表示されます。
今回は生成されたキーペアを利用したいので、Generate new keys and certificate
を選択します。
キーストアの形式は、JKS(Java KeyStore)
形式とPKCS12
形式が選択できます。今回はPKCS12
形式を選択しました。クライアント側のプログラムで利用しやすいほうを選択してください。そのほか必要な項目を埋めて Generate new keys ans certificate をクリックすると、キーペアが生成されるとともに、Private Key が保存されたキーストアkeystore.p12
がダウンロードされます。このキーストアにある Private Key を利用して、JWT に署名を付加することになります。
クライアントプログラム側での対応
クライアントから Keycloak へ Token リクエストを行う際に、先ほど生成した Private Key で署名を行った JWT を送信します。その際の、署名を行う JWT の形式は 3. JWT Format and Processing Requirementsに定義されています。
今回は下記の通りとしました。
{
"aud": "http://localhost:8080/auth/realms/sample/protocol/openid-connect/token",
"exp": 1544091946,
"jti": "7e2f184e-6e1b-415f-99d8-56ca6ccf6946",
"iat": 1543227946,
"iss": "http://localhost:3000/",
"sub": "client"
}
JWT の各 Claim に関しては下記の通りです。
# | Claim | Value |
---|---|---|
1 | aud | Token Endpoint の URL を指定する。 |
2 | exp | トークンの有効期限を設定。 |
3 | jti | JWT の ID で、 JWT 毎にユニークな値にする必要がある。今回は UUID を使用。 |
4 | iat | トークンを署名した時刻を設定。 |
5 | iss | JWT を署名したクライアントの識別子。一般的にはクライアント側の URL 等が利用される。 |
6 | sub | 自身の Client ID。Keycloak に登録されている ID を利用する。 |
JWT への署名が完了したら、下記のパラメータを Token エンドポイントに送信します。
# | Key | Value |
---|---|---|
1 | redirect_uri | http://localhost:3000/callback |
2 | grant_type | authorization_code |
3 | code | (Keycloak から送られた Code の値) |
4 | client_id | client |
5 | client_assertion_type | urn:ietf:params:oauth:client-assertion-type:jwt-bearer |
6 | client_assertion | (署名した JWT) |
特徴として、client_secret
がなくなった代わりに、client_assertion_type
と client_assertion
が追加されています。client_assertion_type
はurn:ietf:params:oauth:client-assertion-type:jwt-bearer
を指定し、client_assertion
には先ほど署名した JWT の値を指定してリクエストを実行します。
上記のリクエストによって Keycloak 側で 署名の検証、JWT の検証が行われ、値が正しければ Keycloak からアクセストークンが発行されます。
RFC7523 を使用する利点
クライアント認証を行う際にClient ID
とClient Secret
を利用する方法では、どうしても通信経路に秘密情報であるClient Secret
が流れてしまいます。そのため、通信経路の盗聴などにより情報が漏えいしてしまう可能性があります。
一方、RFC7523 を利用すると JWT の情報が通信経路に流れますが、その情報には有効期限exp
が指定されていますので、Client Secret
が漏えいするよりも被害を抑えることができます。また Keycloak は、仕様では Optional となっている Replay Attack 防止(jti
による JWT の再利用防止)が実装されているため、使用済みの JWT が漏えいしてもアクセストークンの発行はできなくなっています。
まとめ
Keycloak ではセキュリティを高めるための様々な機能が実装されていて、システムのセキュリティ要件に応じて必要な機能を利用することができます。ただ、ドキュメント化されていない部分も多く、利用が難しいのが現状です。これからも色々な機能を利用して、情報を発信していきたいと思います。