連載
» 2019年12月11日 05時00分 公開

Keycloak超入門(最終回):Keycloakで認可サービスを試してみよう[後編] (1/3)

本連載では、近年注目されている認証プロトコル「OpenID Connect」をサポートするオープンソースのシングルサインオン(SSO)ソフトウェア「Keycloak」の活用方法を解説していきます。Keycloakの認可サービスを利用することで、アプリケーションに対して、より細やかで柔軟なアクセス制御を実現することが可能です。今回は、後編をお届けします。

[和田広之, 相田洋志, 田村広平, 上田直樹, 青柳隆,野村総合研究所/野村総合研究所/フリーランス/株式会社リック/フリーランス]

この記事は会員限定です。会員登録(無料)すると全てご覧いただけます。

「Keycloak超入門」のインデックス

連載目次

本稿で紹介したDocker環境は、以下のGitHubで公開しています。すぐに動かすことができますので、こちらもぜひご参照ください。


はじめに

 前回の第8回では、「Keycloak」の認可サービスのうち、「集中管理方式」について解説しました。集中管理方式では、アクセス制御の管理をシステム管理者が行う「システム管理者中心のアクセス管理」を実現しました。

 今回解説する「UMA方式」では、「UMA(User Managed Access)」というプロトコルを使用してアクセス制御の管理をエンドユーザー自身が行う「エンドユーザー(リソースオーナー)中心のアクセス管理」を実現します。この方式を適用することにより、エンドユーザー自身で、リソースを他者と共有設定することや、パーミッションの認可ワークフロー(パーミッションの申請/承認/拒否)を利用することができるようになります。

 ただし、UMA方式では、Keycloakやクライアントアダプターの設定以外にも、アプリケーション側へ追加の実装が必要になってくるため、集中管理方式に比べると難易度が高く、開発者の負担も多くなります。本稿では、UMA方式の実際の動作を通して、どのような設定や実装が必要になるかを解説していきます。

UMA(User-Managed Access)方式とは

 第8回でも少しだけ触れましたが、UMA方式は「エンドユーザー(リソースオーナー)自身でアクセス制御を行う方式」のことです。そもそも、このUMAは、ID管理技術の相互運用を目指す業界団体「Kantara Initiative」によって標準化が行われているOAuthの拡張の一つです。

 OAuthはリソース管理者がクライアントのアクセスを限定的に認可するためのプロトコル(フレームワーク)ですが、リソース管理者とは別の人物が操作するクライアントに対するユースケースなどは特に規定していません。一方、UMAはそのようなユースケースなどをカバーするためにOAuthを拡張し、設計されたプロトコルになりますUMAの詳しい説明についてはこちらの記事(@ITの記事IPAの技術動向調査)を参照してください。

 UMAを利用することにより、オンラインサービスで提供される各種リソースについて、エンドユーザー(リソースオーナー)自身で、他者や他サービスに対して柔軟なアクセス制御が行えるようになります。つまり、UMAはユーザー主導で動的なアクセス制御が必要となるアプリケーション(特に疎結合なAPIサービスなど)への適用に向いています。逆に言えば、アクセス制御が一定でほとんど変わらないようなアプリケーションでは使う必要のない方式であり、第8回で解説した集中管理方式が適しています。

 今回説明するUMA方式のユースケースを例にとり、図1で各アクターとそれぞれの関係性について、表1で各アクターの役割について説明します。

図1 図1 UMAのアクターとそれぞれの関係性
アクター
(UMAにおける正式名称)
役割
ユーザーA
(Resource Owner)
特定のリソース(図1では画像データ)を所有するエンドユーザー。リソースサーバに対してリソースを作成し、認可サーバに対してリソースの共有やパーミッション申請の承認などのポリシー設定を行う
APIサービス
(Resource Server)
リソースを管理しているサーバ。認可サーバによりリソースは保護されており、リソースサーバがリソースを提供できるかどうかは、認可サーバから認可を得ているか否かに依存する
Keycloak
(Authorization Server)
パーミッションを管理している認可サーバ。デフォルトのポリシーや、リソースオーナーのポリシー設定に応じて、クライアントに対して認可を与えるか否かを判定する
Webアプリ(Client) エンドユーザーに代わってリソースに代理アクセスするアプリケーション。認可サーバから認可を得た上で、リソースに代理アクセスを行う
ユーザーB/ユーザーC
(Requesting Party)
リソースを要求するエンドユーザー。クライアント経由で、リソースにアクセスする。リソースにアクセスする権限がない場合には、パーミッションの申請を行う
表1 UMA方式での各アクターの役割

UMA方式の認可シーケンス

 UMA方式でアクセス制御する場合の動作シーケンスの例を以下の図2図3に示します。図2は、リソース共有時のシーケンス、図3は、パーミッションの申請/承認のシーケンス図になります。なお、図3のパーミッションの申請/承認部分に関しては、UMAの仕様として定義されているものではなく、KeycloakのUMA方式での独自仕様になっています。そのため、認可サーバとしてKeycloakを使用する場合のユースケースの一例として解説します。

図2 図2 UMA方式のリソース共有時の認可シーケンス

(1)ユーザーAが、Webアプリにリソース作成要求を行います。

(2)Webアプリは、APIサービスのリソース作成APIを呼び出します(今回のサンプルではリソース作成もクライアントを経由して実行していますが、UMAとしてクライアントを経由しなければならない仕様というわけではありません)。

(3)APIサービスはリソースの実体を作成するとともに、認可クライアントJava API(後述)を利用して、Keycloakにリソース情報(URI、利用可能スコープ、リソースオーナーIDなど)を登録します。このリソース情報の登録により、ユーザーAがKeycloakの「マイリソース」画面から自身のリソースを他者と共有できる状態になります。

(4)ユーザーBが、ユーザーAのリソース参照の要求を行います。

(5)Webアプリは、APIサービスのユーザーAのリソース参照APIを呼び出します。以降、(5)から(10)までのフローは、RPT(※1)を要求する際のUMAの仕様に準拠した処理フローとなります。UMAにおいて、リソースにアクセスするためには、Keycloakが発行するRPTを取得する必要があります。このRPTを取得するためには、パーミッションチケット(※2)が必要となります。パーミッションチケットはAPIサービスにRPTなしでアクセスすることで取得できます。そのため、このタイミングでは、RPTを送信せずAPIサービスのリソースにアクセスします(UMAのプロトコルフローの概要や詳細については、UMAの仕様ドキュメントの「1.3 Abstract Flow」や「3. Flow Details」をご確認ください)。

(6)APIサービスは、どのリソースのどのスコープ(※3)に対してリクエストがあったのかを元にして、Keycloakにパーミッションチケットの要求を行います。

(7)Keycloakは、APIサービスにパーミッションチケットを返します。

(8)(5)でRPTを送信していないため、APIサービスはアクセスを拒否し、401エラーを返します。この応答のHTTPヘッダに、パーミッションチケットが含まれています。

(9)WebアプリはRPTを取得するために、直前に取得したパーミッションチケットと共に、Keycloakに認可リクエストを送信します。

(10)Keycloakは、ユーザーBに参照権限がないことを判定して、403エラーを返します。

(11)Webアプリは、ユーザーBにアクセスが拒否された結果を返します。

(12)ユーザーAが、Keycloakの「マイリソース」画面で、自身のリソースにユーザーBの参照権限を付与します。

(13)(4)と同じ。

(14)(5)と同じ。

(15)(6)と同じ。

(16)(7)と同じ。

(17)(8)と同じ。

(18)(9)と同じ。

(19)Keycloakは、ユーザーBに参照権限があることを判定して、200応答でRPTを返します。

(20)Webアプリは、再度、APIサービスのユーザーAのリソース参照APIを呼び出します。今回はRPTを取得済みなので、HTTPヘッダにRPTを付与します。

(21)APIサービスは送信されてきたRPTが適切なものかどうか、デジタル署名や各種クレーム値(発行者、有効期限など)を検証します。

(22)APIサービスがユーザーAのリソースを返します。

(23)Webアプリは、ユーザーBにユーザーAのリソースを返します。


※1 「RPT(Requesting Party Token)」とは、該当のユーザーが、どのリソースに対して、どのスコープのアクセスが許可されるかなどの認可情報を含むUMA用のアクセストークンのことです。APIサービス(リソースサーバ)では、適切なRPTが送信されてきているかどうかで、アクセス可否の判断が行われます。

※2 「パーミッションチケット」とは、リソースにアクセスする場合や、新たなパーミッションを要求する場合に、ユーザーが事前に取得する必要があるチケットのことです。どのリソースのどのスコープに対する要求かを含んでおり、このチケットをKeycloakに送信することでパーミッションが評価され、RPTの取得、もしくはパーミッションの申請が行えるようになります。

※3 「スコープ」とは、リソースに対して行えるアクセス範囲(操作)のことです。UMA方式では、「スコープの制限=HTTPメソッドの制限」として利用されます。


図3 図3 UMA方式のパーミッション申請/承認時の認可シーケンス

(1)ユーザーCが、ユーザーAのリソース参照の要求を行います。

(2)Webアプリは、APIサービスのユーザーAのリソース参照APIを呼び出します。この時点ではRPTを取得していないので、RPTは送信しません。

(3)APIサービスは、どのリソースのどのスコープに対してリクエストがあったのかを元にして、Keycloakにパーミッションチケットの要求を行います。

(4)Keycloakは、APIサービスにパーミッションチケットを返します。

(5)(2)でRPTを送信していないため、APIサービスはアクセスを拒否し、401エラーを返します。この応答のHTTPヘッダには、パーミッションチケットが含まれています。

(6)WebアプリはRPTを取得するために、直前に取得したパーミッションチケットと共に、Keycloakに認可リクエストを送信します。

(7)Keycloakは、ユーザーCに参照権限がないことを判定して、403エラーを返します。

(8)Webアプリは、ユーザーCにアクセスが拒否された結果を返します。

(9)ユーザーCが、ユーザーAのリソースの参照権限を要求したいので、Webアプリのパーミッション申請要求を行います。

(10)(2)と同じ。

(11)(3)と同じ。

(12)(4)と同じ。

(13)(5)と同じ。

(14)Webアプリは認可クライアントJavaScript API(後述)を利用して、直前に取得したパーミッションチケットと共に、Keycloakに認可リクエストを送信します。この処理により、要求した操作のパーミッション申請が行われます。パーミッション申請を行うために、「submit_request=true」というパラメーターを付与して、認可リクエストを送信します

(15)当該リソースへのパーミッションがない状態の場合には、Keycloakは403エラーを返しますが、パーミッションの申請自体は成功しています(403エラーのボディー部のJSONのエラーメッセージに「request_submitted」というメッセージが含まれたものが返ってきます)

(16)Webアプリは、ユーザーCにパーミッションの申請結果を返します。

(17)ユーザーAが、Keycloakの「マイリソース」画面を参照すると、ユーザーCから、自身のリソースに対する参照権限を要求されていることが分かります。この申請を「承認」することで、ユーザーCに対して、ユーザーAのリソースの参照権限が付与されたことになります。

(18)(1)と同じ。

(19)(2)と同じ。

(20)(3)と同じ。

(21)(4)と同じ。

(22)(5)と同じ。

(23)(6)と同じ。

(24)Keycloakは、ユーザーBに参照権限があることを判定して、200応答でRPTを返します。

(25)Webアプリは、再度、APIサービスのユーザーAのリソース参照APIを呼び出します。今回はRPTを取得済みなので、HTTPヘッダにRPTを付与します。

(26)APIサービスは送信されてきたRPTが適切なものかどうか、デジタル署名や各種クレーム値(発行者、有効期限など)を検証します。

(27)APIサービスがユーザーAのリソースを返します。

(28)Webアプリは、ユーザーCにユーザーAのリソースを返します。


 以上がUMA方式の概要です。

認可サービスの動作環境の構築

 ここからはUMA方式が動作するDocker環境を使い、実際の動きを確認しながら、UMA方式についての理解を深めていきたいと思います。第8回と同じ環境を利用してUMA方式の動作検証をするため、構築手順については割愛させていただきます。まだ環境を構築されていない方は第8回の記事を参考に構築してください(※第8回のアーカイブから一部内容を変更しているため、既にダウンロード済みの方も新たなDockerビルドファイルでの構築をお願いいたします)。こちらの環境を利用して、図2、図3のシーケンス図で示したようなUMAの基本的な認可フローの動作を確認していきます。

 以降、掲載記事ボリュームの都合上、説明を省略した部分も多くあります。UMAの仕様やKeycloakのガイド、Docker環境などを適宜参照しながら、UMAについての知見を深めていただければと思います。

 今回のDockerイメージでは、httpプロトコルでのアクセスを許可するように設定しています。プロダクション環境では、httpを使うことは推奨されませんので、この点はご注意ください。


図4 図4 今回構築する検証環境の構成

 次に構成するDockerコンテナは、表2のようになります。

コンテナ名 役割 補足説明 UMAでのアクター
kc-example-lb ロードバランサー(SSLアクセレーター) SSLを復号し、構成されるWebアプリコンテナにプロキシするDockerイメージ。ただし、本稿ではSSLは利用していない
kc-example-db Keycloakデータベース MySQL公式のDockerイメージ
kc-example-o Keycloak本体 JBoss公式のDockerイメージに、あらかじめ準備したKeycloak設定をインポートするように構成 認可サーバ
kc-example-app2 Tomcat Tomcat公式のDockerイメージに、Webアプリ兼APIサービスをデプロイするように構成
Webアプリ(authz-uma-client.war) 自作のWebアプリケーション。エンドユーザーに代わって、APIサービスに代理アクセスを行う。UMA方式では、他者のリソースへも権限次第でアクセス可能になる クライアント
JavaScriptアダプター(JavaScriptライブラリ) JavaScriptにより、アプリケーションの保護を行うKeycloakのクライアントアダプター(JavaScriptライブラリ)。このJavaScriptアダプターにより、Keycloakに認証済みかどうかのチェックやログインユーザー情報の取得などが行われる
認可クライアントJavaScript API(JavaScriptライブラリ) Keycloakとの通信において、UMAに準拠したRPTの取得、パーミッションの申請、現在のパーミッション取得などを行うためのJavaScriptライブラリ。Webアプリのプログラム内でこのライブラリを利用することで、Keycloakとの連携が容易になる(※実装例は後述)
APIサービス(authz-uma-api.war) 自作のAPIサービス。Tomcatアダプターや認可クライアントJava APIを経由して、KeycloakとUMAの仕様に準拠した通信を行う リソースサーバ
Tomcatアダプター(Javaライブラリ) TomcatのWebアプリケーションの保護を行うKeycloakのクライアントアダプター(Javaライブラリ)。このTomcatアダプターにより、リソースサーバ内のURLに対して、UMAの仕様に準拠した認可制御が行われる
認可クライアントJava API(Javaライブラリ) Keycloakとの通信において、UMAの仕様に準拠したリソースの管理やパーミッションの管理を行うためのAPI。APIサービスのプログラム内でこのライブラリを利用することで、Keycloakとの連携が容易になる(※実装例は後述)
表2 構成するDockerコンテナ一覧

 UMA方式の動作確認で利用するコンテンツ/APIは、表3のようになります。

コンテンツ アクセス制御 チェックポリシー URI メソッド 用途
Webアプリ 認証必要 認証のみ /authz-uma-client/ GET 各種APIサービスを呼び出すWebアプリケーション
APIサービス Bearerのみ /authz-uma-api/api/items GET リソース(Item)の一覧を取得するAPI
POST リソース(Item)を作成するAPI
リソースオーナーのみ /authz-uma-api/api/items/{ID} GET リソース(Item)を参照するAPI
PUT リソース(Item)を更新するAPI
DELETE リソース(Item)を削除するAPI
表3 Webアプリ兼APIサービスのコンテンツ/API一覧

UMA方式の動作確認

 それでは、UMA方式の実際の動作を確認していきましょう。今回の検証では、大きく分けて、以下の3つのシナリオがあります。

[1]リソースの作成
 リソースオーナー(user001)が、リソースサーバにリソースを作成する操作を確認します。リソースサーバ側にリソースの実体が作成されるのと同時に、Keycloak側にもリソース情報の登録が行われます。

[2]リソースの共有/共有解除
 リソースオーナー(user001)が、自身のリソースをリクエスティングパーティー(user002)に共有/共有解除する操作を確認します。この共有操作により、user002がuser001のリソースにアクセスした際の挙動が変わることを確認します。

[3]リソースへのパーミッションの申請/承認/拒否
 リクエスティングパーティー(user003)が、リソースオーナー(user001)のリソースに対して、パーミッションの申請を行います。user001がこのパーミッション申請を許可することにより、user003がuser001のリソースにアクセスした際の挙動が変わることを確認します。

 以降の動作確認では、前出の図2図3のシーケンス図と見比べながら、動作確認を行うと流れが理解しやすいです。シーケンス図上のユーザーAは「user001」、ユーザーBは「user002」、ユーザーCは「user003」に対応しています。

[1]リソースの作成

【リソースオーナー(user001)の操作】
 1.Webアプリ(http://uma.example.com/authz-uma-client/)にアクセスします。

 2.user001でログインします。

 3.Webアプリのトップ画面(リソース一覧)が開きます(画面1)。この時点では、user001に何もリソースが作成されていない状態です。

画面1 画面1 Webアプリのトップ画面

 4.「リソース管理」プルダウンから「リソースの共有/申請の確認・承認」をクリックすると、Keycloakの「マイリソース」画面が開きます(画面2)。この時点では、ログインユーザーが所有しているリソースはないことが分かります。

画面2 画面2 Keycloakの「マイリソース」画面(リソース作成前)

 5.画面右上の「authz-uma-clientに戻る」を押して、Webアプリに戻ります(画面3)。

画面3 画面3 Keycloakの「マイリソース」画面

 6.「リソース管理」プルダウンから「リソースの新規作成」をクリックします。「リソース名」「メモ」を入力可能な画面が表示されます(画面4)。ここではリソース名に「user001 Item」という文字を入力して、「リソースの作成」ボタンをクリックします。正常にリソースが作成されると、「簡易メッセージ」に「リソースが作成されました!」というメッセージが表示されます(画面5)。

画面4 画面4 リソースの新規作成
画面5 画面5 リソースの新規作成完了

 7.フッター部の「リソース一覧に戻る」のリンクをクリックすると、画面上に作成したリソースへアクセスするリンクが表示されるようになります。自分のリソースに対しては、どの操作も問題なく実行できることを確認できます(自身が所有するリソースに対しては、「リソース操作」ボタンは白色で表示され、権限申請のボタンは表示されません)。

 8.リソース作成後に「マイリソース」画面がどのように変わったかを確認するため、再び、「リソース管理」プルダウンから「リソースの共有/申請の確認・承認」をクリックします。先ほどとは異なり、マイリソースに「user001 Item」というリソースが表示されていることが分かります(≪≫画面6)。

画面6 画面6 Keycloakの「マイリソース」画面(リソース作成後)

 9.画面右上の「authz-uma-client に戻る」を押下して、Webアプリに戻ります。

 10.「ログアウト」して、user002、user003でも同様にリソースの作成操作を行っておきます。

[2]リソースの共有/共有解除

【リクエスティングパーティー(user002)の操作】
 1.user002でWebアプリにログインします。

 2.「user001 Item」の「参照」「削除」の操作を行ってみます(画面7)。いずれも、401 errorが発生し、全ての操作が拒否されていることを確認できます(自身が所有しないリソースに対しては、「リソース操作」ボタンは青色で表示され、権限のない操作に関しては、それぞれの権限申請のボタンが表示されます)。

画面7 画面7 他者のリソースへのアクセス拒否

【リソースオーナー(user001)の操作】
 3.「マイリソース」を押下し、リソースの「user001 Item」を押下します。現在のこのリソースにアクセスできるユーザー一覧や、他者と共有するための「共有」ボタンが表示されます。

 4.ここで「他人と共有」の「ユーザー名 or Eメール」に「user002」を指定し、リソースの削除権限である「item:delete」の「×」をクリックした後で「共有」ボタンをクリックします(画面8)。

画面8 画面8 別ユーザーとのリソース共有操作

 5.「このリソースにアクセスできる人」の中にuser002が追加され、許可されている操作は「item:update」と「item:view」になっていることを確認できます(画面9)。

画面9 画面9 共有後の「user001 Item」の表示

【リクエスティングパーティー(user002)の操作】
 6.「user001 Item」の「参照」「更新」「削除」の操作を行ってみます。先ほどとは異なり、「参照」「更新」は「200 success」が返り、user001により共有された操作(item:viewとitem:update)だけが許可されていることが分かります。削除(item:delete)に関しては、401 errorが発生し、アクセスが拒否されていることが分かります(画面10)。

画面10 画面10 リソース共有が適切に動作した結果

[3]リソースへのパーミッションの申請/承認/拒否

【リクエスティング・パーティー(user003)の操作】
 1.user003でWebアプリにログインします。

 2.「user001 Item」の「参照」「削除」の操作を行ってみます。いずれも、401 errorが発生し、全ての操作が拒否されていることを確認できます。

 3.「user001 Item」の「権限申請」から、「参照権限申請」と「更新権限申請」をクリックします(画面11)。

画面11 画面11 「user001 Item」の「更新権限申請」のパーミッション申請の呼び出し

 4.「リソース管理」プルダウンから「リソースの共有/申請の確認・承認」をクリックします。「承認待ちのリクエスト」にuser001に対して、パーミッションが申請中の状態になっていることを確認できます(画面12)。

画面12 画面12 承認待ちリクエストの表示

【リソースオーナー(user001)の操作】
 5.「リソース管理」プルダウンから「リソースの共有/申請の確認・承認」をクリックします。「承認が必要」にuser003から「item:view」と「item:update」のパーミッションが申請されていることを確認できます(画面13)。

画面13 画面13 パーミッション申請の承認画面

 6.「item:update」を削除した上で、「承認」ボタンをクリックします。

【リクエスティングパーティー(user003)の操作】
 7.「user001 Item」の「参照」「更新」「削除の操作を行ってみます。先ほどとは異なり、「参照」は、200 successが返り、「更新」「削除」に関しては、アクセスが拒否されます(画面14)。申請した操作のうち、user001が許可した操作(item:view)だけが、許可されていることが分かります(画面15)。

画面14 画面14 アクセス申請が許可された後の「user001 Item」の参照操作
画面15 画面15 アクセス申請が許可された後の「user001 Item」の更新操作
       1|2|3 次のページへ

Copyright © ITmedia, Inc. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。