SaaS on AWS における認証認可の実装パターンとは ?
SaaS on AWS を成功に導くためのポイントとは ? 第 4 回
櫻谷 広人
こんにちは、パートナーソリューションアーキテクトの櫻谷です。
SaaS on AWS の連載第 4 回目、今回のテーマは「認証・認可」です。前回、前々回の 2 回にわたって、テナント分離のお話をしてきましたが、その中でテナント分離を行う目的に関してこんな記載がありました。
認証とは、その操作を行なっている人が「誰」であるか、確かにその本人であるということを証明するための仕組みです。(中略)
認可については 2 つのスコープに分けることができます。特定のテナント内の認可と、複数テナントをまたがったクロステナントでの認可です。
SaaS には「テナント」という概念があります。そのため、アクセスしてきているユーザーが誰であるかということに加えて、そのユーザーはどのテナントに所属しているのか、という点を検証することが重要になります。では、この情報はどこに保存し、どのように検証するのが適切でしょうか ?
今回はそのあたりを中心に SaaS におけるアイデンティティ管理について考えてみましょう。
この連載記事のその他の記事はこちら
- 選択
- 第 1 回 SaaS on AWS を成功に導くためのポイントとは ?
- 第 2 回 SaaS ビジネスの成否を分けるテナント分離戦略
- 第 3 回 動的なポリシー生成を使ったテナント分離
- 第 4 回 SaaS on AWS における認証認可の実装パターンとは ?
- 第 5 回 SaaS におけるオンボーディングとは ?
- 第 6 回 SaaS におけるデータパーティショニング設計の勘所
- 第 7 回 SaaS におけるメトリクスの取得と可視化
- 第 8 回 マルチテナントアーキテクチャのコスト分析
- 第 9 回 SaaS における料金プランとメータリング、ビリング
- 最終回 AWS と始める SaaS 化への道
SaaS における "アイデンティティ" とは
システムにおけるアイデンティティとは一般に、そのユーザーが誰であるかということを識別するための情報になりますが、SaaS においては、そのユーザーがどのテナントに属しているかまで識別する必要があります。というのも、テナント分離の回で見たように、認可のレイヤーではデータストレージなどのどのリソースに誰がアクセスできるかはテナント単位で決まってくるからです。
もちろんある特定のテナント内部でも、ユーザーのロールや所属する事業部に応じてアクセスできる範囲がさらに絞り込まれる可能性はありますが、まずこのテナント単位での識別ができなければ、他のテナントのデータが読み書きできてしまうクロステナントアクセスのリスクが発生します。
そのため、SaaS におけるアイデンティティは、ユーザー固有の情報 (ex. 名前、ロール、所属する事業など) とそのユーザーが所属するテナントの情報 (ex. 会社名、テナントが契約しているプランなど) から構成される形になります。
各種アイデンティティプロバイダー (IdP) やデータベースなどに散らばるこれらの情報を一元的に管理することができれば、複雑化しがちな認証・認可の実装のコストの軽減や、パフォーマンスの向上につなげることができますが、これはどのように実現することができるでしょうか ?
まずはコンセプトから見ていきましょう。
テナントコンテキストの伝達
リクエストの送信元のユーザーがどのテナントに所属しているのか、そのテナントが契約しているプランは何か、そういったテナントにまつわる情報、今後はテナントコンテキストという呼び方をしますが、これを先に述べたような一元的な SaaS Identity として管理し、受け渡すやり方にはどのようなものがあるでしょうか ?
実はこれ、前回 の連載でも簡単にご紹介しているのですが、一つは JSON Web Token (JWT) を用いる方法があります。JWT とは、簡単に説明すると、クレームと呼ばれる属性情報を二者間で安全に受け渡しするための JSON ベースの形式について規定した仕組みのことで、RFC7519 としてオープン標準になっています。
この JWT を使った仕組みがどのように動作するかというと、まずユーザーの認証時に、所属するテナントの識別子 (ex. 一意のテナント ID) をカスタムクレームとして JWT に含め、クライアントに返却します。クライアント側は、毎回のリクエストでこの JWT を HTTP リクエストのヘッダーに含め、サーバー側に送信します。そしてサーバー側は必要に応じてトークンの検証を行い、パースして中身のクレームを取り出しテナント ID からテナントを識別するという流れになります。
また、バックエンドがマイクロサービスで構築されている場合、マイクロサービス間のリクエストでもこの JWT を引き渡す形がおすすめです。
毎回データベースにクエリを行なってユーザーがどのテナントに所属しているかを問い合わせると、データベースの負荷やレイテンシの増加につながり、ユーザーエクスペリエンスを損なう恐れがあります。JWT の検証、パース、テナントごとのアクセスポリシーの反映といった一連の認証・認可の流れは、個別のサービスまたは共通ライブラリとして実装することをおすすめします。
こちらの図では Token manager がその役割を担っています。サービスが成長し開発チームが増えてくると、テナントを意識した認証・認可の実装漏れや、標準化されていない方法での実装が入り込む可能性が高くなります。生産性の低下にもつながる恐れがあるので、テナントごとの認証・認可の仕組みを各開発者に意識させずに、ライブラリを呼び出すだけ、あるいはマイクロサービスにリクエストを送れば良いだけといった設計にしましょう。
また、このテナントコンテキストはログやメトリクス、メータリングにおいても活用できます。ログやメトリクスにテナントIDを埋め込むことによって、テナントごとの利用傾向の可視化や障害時の調査に役立てることができるのですが、これについては以降の連載の運用や分析の回でも取り上げますのでお楽しみに !
Amazon Cognito を使った実装方法
ここからは上で紹介した仕組みについて具体的な実装方法を見ていきましょう。
どの IdP を使うかによってそれぞれ異なる部分がありますが、今回は Amazon Cognito を例に考えていきます。Amazon Cognito は、独自のユーザーディレクトリを持ち、AWS Identity and Access Management (IAM) と組み合わせることで AWS リソースへのアクセス権限を管理することもできる認証・認可の機能を提供するサービスです。ソーシャルサインインや OpenID Connect (OIDC), SAML 準拠の IdP とのフェデレーションもサポートしています。
まずはユーザープールを作成します。これは Cognito のユーザーディレクトリで、ユーザーの管理、パスワードポリシーや MFA 、フェデレーションの設定などを行うことができます。
SaaS においては、このユーザープールをシングルテナントにするかマルチテナントにするかという検討事項があります。それぞれトレードオフがありますが、テナント分離の回で見たように、AWSリソースへのアクセスポリシーを細かく制御する必要がある、またはパスワードポリシーや MFA の設定をテナントごとに柔軟に変えたいというような要件がある場合は、テナントごとに個別のユーザープールを作成することをおすすめします。
ただしこの場合、認証リクエストが来た際にどのユーザープールに対して認証を行うかを判断する必要が出てきます。一つの方法としては、メールアドレスのドメインとそのテナントのユーザープールの対応表を Amazon DynamoDB のようなデータベースに保存しておき、リクエストの内容を見てどのユーザープールを使うのか判断するという方法が考えられます。
また、この方法は複数の IdP を用いる際も有用で、どの IdP を使うか前段でルーティングを行うことで、あるテナントでは Cognito、別のテナントではサードパーティの Auth0 を使うといった構成が可能になります。これは特に BtoB でよくあるケースですが、SaaS 利用者がすでに社内で利用している IdP があってそれをそのまま使いたいというようなケースでユーザーの要望に応えることができます。
下の図では、テナント 1 およびテナント 2 がオンプレミスで管理しているユーザーディレクトリを、他のテナントでは Amazon Cognito をアイデンティティストアとして利用するハイブリッドな構成例を示しています。Authentication manager がどのテナントがどの認証方法を用いるかを管理している Tenant configuration に問い合わせを行い、その設定に応じて認証とトークンの受け渡し処理を行います。
さて、次に Cognito によるトークンの取り扱いについて見ていきます。
ユーザープールに対してユーザーがメールアドレス、電話番号、パスワードなど (何を用いるかはユーザープールの設定による) で認証を行うと、成功時に 3 つのトークンが返却されます。OIDC オープン標準によって定義されている ID トークン、アクセストークン、リフレッシュトークンの 3 種類です。各トークンの詳細については こちらのドキュメント をご覧ください。
トークンにはそれぞれ OIDC で規定されているクレームがデフォルトで含まれていますが、ユーザープールの設定でカスタム属性を追加することができるので、テナント ID など使用する属性をあらかじめ設定しておきます (カスタム属性には、常に custom: プレフィックスが付与されます)。ユーザーのサインアップ時にはそれらの属性を含めてユーザーを登録します。
JWT の復号化と検証にはライブラリを使うことをおすすめします。
ID トークンとアクセストークンはそれぞれ異なる鍵で署名されていますが、Amazon Cognito SDK、Mobile SDK for iOS、Mobile SDK for Android を利用すると実装の手間を減らすことができます。
JWT の検証の詳細については JSON Web トークンの検証 をご覧ください。
まとめ
いかがでしたでしょうか ?
マルチテナント SaaS においては、顧客のデータを保護するために特にセキュリティに関して気を配る必要がありますが、標準化された手段やマネージドサービスをうまく活用してリスクや実装の手間を削減していただければと思います。
次回の予定は「オンボーディング」です。テナントの登録、ユーザーの発行、インフラストラクチャのプロビジョニングなど、顧客が SaaS を契約してから利用できるようになるまでに、やらなければならないことはたくさんあります。このリードタイムの短さ、理想を言えば完全にセルフサービスで利用できることが SaaS のメリットの一つですが、これはどのように検討することができるでしょうか ?
ぜひ次回の連載もお楽しみに !
この連載記事のその他の記事はこちら
- 選択
- 第 1 回 SaaS on AWS を成功に導くためのポイントとは ?
- 第 2 回 SaaS ビジネスの成否を分けるテナント分離戦略
- 第 3 回 動的なポリシー生成を使ったテナント分離
- 第 4 回 SaaS on AWS における認証認可の実装パターンとは ?
- 第 5 回 SaaS におけるオンボーディングとは ?
- 第 6 回 SaaS におけるデータパーティショニング設計の勘所
- 第 7 回 SaaS におけるメトリクスの取得と可視化
- 第 8 回 マルチテナントアーキテクチャのコスト分析
- 第 9 回 SaaS における料金プランとメータリング、ビリング
- 最終回 AWS と始める SaaS 化への道
プロフィール
櫻谷 広人
アマゾン ウェブ サービス ジャパン合同会社
パートナーソリューションアーキテクト
大学 4 年から独学でプログラミングを習得。新卒で SIer に入社して Web アプリケーションの受託開発案件を中心にバックエンドエンジニアとして働いた後、フリーランスとして複数のスタートアップで開発を支援。その後、toC 向けのアプリを提供するスタートアップで執行役員 CTO を務める。現在は SaaS 担当のパートナーソリューションアーキテクトとして、主に ISV のお客様の SaaS 移行を支援。
AWS を無料でお試しいただけます