デプロイメントパターンについて

川崎貴彦氏:次はデプロイメントパターンの説明です。OAuthやOpenID Connect、認可サーバーやIdPを実装して配備する。みんな商用のときはそれを使っていると思いますが、いくつかのパターンに分けられるので、それを説明します。

よくあるのは、閉じたネットワークのオンプレミス環境を用意し、そこに物理サーバーを用意して任意の認可サーバーのソフトウェアの実装を入れて動かす。この認可サーバーのソフトは自分で取ってきて、オープンソースを実装します。これに、名前を付けるとするとOn-Premisesパターンです。

次にあるのがクラウドを利用する環境、Infrastructure as a Service。ここでそのクラウド環境でサーバーを用意してもらって、その中にこれは自分でインスタンスを立ててそこに自分の好きな認可サーバーのソフトウェアをぶち込んで運営する。これはサーバーがホストされている状態なので、Hosted Serverパターンと呼ぶ。これは自分で物理サーバーを運営しなくていいので楽になります。

もう1つのパターンは、Software as a Serviceで認可サーバーを提供しているものもあり、これもクラウドです。「あなたの認可サーバーは我々が全部管理しますよ」みたいな感じです。

この場合はユーザーの管理やユーザーの認証、同意画面とかは基本的にはクラウド側のサービスがもつことになり、これがHosted Serviceパターンです。それぞれ仕組みは違いますが、基本的にはユーザーのデータベースのデータとかを全部認可サーバー側に渡すことになります。

あとはユーザー認証の方法もカスタマイズできるんですけど、カスタマイズにも限界があるので、独自のユーザー認証を実施しているサービスにとっては使いづらいです。同意画面もカスタマイズできるものも多いですが、制限があるパターンも存在します。

これがよく知られている3つのパターンです。ただ、Justin Richerという人がいて、この人が「Deployment and Hosting Patterns in OAuth」というブログを書きました。このJustin Richerは、OAuthとOpenID Connect関連の仕様のライターとして業界でも有名な技術者です。彼は『OAuth 2 in Action』という本も書いているんですね。

この本は、Authlete社が監修していて『OAuth徹底入門』という名前で日本語訳としても発売されています。

OAuth徹底入門 セキュアな認可システムを適用するための原則と実践

このJustinがブログで「パターンは3つある」ということを言ったんです。On-Premises、Hosted Server、Hosted Service。最後に4番目にSemi-Hosted Serviceというパターンもあると言いました。 実はこれが弊社、Authleteのプロダクトのパターンです。

JustinがAuthleteのアーキテクチャを知ったときに、これは今まで見たことないパターンだなと気が付いて、僕に問い合わせをしてきて、「このパターンのネタでブログを書きたいんだがいいか?」と聞いてきて、どうぞとお願いをして、その結果彼が書いたのがこのブログです。

このSemi-Hosted Serviceパターンは何かというと、今の世の中にはクライアントアプリと認可サーバーがあって、認可サーバーがオンプレかクラウドかは別として、認可サーバーというのは仕様書に定義されたエンドポイントを実装します。実装してここのクライアントアプリとやり取りするという流れです。

Semi-Hosted ServiceパターンであるAuthleteは、認可サーバーそのものではありません。後ろにいて、認可サーバーを作るのに必要な機能を全部Web API化しました。認可サーバーの実装はAuthleteのAPIを呼び出すことで作っていくというパターンです。

Authlete社の競合他社が一生懸命に認可サーバーを作ってやっているんですけど、Authlete社はそこをやっていなくて裏で動く仕組みを作っています。このSemi-Hosted Serviceパターンで何が起こるかということで、Authlete以前とAuthlete以後です。

Authlete以前とAuthlete以後の動き

これは従来の場合におけるクライアントと認可サーバーの関係になります。認可サーバーはOAuthやOpenID Connectに準拠したエンドポイントを実装・公開していて、クライアントはそれとやりとりを行なう。

そういうわけなので、OAuth&OIDCのロジックとか、それに関連するデータ、アクセストークンやクライアントメタデータのデータベースもここにあり、かつこの認可サーバーというのはユーザー管理やユーザー認証もやらないといけないので、ユーザーのデータベースなども含んでいます。

AuthleteみたいなSemi-Hosted Serviceを使って何をするかというと、認可サーバーとクライアントの関係は今までと同様です。一方でAuthleteがあると、AuthleteがWeb APIを提供していて認可サーバーはこのAPIでやりとりをする。OAuthとかOpenID Connectとかののロジックとかアクセストークンとかは全部Authlete側がもつようになります。

一方で、フロントとなる認可サーバーにはユーザー認証とかユーザー管理の部分などが残るので、ここで分離される。認可サーバーの実装として、ユーザー情報のデータベースはAuthleteに渡す必要はありません。なのでOAuthとOpenID Connectの実装からユーザー管理とかユーザー認証を分離する仕組みです。

この仕組みで分離されるのはそれだけではなくて、API管理も、OAuth・OIDCの実装から分離します。例えばちょっと昔の図なんですけど、AmazonのAWS API Gatewayの図です。AWS API Gatewayは、クライアントがAPIに提示したアクセストークンの検証を外部に移譲する仕組みとして、Custom Authorizerというものを持っています。

ここにクライアントがあって、これがAPIにアクセスしてきて、そのリクエストにアクセストークンが含まれてきますが、そのアクセストークンの検証を外で行なうために、Custom Authorizerというのにそれを渡す。ここでアクセストークンの検証をやるんですけど、そのCustom Authorizerの実装の中からさらに外部の認可サーバーに作業を移譲することで、アクセストークンの検証を簡単に行なうことができます。

AuthleteみたいなOAuthやOpenID Connectの実装に特化したような裏で動くバックエンドサービスなら、こういう感じでCustom Authorizerを実装して問い合わせるだけで楽にできる。OAuthの仕組みとかをAPI Gatewayで実装しようとすることは、あまりいいデザインではないので、こういうふうにレイヤーを分けてやったほうがいいです。

でも、これはAPIの管理が分かれた例で、他にもこういうアーキテクチャでどんないいことが起こるかというと、資料を作る時間がなかったので僕のツイートをコピペしています。「MTLS、RFC 8705という、つい最近できてRFC化された仕様なんですけど、これはOAuth 2.0 Mutual-TLS Client Authentication and Certificate-Bound Access Tokensです」。

これはどこか僕のブログに書いてあるんですけど、これはトークンリクエストのときに使われたTLSコネクションがMutual-TLSの場合、クライアント証明書が含まれています。このクライアント証明書をただのTLSコネクションだけではなくて、他のOAuth的な文脈でも流用しましょうということです。

流用をするポイントが2つあって、クライアント認証にクライアント証明書を使う方式。あとはセキュリティ的に重要なんですけど発行するアクセストークンにそのクライアント証明書を紐づけておくという仕組みがあります。これはFinancial-grade APIでも重要なポイントです。

クライアント証明書の処理が絡みますが、そこをAPI Gatewayのレイヤーでやってしまうと本当にアーキテクチャ的にはよくない。ただ、Authleteはそこを分離して、そこの仕様もサポートしています。API Gatewayレイヤーから取り出したクライアント証明書をAuthleteのAPIに投げさえすればMTLS、RFC 705の仕様はAuthleteが自動で作業してくれるという感じです。

だからどんなAPI Gatewayの製品を使っていてもAuthleteと組み合わせるとMTLSが実装でき、よりセキュアにFinancial-grade APIの世界に入っていけます。なので、AmazonのAPI GatewayやAzureのAPI Management、それこそApigeeを使ってもいいです。

ついでに話すとApigeeは自分でいろいろコードを書けるんですけど、けっこう自分でいろいろ書かないとできないので、PKCEの実装は実はApigeeは直接は実装していません。ApigeeでPKCEを実装した人はApigeeを使っている人たちが自力でPKCEを実装している状況です。

でもApigeeを組み合わせてAuthleteを使っている場合は、そこら辺の実装もAuthleteに投げられるので、Apigeeは彼らの得意分野である、APIのトラフィックを分けたり統計を取る部分に使っている状況です。

実際にうちのお客さんもApigeeとAuthleteを組み合わせて使っているという人もいますし、ある銀行さんとかはApigeeじゃなくて他のGateway製品とかも、マイクロソフトのAzureとAuthleteを組み合わせて使っています。これがデプロイメントパターンです。

OAuth 2.0とAuthleteを組み合わせる

参考までにOAuth 2.0とAuthleteを組み合わせるとどういうフローになるのか。Authleteの背景にある哲学とは何かというと、エンドユーザー認証というのはいっぱいあります。ログインIDとパスワードで認証するもの、指紋認証や虹彩認証もあるし、multi-factor authenticationなど。ユーザー認証もいっぱいあるんだけど、いずれも最終的にはエンドユーザ一の一意識別子を特定する処理である、という割り切り方をしています。

そしてアクセストークンを格納するデータベーステーブルには、アクセストークンはどのユーザーがどのクライアントに何の権限を与えたとかの情報が入ってます。なのでアクセストークンテーブルというのはユーザ一の一意識別子と必ず紐づいている。赤で強調していますが、このユーザーがこのクライアントにこんな権限を与えました。「有効期限はこれです」というような情報がアクセストークンテーブルに入っています。

だからアクセストークンを作るときには、このユーザ一一意識別子がどうしても必要です。Authleteは、このエンドユーザ一一意識別子を外部から提供してもらうという仕組みになっています。だからAuthleteは内部では管理をしないし、Authlete自体はユーザーデータベースを持たない。

ちょっと複雑なんですけどAuthleteを交えてフローをやると、アプリが権限を求めてアプリが認可リクエストを投げる。これはRFCに従った認可リクエストです。認可サーバーがAuthleteを裏で使っていると何が起こるかというと、認可サーバーは受け取った認可リクエストをAuthleteに丸投げします。

そうするとAuthleteは認可リクエストの内容が正しいかどうか。例えばクライアントIDに含まれているけど「それって正しいIDなの? 」とか「存在するIDなのか? 」などをチェックして認可リクエストを解析します。結果、認可リクエストもこういう情報でした。「いい情報だったのでその続きを処理してください」というのをフロントの認可サーバーにお願いします。

ここで認可サーバーは認可画面を生成してユーザーに表示をして、ユーザーがOKを出す。「ユーザーがOKを出しました」というのが認可サーバーに返ってきます。ここで認可サーバーは、まだユーザーの認証が終わってなければ、ここでユーザー認証をするはずです。データベースがどこに保存されているかわからないけどユーザー認証の結果、ユーザーの一意識別子というのが取得できます。

その取得したユーザ一一意識別子を添えてAuthleteの応答生成APIを呼ぶ。例えば認可コードを作り、この認可コードをユーザーに紐づけて覚えておく。それで処理が全部うまくできました。Authleteはこういう応答をクライアントに返してくださいというのを認可サーバーに言います。認可サーバーはAuthleteが用意した応答をそのままクライアントに返せば認可コードが発行されることになる。

これがちゃんとその仕様に沿ったようになります。クライアントアプリケーションが認可コードをトークンエンドポイントに送信するんですけど、今度は認可サーバーのトークンエンドポイントというのは仕様通りです。トークンエンドポイントの実装は、またAuthleteにトークンエンドポイントの実装を丸投げします。

ここでMutual TLSのクライアント証明書が必要なら一緒に渡したりすることも可能です。ここでAuthleteはアクセストークンを生成してクライアント返すべき応答を用意して認可サーバーに投げる。認可サーバーはAuthleteが用意した応答をクライアントに返す。それでアクセストークンが結果的に発行されて、これも仕様書通りに実装されるという感じになります。

ちょっと複雑なフローになっていますが、これがAuthleteの仕組みです。これは認可コードフロー+Authleteなんですけど、他のフローもいろいろありますが、これは飛ばしてあとで資料をアップロードするので見ていただければと思います。

こんな感じで……これはリソースオーナー・パスワード・クレデンシャルズフローでユーザー認証が絡む。やっぱりそこはAuthleteでは極力やらず、認可サーバー側でやってもらうという仕組みになってます。クライアント・クレデンシャルズフロー、リフレッシュトークンフローも、こんな感じでAuthleteを使うと実装できます。

今日は以上で勉強会は終わりです。ご清聴ありがとうございました。