KeycloakによるAPIセキュリティの基本

2020年5月28日(木)
中村 雄一
連載の1回目である今回は、Keyclooakの基本および、API保護が必要とされる背景について解説します。

サービスがより活発に利用されることを狙って、企業や公的機関によるサービスのAPI(Application Programming Interface)公開が広がっています。また、自組織内でもモバイルアプリケーション開発やシステム間連携を行いやすくするために、システムがAPIを提供することが多くなってきています。その際、APIは限られた人やシステムにだけがアクセス可能にする必要があるため、認証・認可のようなセキュリティ技術が必須になってきます。

認証・認可は、OAuth 2.0の枠組みに基づくことが一般的ですが、OAuthは自由度が高い仕様であるため、誤って実装・構築してしまうとセキュリティホールが作りこまれてしまいます。本記事では、近年急成長を遂げている認証・認可サーバOSSである「Keycloak」を用いて、APIを保護していく方法を紹介していきます。なお、APIとしては、使い勝手の良いREST APIが用いられることが多いため、本連載における「API」はREST APIを対象にします。また、同じくRESTで実装されることの多いマイクロサービスの分野でもAPI保護と同様の考え方の適用が進んでいるため、マイクロサービス保護用途の使い方も紹介して行ければと考えています。

第一回は、背景となるOAuth 2.0のメリットと注意点、またAPI保護の要となるKeycloakの基本的な概念の紹介を行います。

OAuth 2.0によるAPI保護のメリット

最初に、APIの保護に広く使われる「OAuth 2.0」のメリットと注意点を見ていきます。OAuth 2.0とは、「RFC6749: The OAuth 2.0 Authorization Framework」にて定められる、HTTPで提供されるサービスに外部のアプリケーションがアクセスするための仕組みです。OAuth 2.0以前では、サービスが外部のアプリと連携する場合は、図1のように外部アプリ側にて、サービスにログインするためのID・パスワードを保管し、アプリが人間の代わりにサービスのWeb画面を解析し、認証情報を入力、必要な情報を取得することで連携していました。しかしこの手法では、外部アプリがサービスの認証情報を保管するため、認証情報が流出するリスクが増大してしまう問題があります。また外部アプリにとっても、Web画面を解析・認証情報を代理入力するという処理の作りこみが大変という課題がありました。

図1:OAuth 2.0以前の外部アプリ連携

図1:OAuth 2.0以前の外部アプリ連携

一方、OAuth 2.0では、APIで外部アプリと連携することになります(図2)。APIをコールする前に、「認可サーバ」にアクセスします。認可サーバは、ユーザ認証を行い、APIアクセスの同意をユーザから取得し、その結果として「アクセストークン」と呼ばれる情報を外部アプリに払い出します。外部アプリは、アクセストークンとともにサービス側のAPIをコールすることで、サービスと連携します。ここでは、ユーザ認証は認可サーバで行われるため、認証情報が外部アプリに渡ることがなく、さらにアプリ側の作りも簡易であることから、OAuth 2.0によるAPI連携が急速に広まっていきました。今やAPI連携では、OAuth 2.0を使うのが珍しくなくなりつつあります。

図2:OAuth 2.0による外部アプリ連携

図2:OAuth 2.0による外部アプリ連携

OAuth 2.0の注意点

OAuth 2.0を使うことで、セキュアかつ利便性の高いAPI連携を実施できるように見えますが、「The OAuth 2.0 Authorization Framework」という仕様名からわかるように、あくまで「Framework(枠組み)」であり、適切に実装しないと脆弱性が生じてしまいます。図3に、OAuth 2.0での最も典型的なフローである「Authorization code grant」と注意点を記しています。こちらのフローでは、①~③において、ユーザ認証を行い、API連携による情報アクセスの同意をエンドユーザから取得します。ここでエンドユーザは「スコープ(scope)」に対して同意します。スコープとは、エンドユーザに関する情報(リソースと呼ばれます)に対するアクセスを同意する範囲を表す任意の文字列です。例えば「email」というスコープは、エンドユーザの電子メールアドレスへのアクセスへの同意を表します。

スコープはシステムの特性に合わせて任意に作成することができます。認証後、エンドユーザに対してスコープに対する同意を求めるダイアログ画面が出てきます。エンドユーザからスコープへの同意が得られると、その結果「認可コード」が外部アプリに払い出され、さらに認可コードを使ってアクセストークンが外部アプリに払い出されます(④~⑥)。外部アプリは、アクセストークンを付与してAPIサーバにアクセスし、APIサーバはアクセストークンのスコープの範囲内の情報を返します(⑦)。

ここで次にあげる3点について気を付ける必要があります(図3)。

図3:OAuth 2.0のAuthorization Code Grantと注意点

図3:OAuth 2.0のAuthorization Code Grantと注意点

注意点1:認証はOAuth 2.0の範囲外

OAuth 2.0は認証のための標準と誤解されがちですが、実際にはOAuth 2.0では、認証をどのように行うかは定められていません。極端な話、ユーザ名だけで認証することも可能です。しかし、脆弱な認証を実装してしまっていては何の意味もなくなってしまいます。

注意点2:脆弱な実装による隙が生じる

OAuth 2.0では、認可コードやアクセストークンをどのように認可サーバが払い出すのかというインタフェースのみが定められています。認可サーバ側の実装の自由度が非常に高く、実装を誤ってしまうと、

例えば、④の認可コードを悪意の第三者に渡してしまう脆弱性を作りこんでしまうことも考えられます。このような隙をなくすために、認可サーバ側では、専門家コミュニティで検討されたベストプラクティスや追加仕様に則って実装を行う必要があります。ここでは、認可サーバ側をしっかり実装するだけではなく、外部アプリ側でも適切にパラメータを付与しチェックする必要もあります。

注意点3:トークンの取り扱いは任意

OAuth 2.0では、アクセストークンを受け取ったAPIサーバがアクセストークンをどう扱うか定められていません。そのため、APIサーバ側がアクセストークンの確認を行わずに処理を進めてしまうと、悪意の第三者に情報を渡してしまうなどの問題が生じます。「アクセストークンが改ざんされていないか」「誰のためのアクセストークンなのか」「スコープは合っているか」などチェックした上で処理を進める必要があります。さらに、アクセストークンの管理方法(例:どう失効させるか)も任意ですので、実装を誤るとアクセストークンを失効できないなどの問題が生じることもあります。

このように、OAuth 2.0の自由度の高さに起因する問題が起こってしまっていることから、周辺仕様を策定する動きも出てきています。例えばOpenID Connectでは、シングルサインオンにも使えるようにするなどOAuth 2.0の使い方を定めています。また、OAuth 2.0 Security Best Current Practiceでは、OAuth 2.0をセキュアに実装するための最新のベストプラクティスがまとめられています。

そのベストプラクティスを踏まえて金融業界のような高いセキュリティが求められるシステムにも使えるよう、OAuth 2.0の安全性を高めたFinancial Grade API(FAPI)という仕様も定められています。

API認可サーバとして注目のKeycloak

OAuth 2.0によるAPI保護の要になるのは、OAuth 2.0のフローの中でアクセストークンを発行・管理する認可サーバです。ここの実装を誤ると脆弱性が作りこまれてしまいますし、また最新のベストプラクティスに追随するためには、新たに作成される規格にも対応していく必要があるため、認可サーバを独力で実装するのは非現実的です。そのため、専用の認可サーバソフトを利用することが一般的です。認可サーバの実装の中でも、OSSである「Keycloak」に今回は注目します。

Keycloakとは、Red Hat社を中心にOSSにて開発されているID管理・アクセス管理のソフトウェアです。Keycloakは、WildFly(Red Hat社のJBoss EAPのベース)というJava APサーバの上に実装されており(したがってJava言語で実装)、WildFlyと一体化した形で配布されています。最小構成ではzipファイルを展開しスクリプトを叩くだけで起動することができ、可用性要件に応じて、クラスタを組むこともできます。

Keycloakを導入すれば、WebシステムやAPIの認証をすべてKeycloakに任せることができます(図4)。つまり、システムの認証が必要になった場合、SAML 2.0やOpenID ConnectのようなシングルサインオンのプロトコルでKeycloakにリダイレクトし、Keycloakは他の認証サーバやデータストアとブリッジします。例えばGitHubやTwitterとのソーシャルログインとブリッジしたり、LDAPやActive Directoryとの認証をブリッジしたりすることもできます。また、Keycloak自身が認証情報を管理し、認証することもできます。

図4:Keycloakの主な機能

図4:Keycloakの主な機能

KeycloakはOAuth 2.0を前提とするOpenID Connectに対応していますので、APIの認可サーバとしても利用することができます。筆者らもKeycloakコミュニティでの開発に携わっていますが、KeycloakはAPI認可サーバ向けの機能も活発に行われており、最新の仕様へも追随していっています。例えば、OAuth 2.0を強化した最新仕様であるFAPI対応の開発状況については、こちらのページに筆者がまとめています。

また、実システムへの適用時には、既存の認証システムや認証情報との繋ぎ込みが重要になりますが、Keycloakは豊富なカスタマイズポイントを備え、OSSであることから拡張しやすくシステム個別の要件も取りこみやすい特徴があります。さらに、商用サポートが必要な場合も、商用版のRed Hat Single Sign-OnがRed Hat社から提供されていることもあり、近年API認可サーバとしての利用が拡大しています。

API保護のためにやるべきこと

本連載では、図3で紹介した注意点1~3に留意しつつ、認可サーバとしてKeycloakを構築してAPIを保護していきます。本連載では、図5のような構成で注意点をクリアしてきます。

図5:本連載でのAPI保護の構成

図5:本連載でのAPI保護の構成

注意点1、2(認証・脆弱な実装)については、Keycloakをしっかり構築することで対策が実現できます(①)。一方、注意点3(トークンの取り扱い)については、APIサーバ側でトークンを適切にチェックすることが必要になってきます。APIが増えてくると各APIでの実装の漏れが出てくる恐れがあります。

そこで、本連載では②のように「APIゲートウェイ」をAPIサーバのリバースプロキシとして配置し、ここでアクセストークンをチェックします。APIゲートウェイとしては、さまざまなものがありますが、本連載では最も簡便である「NGINX」を使います。

Keycloakにおけるトークンの種類

実際の構築に進む前に、KeycloakでAPI認可サーバを構築する際に最も重要な概念となるトークンについて、その種別と管理について解説します。

Keycloakでは、下表に示すようにアクセストークンなど4種類のトークンをサポートしています。これらのトークンは図3⑤のトークンリクエストのレスポンスとして返ってきます。それぞれの詳細を見ていきましょう。

表1:Keycloakにより発行されるトークン類

#トークン種別概要
1アクセストークンRFC 6749で定められたアクセストークン。JWT
2リフレッシュトークンRFC 6749で定められたリフレッシュトークン
3オフライントークン永続化されることを意図したリフレッシュトークン
4IDトークンOpenID Connectで定められたIDトークン

アクセストークン

図3でも紹介したOAuth 2.0の主役ともいえるアクセストークンです。実はOAuth 2.0の仕様であるRFC6749では、トークンの形式については任意となっているため、形式は認可サーバに依存したものになっています。Keycloakでは、JWT(JSON Web Token)という形式を採用しています。JWTでは、JSONにて情報が記載され、そのJSONがKeycloakによって署名されBase64 URLエンコードされています。署名されていますので、アクセストークンを受け取ったAPIサーバは改ざん検知を行うことができますし、また、JWTの中のJSONを取り出せば、トークンに紐づくスコープやユーザ属性などの情報を素早く知ることもできます。

図6にKeycloakが発行したアクセストークン中のJSONの例を示します。トークンの管理情報や、アクセストークンに紐づく属性情報が格納されています。また、属性情報については何を入れるかはカスタマイズ可能になっており、APIサーバにとって必要な情報を入れておくこともできます。

図6:アクセストークン中のJSONの例。JSONは署名され改ざん検知可能

図6:アクセストークン中のJSONの例。JSONは署名され改ざん検知可能

リフレッシュトークン

OAuth 2.0を定めたRFC6749にて定義されるトークンです。OAuth 2.0では万が一アクセストークンが漏えいすると、他人であってもアクセストークンを行使できてしまい、API保護が意味をなさなくなります。そのため、アクセストークンの有効期限は短めに設定することが一般的です。しかし有効期限を短くすると、すぐにユーザ再認証が必要になり利便性が大きく損なわれます。

そこで導入されたのがリフレッシュトークンです。リフレッシュトークンを持っていれば、ユーザ再認証なしに、アクセストークンを認可サーバに再発行してもらうことができます(トークンリフレッシュ)。リフレッシュトークンの有効期限をアクセストークンよりも長く設定しておけば、アクセストークンの有効期限が切れても、外部アプリは、リフレッシュトークンによりユーザの再認証なしにアクセストークンを取得できます。

「リフレッシュトークンが悪意のある第三者に漏れたらアクセストークンを取得・行使されてしまうのでは」と心配されるかもしれませんが、トークンリフレッシュ時にクライアント認証(RFC6749の記載に従い元々リフレッシュトークンが発行されたクライアントであることを認証する)を必須にしたり、リフレッシュトークンの中身をトークンリフレッシュごとに変更したりすることで、万一漏えいした場合のリスクを軽減することができます。Keycloakでは、図3⑤⑥のトークン発行時にアクセストークンともにリフレッシュトークンも発行され、またリフレッシュトークン漏えい時のリスク軽減策も設定することができます。

オフライントークン

Keycloakのリフレッシュトークンは、パフォーマンス上の理由から内部的にはメモリ上で管理されています。そのため再起動するとリフレッシュトークンは消えてしまいます。クラスタを組んでいたとしても、クラスタを全台停止すると消えてしまいます。リフレッシュトークンが消えた場合、エンドユーザは再度ユーザ認証し、アクセストークン・リフレッシュトークンの再取得が必要になります。ユーザの利便性の観点から、このような事態が望ましくない場合もあります。

このような場合、「オフライントークン」を使うことで、回避できます。オフライントークンの実体は、リフレッシュトークンをデータベースにより永続化できるようにしたもので、外部アプリからの見た目はリフレッシュトークンと同じです。再起動しても消失することはありません。また、キャッシュにロードされるため、パフォーマンス上の影響も実際は起動時のロード時間がかかるだけで、一度起動してしまえばパフォーマンス上の影響は最小限になっています。

IDトークン

OpenID Connectで定められたIDトークンです。主にシングルサインオン目的で使いますが、デフォルトでは空になっています。

Keycloakにおけるトークンの管理

Keycloakでは、これらのトークンを「セッション」という概念で管理しており、Keycloakを構築するためには、このセッションへの理解が不可欠です。セッションの概要と、トークンの有効・無効の管理について見ていきます。

セッションとトークン

Keycloakでは、トークンそのものが内部的に保持・管理されているのではなく、「セッション」というデータ構造にて管理されています(図7)。

図7:セッションとトークンの関係

図7:セッションとトークンの関係

セッションは、OAuth 2.0フローにて、認証が成功し同意が成立した段階(図3でいう③)でメモリ内(実体はinfinispanというKeycloak内蔵の分散KVS内)に生成されます。セッションとしては、「ユーザセッション」と「クライアントセッション」が生成されます。ユーザセッションは認証されたユーザの状態を管理し、クライアントセッションはログインに使ったクライアント(図3でいう外部アプリ)の情報を管理しています。そして、これらのセッションに紐づいてトークン類が管理されるようになります。トークン発行の際も、セッションの情報を元にトークンのデータを作成します。また、セッションがログアウトや有効期限切れにより無効になると、紐づいたトークン類もすべて無効になります。

なお、セッションには、「オフラインセッション」というものも存在します。オフラインセッションは、オフライントークンを使う設定をした場合に生成され、実体はデータベースにも永続化されています。オフラインセッションには、ユーザセッション・クライアントセッションにそれぞれ対応するオフラインユーザセッション・オフラインクライアントセッションが存在します。これらは、Keycloakの起動時にメモリ(infinispanで管理)にロードされます。

トークン類の有効期限の設定

トークン類の有効期限の設定については、上記の「セッション」を意識しつつ管理画面で行うことになります。こちらは実際の設定例とともに見ていったほうがわかりやすいため、第二回以降で実例とともに紹介します。

トークンの失効とToken Introspection

トークンは有効期限による管理だけではなく、明示的に失効させることもできます。つまり、管理コンソールから管理者が失効させることもできますし、クライアント側から失効させることもできます。実用上は、API連携解除するためにクライアント側からの失効のニーズが高いと思われます。クライアント側からの失効のためには「logoutエンドポイント」「token revocationエンドポイント(Keycloak 10.0以降で利用可)」の2つのインタフェースが用意されています。これらのエンドポイントにリフレッシュトークンを付与してリクエストすると、紐づくセッションが消去され、関連するアクセストークン・リフレッシュトークンすべてが失効します。

logoutとtoken revocationエンドポイントには、表2のような違いがあります。本来は、標準に準拠しておりアプリ単位で失効できるtoken revocationエンドポイントが推奨されますが、Keycloak 10.0以降でしか対応していません。記事執筆時点で使われることが多いKeycloak 9.0系ではlogoutエンドポイントを使わざるを得ないため、logoutエンドポイントでは複数のアプリに対してトークンが発行されている場合はすべて失効するという点に注意が必要です。

表2:トークン失効のためのエンドポイント

種類標準準拠失効範囲
logoutエンドポイント独自ユーザに紐づくセッションすべて。
例:一人のユーザが複数種類の外部アプリを利用し、アプリにトークン発行されている場合、全アプ リに発行されたトークン失効
token revocationエンドポイント
(Keycloak 10.0以降で利用可)
RFC700 9ユーザとクライアントの組に紐づくセッションのみ。
例:一人のユーザが複数種 類の外部アプリを使っており、アプリにトークン発行されている場合、token revocationエンドポイ ントを呼んだアプリに発行されたトークンのみ失効

また、共通して重要なのは、これらのエンドポイントを呼んでもトークンが失効したことを知っているのは、Keycloakのみとなる点です。したがって、アクセストークンを受け取ったAPIサーバにとってみれば、Keycloakにトークンの有効・無効を聞きにいかないと、その失効を知ることができません。

有効・無効を聞きに行くために用意されているのが、RFC 7662で定められた「Token introspection エンドポイント」です(図8)。APIサーバは、アクセストークンを受け付けた際に、Keycloakのtoken introspectionエンドポイントをコールし、その結果(activeフィールドのtrue or false)を見ることで、アクセストークンが有効なものであるかを知ることができます。

図8:Token Introspectionでトークン失効を検知

図8:Token Introspectionでトークン失効を検知

ここで全APIにそれぞれこのような処理を実装していくことが煩雑であるため、図5②でも示したAPIゲートウェイでのトークンのチェックの中で処理を行うことが多いです。より具体的には、図9のように、APIゲートウェイにて、Token Introspection処理を肩代わりし、アクセストークンが有効な場合にだけAPIサーバにリクエストが届くようになっています。

図9:APIゲートウェイにてAPIサーバの代わりにToken Introspectionを実施

図9:APIゲートウェイにてAPIサーバの代わりにToken Introspectionを実施

次回は、図5や図9の構成に基づいて、APIゲートウェイの例としてNGINXを採用し、API認可サーバとしてのKeycloakの構築と動作確認を行っていきます。

株式会社 日立製作所

SELinuxから始まりOSSコミュニティ活動を長年行っている。近年は、OSSソリューションセンタにおいて、Keycloakのアップストリーム活動と関連ビジネスを立上げるなど、OSS戦略を推進中。また、The Linux Foundationのボードとして、日本国内のOSSコントリビューションの盛り上げに挑戦中。

Cloud Native Community Japanの設立発起人、OSSセキュリティ技術の会会長。博士(工学)。

連載バックナンバー

運用・管理技術解説
第7回

コンテナ上のマイクロサービスの認証強化 ~StrimziとKeycloak~

2021/2/16
前回に引き続き、マイクロサービスの認証強化を実現する最先端の機能を紹介します。
運用・管理技術解説
第6回

コンテナ上のマイクロサービスの認証強化 ~QuarkusとKeycloak~

2021/1/19
連載6回目となる今回は、マイクロサービスの認証強化を実現する最先端の機能を紹介します。
セキュリティ技術解説
第5回

コンテナ上のマイクロサービスの認証強化 ~IstioとKeycloak~

2020/12/15
連載5回目となる今回は、Istioを用いたマイクロサービスのシステムをKeycloakを用いて認証強化する手順を紹介します。

Think ITメルマガ会員登録受付中

Think ITでは、技術情報が詰まったメールマガジン「Think IT Weekly」の配信サービスを提供しています。メルマガ会員登録を済ませれば、メルマガだけでなく、さまざまな限定特典を入手できるようになります。

Think ITメルマガ会員のサービス内容を見る

他にもこの記事が読まれています