Oracle Cloud Hangout Cafe Season4 #4「マイクロサービスの認証・認可とJWT」(2021年7月7日開催)
はじめに
「Oracle Cloud Hangout Cafe」(通称「おちゃかふぇ」/以降、OCHaCafe)は、日本オラクルが主催するコミュニティの1つです。定期的に、開発者・エンジニアに向けたクラウドネイティブな時代に身につけておくべきテクノロジーを深堀する勉強会を開催しています。
連載第2回の今回は、2021年7月7日に開催された「Oracle Cloud Hangout Cafe Season4 #4『マイクロサービスの認証・認可と JWT』」の発表内容に基づいて紹介していきます。
この回では、JWT Propagationを理解するために必要な、JWT周り(JOSE)、OAuth 2.0/OpenID Connect 1.0を復習した後に、デモを交えながらMP-JWTについて解説しました。
アジェンダ
今回は、以下アジェンダの流れに従って解説します。一部、内容を割愛しているため、詳細は本編を参照ください。
- 認証・認可のおさらい
- JSON Web Token(JWT)とその周辺仕様
- OAuth 2.0/OpenID Connect 1.0
- Java で実現するマイクロサービスの認証・認可
- MicroProfile - JWT Propagation
発表資料と動画については、下記のリンクを参照してください。
【資料リンク】
【動画リンク】
認証・認可のおさらい
そもそも認証・認可とは?
はじめに、認証と認可についておさらいします。混同しがちな概念なので、しっかりと復習しましょう。
認証とは、ID/パスワードに代表される情報を用いてユーザー/システムの本人性を検証することです。以下の3要素のうち、1つ以上を用いて行なわれます。
- 記憶: What you know
- 所有: What you have
- 生体: What you are
認可とは、ユーザー/システムに対して特定の処理を行うことを許可することです。
一般的に広く使われている認証の方式
特に、マイクロサービス・アーキテクチャの文脈ではJSON Web Token(JWT)という、自己完結型のトークンを用いた認証方式が広く使われています。使われている理由としては、以下のようなことが考えられます。
- JSON Web Tokenを用いたID連携のための標準プロトコルが存在する(= OpenID Connect 1.0)
- コンパクトで自己完結型の表現方法がマイクロサービス・アーキテクチャと相性が良い
- 自己完結型のトークンを用いることで、認証を担うサービスとその他のサービス間を疎結合に保つことができる
- 通信全体のトラフィック量の削減が期待できる
一般的なフローとしては、下図のようになります。
アクセス制御の基本方針(DAC、MAC、RBAC、ABAC)
アクセス制御の基本方針(DAC、MAC、RBAC、ABAC)について解説します。
DACはDiscretionary Access Controlの略で、任意アクセス制御とも呼ばれる方式です。オブジェクトの所有者(Subject)が対象(Object)に対する権限を設定するような方式で、LinuxやUNIXにおけるファイルに対するアクセス制御で標準的に使用されます。
MACはMandatory Access Controlの略で、強制アクセス制御とも呼ばれる方式です。操作の主体(Subject)と操作の対象(Object)に対して、それぞれレベルを設定し、そのレベルを比較することでルールに従ったアクセス権限を強制的に設定する方式です。
例えば、上図のように操作主体(User A)と操作対象にレベルが設定されており、アクセス権限に関するルールが設定されているとします。このとき、各Levelに対して許可される操作は以下のようになります。
- Level 1 の操作対象: 書き込みのみ OK
- Subject Level >= Object Level のため、書き込み OK のルールが適用される
- Level 2 の操作対象: 読み込み、書き込み OK
- Subject Level = Object Level のため、両ルール(書き込み、読み込みを許可するルール)が適用される
- Level 3 の操作対象: 読み込みのみ OK
- Subject Level <= Object Level のため、読み込み OK のルールが適用される
RBACはRole Based Access Controlの略で、操作の主体(Subject)をロールに割り当て、そのロールに基づいて操作の対象(Object)に対するアクセス制御をする方式です。
例えば、上図のようにAdmin、Guestロールを作成します。Role: AdminにはRead/Writeができる権限が割り当てられており、Role: GuestにはRead できる権限が割り当てられています。そして、User AにはRole: Adminを、User BにはRole: Guestを割り当てます。このとき、各ユーザーが操作対象(Object)に対して可能な操作は以下のようになります。
- User A: Read and Write
- Role: Admin が割り当てられているため
- User B: Read
- Role: Guest が割り当てられているため
ABACはAttribute Based Access Controlの略で、操作の主体(Subject)に対して付与された様々な属性(Attribute)によってアクセス制御を実現する方式です。
例えば、上図のようにUser Aには部署: 開発と階級: 一般という属性が付与されており、User Bには、部署: マーケティングと階級: マネージャーという属性が付与されています。このとき、操作の対象(Object)に対して“マーケティング部のマネージャー以上の階級で閲覧(Read)可能”というルールを作成した場合、User Bのみが閲覧可能となります。
以上がアクセス制御の基本方針(DAC、MAC、RBAC、ABAC)です。本稿での認可制御は、RBACを中心に扱います。
JSON Web Token(JWT)とその周辺仕様
ここからは、JSON Web Token(JWT)とその周辺仕様に関して、MP-JWT(MicroProfile JWT Propagationで用いられるJWTの形式)を理解するために最低限押さえておきたいことを説明します。各仕様にはRFCのリンク先を併記しているため、より詳細な情報が知りたい場合はそちらを参照してください。
JSON Web Token
JSON Web Tokenは、JOSE(JavaScript Object Signing and Encryption)と呼ばれる仕様群の1つです。スペースに制約のある環境(HTTP Header、URLなど)を想定したコンパクトなクレーム(属性情報)の表現方法であり、以下のように表現されます。
- JSON を URL-safe な形でエンコードする
- 各クレームは、コンパクトにするという目的で省略形が使われることが多い
- ssuer -> iss
- audience -> aud
- etc.
余談ですが、JWTはRFC 7519で、jot(ジョット)と発音することが推奨されています。
JOSEと関連仕様
JOSEとその関連仕様を紹介します。JOSEはJavaScript Object Signing and Encryptionの略称で、当事者間でクレームを安全に転送する方法を提供することを目的にしたフレームワークです。この目的を満たすために、いくつかの仕様群が提供されています。
- JWS(JSON Web Signature): RFC 7515
- 署名されたコンテンツを JSON データ構造で表現するための仕様
- JWE(JSON Web Encryption): RFC 7516
- 暗号化されたコンテンツを JSON データ構造で表現するための仕様
- JWK(JSON Web Key): RFC 7517
- 暗号鍵を JSON データ構造で表現するための仕様
- JWA(JSON Web Algorithms): RFC 7518
- 暗号化や署名の作成に用いる暗号アルゴリズムを定義した仕様
- JWT(JSON Web Token): RFC 7519
- スペースに制約のある環境(HTTP Header、URLなど)を想定したコンパクトなクレーム(属性情報)の表現方法を定義した仕様
詳細は本編で触れています。詳しく知りたい場合は、発表資料と動画から参照ください。
OAuth 2.0/OpenID Connect 1.0
ここからはOAuth 2.0/OpenID Connect 1.0に関して、MP-JWT(MicroProfile JWT Propagationで用いられるJWTの形式)を理解するために最低限押さえておきたいことを説明します。各仕様にはリンク先を併記しているため、より詳細な情報が知りたい場合はそちらを参照してください。
OAuth 2.0
OAuth 2.0の概要
OAuth 2.0は権限委譲/認可情報を扱うプロトコルで、RFC 6749に規定されています(日本語訳がOpenID Foundation Japanから出ているので、こちらを読むことを推奨します)。よく勘違いされてきましたが、認証のためのプロトコルではありません。実際の例を見てみましょう。
これは、OAuth 2.0の典型的なユースケースです。写真アプリ(例ではInstagram)に投稿すると連携され、他SNS(例ではFacebook)にも投稿がされる…といったシーンを見たことがあるのではないでしょうか。
この際に、写真アプリ(Instagram)からHTTPサービス(Facebook)に対する限定的なアクセス(写真を投稿する、など)を可能にするフレームワークがOAuth 2.0です。後ほど、きちんとしたシーケンスで整理するので、ここでは簡易的に処理の流れを見てみましょう。
- 写真アプリ(Instagram)に画像の投稿を行う
- 写真アプリ(Instagram)が認可サーバー(Facebook)に対して、Facebook へのアクセス権を要求する
- 認可サーバー(Facebook)は“Facebook へのアクセス権を Instagram に委譲すること”についてユーザーの合意を求める
- ユーザーが合意する
- 認可サーバー(Facebook)は、権限が委譲された証明として、アクセストークンを発行し、Instagram へ渡す
- 写真アプリ(Instagram)は、発行されたアクセストークンを持って他 SNS(Facebook)の API にアクセスする
- 他 SNS(Facebook)でアクセストークンの有効性を確認し、問題なければ当該 API の実行結果を返却する
OAuth 2.0のアクター(登場人物)
OAuth 2.0で出てくるアクターを整理します。下図は、前述したOAuth 2.0の概要で紹介した例を一般的にしたものです。
各名称と役割を以下に記します。XXX(YYY)のように表記した場合は、XXX: 一般的な名称、YYY: 具体例中に出てきた名前とします。
- リソースオーナー(Instagram のユーザー)
- リソース(連携投稿する写真等)の所有者を指します
- リソースサーバー(Facebook API)
- リソースに対する API を提供します
- クライアント(Instagram)
- リソースサーバーを利用するアプリケーションを指します
- 認可サーバー(Facebook)
- クライアントに対するアクセス権(=アクセストークン)を発行するサーバーを指します
アクセストークン
アクセストークンに関して簡単に整理します。アクセストークンとは、ひと言でいうと保護されたリソースにクライアントがアクセスするために必要な資格情報のことです。多くの場合はBearerトークン*1のため、ビルの入館カードや電車の切符に例えられます(e.g:所持している本人性は問わないため、その辺りに落ちている入館カードでもビルの特定エリアに入れてしまう)。
*1:セキュリティトークンのうちその利用可否が「トークンの所有」のみで決定されるもの
発行先はリソースサーバーと定められていますが、実装方法はRFC 6479では定められていません。大別すると、以下の 2(3)種類に分類されます。
- identifier(識別子型)
- self-contain(内包型)
識別子型とは、認可サーバー内に存在するアクセス権限に関する詳細情報を参照するための識別子をアクセストークンとして払い出す方式のことです。実際にトークンを検証する際はOAuth 2.0トークンイントロスペクションというアクセストークンを認可サーバーの特定のエンドポイントへ送信し、その妥当性を認可サーバーに検証してもらう方式がよく使われます。
一方、内包型はその名前の通り、アクセストークンとして検証に必要な情報を内包した形で払い出され、リソースサーバー自体で検証が行なわれます。この際に、コンパクトなクレームの表現方法であるJWTが使用されることが多いです。
また、識別子型と内包型のハイブリッド型も存在します。これはアクセストークンとしては内包型の形式を取りますが、さらに付随する情報はアクセストークン内に含まれる識別子を用いて参照させるような方式です。
スコープ
次に、スコープについて説明します。スコープは、アクセストークンに紐づくアクセス権を細かく制御するための仕様です。アクセストークンに紐づけたいスコープは、クライアントから認可サーバーへリクエストを送信する際に指定します(※後述)。
例えば、上図のようにアクセストークンとしてreadというスコープが紐づけられているとします。このとき、readというスコープを要求するリソースサーバーのエンドポイントにはAPIの実行を許可、writeというスコープを要求するエンドポイントにはAPIの実行を拒否する、といった形で実装することで、エンドポイントに対する細かなアクセス制御を行うことができます。