このビデオは、2018 年 7 月 24 日に開催された Financial APIs Workshop 2018 のプレゼンテーション録画のひとつです。 OAuth 基盤構築における従来のアプローチと Authlete 独自の Semi-hosted アプローチとの比較、Authlete が FAPI を実装するにあたってどのようにクライアント認証機能の拡張や相互 TLS の対応を行なったかについて、 Authlete の Justin Richer がお話しします。
プレゼンテーション資料は https://www.slideshare.net/fintechlabs-io/authlete-fapi-implementation-part-1 からダウンロード可能です。
Justin: みなさん、こんにちは。 私の名前は Justin Richer です。 これまで 1 年ほど、Authlete と仕事をしてきました。
最近取り組んでいるプロジェクトの一つは、FAPI プロトコルをサポートするために、認可サーバーである Authlete サーバーを強化することです。
Authlete のシステムは、他の多くの実装とはかなり異なります。そこで、まず始めに、Authleteシステムがどのように機能するかについて、少し説明します。
OAuth を実装しようとするとき、これまでは主に 2 つの選択肢がありました。 ひとつは、すべてをオンプレミスで構築することです。そうすることで、すべてをセキュリティドメイン内に配置できます。 以前とは違い、最近のオンプレミスは管理下のクラウド等にあるかもしれませんが、 実際のところ、これはすべてあなたのコントロール内にあるということです。認可サーバー、リソースサーバー、およびすべてのユーザーアカウントが一緒になっています。
実のところ、OAuth はこのモデルに合致するものでした。これが、OAuth が生み出された当時のモデルなのです。つまり、すべてのスタックが管理下にあり、何がどこにあるか把握している環境です。
しかし最近では、サービスとして利用できるものが多くあります。様々なプロバイダーが提供する、サービスとしての OAuth を利用することができます。
数多くの会社が存在し、サービスを提供してくれています。認可サーバーを運用するのは基本的には彼らです。そのため、利用する際にはエンドユーザーを彼らのサイトに送り、そこで認証し、そして、トークンを取得してもらいます。その取得したトークンを使って、API を利用することとなります。
他に選択肢はないのでしょうか? これら従来のふたつのアプローチには、メリットもデメリットも存在するのです。
とくに人々を悩ませるのは、クラウドにホストされているサービスを使うパターンです。自身のユーザーを彼らのサイトに送り込み、ユーザーのクレデンシャルも彼らに渡すことになります。
Authlete のアプローチは「semi-hosted アプローチ」です。それは、OAuth 準拠のシステムを構築するための、API を提供するというモデルです。
言い換えると、あなたの管理するソフトウェアが、その API をコールするというかたちです。OAuth 処理をコントロールするのはあなたのソフトウェアですが、そのソフトウェアが Authlete の API をコールし、次に何をすべきか、API から指示をもらいます。
この話が、なぜ FAPI の領域と関係があるのでしょうか?
Semi-hosted アプローチでは、クラウド上でホストされたサービスの場合と同様、新しい機能を Authlete が自社の API に追加できます。そして Authlete API を使ってシステムを構築している人は、その追加機能を利用できるようになります。何ら変更なしにです。
ひとつの良い例が、モバイルアプリ用に策定された PKCE を Authlete がサポートしたケースです。弊社のお客さまは、突然、その機能を使えるようになりました。クライアントから受け取った code_challenge
や code_verifer
を含むリクエストを Authlete API に送るだけで、システムを何ら変更することなく、PKCE をサポートできるようになったのです。
なぜなら、Authlete の API が、それら新しいパラメーターをどう処理すべきか、すべて指示してくれるからです。
FAPI の場合はどうでしょうか? FAPI と Open Banking は、近い将来に統合される予定です。 どちらも、Authlete サーバーが当初サポートしていなかったいくつかの異なる要件を追加します。
より高度なクライアント認証モデル。相互 TLS クライアント証明書への対応。
read のリクエストと read/write のリクエスト、また潜在的には他の API とプロファイルをどのように処理するかを知るための、スコープ管理。さらにリクエストオブジェクトの処理もあります。
最初の2つをどのように実装したかについて、少しお話しします。 そして、Hide が、2 番目の 2 つのトピックについて話し、このプレゼンテーションの後半を締めくくります。
まず、以前の Authlete では、次のようにクライアント認証を処理していました。
Authlete をご利用のお客さまは、管理コンソールなどを介して Authlete API を利用します。そして(その API を介して)クライアントを登録し、シークレットを含むクライアント構成を取得します。そして、彼らはその情報をクライアントに提供します。
クライアントは OAuth トランザクション中に、それを認可サーバー (AS) に提示します。 このとき認可サーバーは、そのシークレットについて何をすればいいかわかりません。これはすべて顧客のシステムで実行されていることに注意してください。認可サーバーは、実際にはクライアントシークレットについて何も知りません。そこで Authlete API に、「このクライアントシークレットは問題ないか?」と尋ねます。 ここでのクライアントシークレットは「共有シークレット」です。
このモデルは非常に有効です。認可サーバーの開発者にとっては、実装がとてもシンプルになります。 このようなモデルをデプロイしたら、Authlete API にこう尋ねればいいわけです。「リクエストを受け取りました。次は何をすればいいですか?」
このようなしくみであるため、ローテーションを行いたい場合、より厳密なクライアントシークレットなどを強制したい場合には、Authlete API を呼び出すだけでそれが可能となります。認可サーバー側には、コード変更の必要がなくなる、というメリットがもたらされます。
これは素晴らしい形式だと言えるでしょう。しかしこの時点では、Authlete はクライアントシークレットしか扱えなかったため、Authlete を使って構築されたすべての認可サーバーもまた、クライアントシークレットしか扱えませんでした。 ただし、そのこと自体はさほど驚きではありません。 クライアントシークレットは、OAuth クライアントが認可サーバーに対して認証するための最も一般的な方法です。世の中に存在する他の認可サーバーでも、これが通常のクライアント認証のやり方です。他の多くの OAuth 実装がこのように認証することは非常に理にかなっています。
しかしながら、FAPI や Open Banking をサポートするためには、さらにやるべきことがあります。
我々はいろいろなことを解決しなければなりませんでした。認可サーバーからの API コールに対して、パブリッククライアントの場合、クライアントシークレットの場合、共通鍵で署名された JWT の場合、非対称暗号方式で署名された JWT の場合、相互 TLS で自己署名証明書または PKI の場合、それぞれどのように処理するのか。
ここからが面白いところです。
Authlete API にこれらを実装しようとしたとき、相当のリエンジニアリングが必要になりました。Authlete API 側で、これらのさまざまなメソッドをすべてサポートする方法を見つけ出し,すべてのキーが適切な場所に登録されていることの確認と、すべてのセキュリティチェックを行うようにしたのです。
そして Authlete API を呼び出しているすべての外部システムに対し、これを容易に使用できるようにしました。
Authlete API に処理を任せるために、認可サーバーはクライアント認証に関するすべての情報を送信する必要があります。これは OAuth のトランザクションであるため、認可サーバーはこれまで通り、Authorization
ヘッダーの値と、トークンエンドポイントにポストされたパラメーターのリストを送信し、次に何をすべきか、指示をもらいます。
つまり、Authlete API に接続されているすべての認可サーバーにおいては、この新しい機能が利用可能になったら、管理者は新たなクライアント認証に対応したクライアントを登録するだけでよいのです。あるクライアントは共通鍵または公開鍵を使うでしょうし、別のクライアントは相互 TLS を用いるでしょう。
これを行う際に認可サーバーがすべきことは、これまで同様、クライアントから受け取ったリクエスト全体を Authlete API に渡し、「このクライアントの場合、正しい鍵と署名検証方式は何ですか? このリクエストは有効ですか? クライアントはこのすべてを行うことができますか?」 と聞くだけです。
そしてこれを実現するためには、Authlete API 側ではいろいろなリエンジニアリングを行う必要がありました。そしてその結果、Authlete API を呼び出すお客さまの認可サーバー側では、スムーズな利用が可能となったのです。
次は、相互 TLS に関する話題です。
Authlete のモデルにおける相互 TLS のしくみは非常に変わっています。
まずは、相互 TLS がどのように動作すべきか知る必要があります。TLS の仕様と、TLS について書かれた多くのドキュメントを読むことになるでしょう。
TLS は基本的に、あるコンピューターが別のコンピューターに接続する際、接続相手のコンピューターの先にはルートとなる認証局があって、そのルート証明書を用いてコンピューターの証明書を検証し、正しい当事者であることを確認して、処理を進めるというものです。
これが、TLS が想定している動きです。
いま一度、Authlete のモデルを思い出してください。認可サーバーは Authlete API と通信することになります。Authlete モデルでは、そうご TLS をどのように取り扱っているのでしょう?
クライアントは認可サーバーに対して相互 TLS 認証を実行します。すると認可サーバーは Authlete API に対して、「クライアントからの通信の中に証明書があったんだけど。これを渡すから、あとはよろしく」と言うことになります。
そして Authlete API は、認可サーバーにとっての認証局として機能します。Authlete は「このコンテキストにおいて、このクライアントがこの証明書を用いることは、適切かどうか」を確かめることになります。
ここからが、このモデルの面白いところです。
先にお話しした通り、TLS は 1 台のコンピューターが別のコンピューターと通信することを前提としています。 今日の環境では、クラウドサービス、マイクロサービス、Docker コンテナーなどがあります。そのような中、“コンピューター” とはどういう意味でしょうか?
あるシステムが別のシステムと通信するとしましょう。その過程では、TLS ターミネーター、リバースプロキシー、API ゲートウェイ、その他いろいろなスタックを通過している可能性があります。
TLS が当初意図していた、ポイント・ツー・ポイントの暗号化、相互の完全な認証と検証は、今日のコンピューターのデプロイメントモデルとは実際のところ一致しません。
Authlete API が行っていることとは、従来の TLS の観点にはないもので、一見すると奇妙に思えます。しかしわたしには、これは最近のコンピューターのデプロイ手法の進展に TLS が追いついていないのだと思えます。
お話ししたように、このリンク(クライアントと認可サーバーの間)では、相互 TLS の確立と、その TLS ソケットの検証を行います。
ただし、認可サーバーはクライアント証明書自体の認証は行いません。認可サーバーはどのようなクライアント証明書であっても受け付けます。そのクライアント証明書に誰が署名したかは気にしませんし、自己署名証明書であっても構いません。チェックすることすらありません。そのような確認処理はすべてオフにします。
認可サーバーが確認することは、そのクライアント証明書が TLS チャネルで使用されているものであるかどうかです。
そのクライアント証明書が、認可サーバーの信頼する CA によって署名されているかどうかなども、確認しません。それらすべての処理を Authlete API にオフロードします。
ここで、Authlete API 自身はこの TLS 接続の検証を行うことができません。検証するための情報が何もないからです。
これは正しく TLS の用途です。つまり、そのポイント・ツー・ポイント接続の外にいる人からは、その通信について何もわからないのです。
ひとつ言えるのは、その証明書について、実際に使われたものであると認可サーバーが表明するしないに関わらず、Authlete API はそのクライアントの種別を判定し、適切な権限を有しているか、正しくアカウントにひもづいているか、それらがこのトランザクションにおいて有効かを確認するということです。
PKI ベースの相互 TLS に登録されているクライアントの場合、Authlete API にルート証明書があるということになります。ここでクライアントが自己署名証明書を提示すると、Authlete API はそれをリジェクトし、認可サーバーに対しても、そのリクエストを拒否するよう指示します。このときの TLS 接続が認可サーバーにとっては適正であってもです。そして OAuth トランザクションは拒否されることになります。
マイクロサービスや API プロキシ、クラウドベースのプロバイダーの増加とともに、このモデルをわたしたちが目にする機会はますます増えています。 いずれにせよ、これこそが、TLS の実世界での使われかたとなっているのです。とても興味深いとわたしは感じています。
わたしたちがいま現在、どのように TLS と「信頼の源 (Root of Trust)」を認識し、そしてそれを、複数のピアからなるサービス全体でどのように適用するかの、ひとつの例なのです。