マルチテナント SaaS アプリケーションの認証を Amazon Cognito で実現してみよう !

2023-01-05
ビジネス x クラウド

柴田 龍平

こんにちは ! ソリューションアーキテクトの柴田です。

皆さんはマルチテナントアプリケーションを開発されたことはありますか ? マルチテナントアプリケーションは、シングルテナントアプリケーションに比べて、インフラストラクチャの集約によるコストの最適化や、運用の均一化による開発速度の向上といったメリットがあります。

一方で、マルチテナント SaaS アプリケーションではコンシューマー向けの Web アプリケーションや従業員向けの BtoE アプリケーションと異なり、「テナント」の概念をアプリケーションの各レイヤーや運用に組み込む必要があります。詳細については こちらの連載AWS Well Architected フレームワーク SaaS レンズ にて紹介されていますので、ぜひご覧ください。

複数のテナントで同じ環境を共有するため、特にセキュリティの観点で重要になってくるのは、アクセスしているユーザーがどのテナントのコンテキストでアクセスしているかを識別し、他のテナントのリソースにアクセスできないことを保証することです。これには認証・テナント分離のための特別な設計が必要となります。マルチテナント SaaS における認証の実現方法としては Amazon Cognito の機能を利用する、AWS のパートナー製品を活用する、OSS を利用するなど複数の選択肢が存在します。リクエストのボリュームや実現したい要件によって最適なものを選んでいくのですが、 この記事では Amazon Cognito の機能を使ってどのように実装できるかをご紹介します。

このシリーズ記事のその他の記事はこちら

選択
  • 選択
  • ビルダーのビルダーによるビルダーのためのセキュリティ »
  • セキュリティを何から始めれば良いか分からない開発者の方へ »
  • DevSecOps パイプラインを構築してみよう ! »
  • Amazon Inspector と AWS Systems Manager を用いて脆弱性の修復パイプラインを構築しよう
  • マルチテナント SaaS アプリケーションの認証を Amazon Cognito で実現してみよう !
  • すぐに始めて、継続できる AWS のセキュリティ対策

マルチテナント SaaS での Amazon Cognito

マルチテナント SaaS における認証サービスの選択肢の一つとして、Amazon Cognito をご活用いただけます。Amazon Cognito にはユーザープールというユーザーディレクトリが用意されており、この中にアプリケーションのユーザープロファイルを格納できます。Amazon Cognito は クォータの範囲 内の一定のテナント数までであれば マルチテナントな使い方 もサポートしています。

マルチテナントな SaaS アプリケーションの認証・認可の実装においては、通常の Web アプリケーションの認証・認可に比べて下記のような追加の作り込みが必要となります。

  • 新規テナント登録時のリソース作成 (オンボーディング)
  • テナントごとの認証要件のカスタマイズ
  • バックエンドアプリケーションでの複雑なアクセス制御
  • テナント管理者によるユーザーやアイデンティティプロバイダー (IdP) の登録

マルチテナント戦略によって作るべきリソースは異なりますが、新規テナントがオンボーディングした際にはテナントごとにユーザープールやアプリケーションクライアントと呼ばれるリソースを作成する必要があります。また、バックエンドアプリケーションではテナント分離や契約プラン、ユーザーロールなどの複数の要素に基づいてアクセス制御を行う必要があります。アクセス制御においては、こちらの記事 で紹介している通り、各種 IdP やデータベースなどに点在しているこれらの情報を最初に JSON Web Token (JWT) に含んだ上でバックエンドに送ることで、バックエンド側の認可処理をシンプルに実現することができます。

では、通常の Web アプリケーションに比べて追加の労力が必要な開発を少しでも楽にするにはどうすれば良いでしょうか ? ここからは Amazon Cognito やライブラリの機能を活用して少しでも労力を減らすためのテクニックをご紹介します。

ライブラリや組み込み機能の活用

Amplify Libraries

フロントエンドを JavaScript の各種フレームワークやモバイルアプリ等で開発する場合、AWS Amplify Libraries は Amazon Cognito との連携をするための最も有力な選択肢です。従来の Web アプリケーションではバックエンド側に認証の機能を実装するのが一般的でしたが、フロントエンドアプリケーションと Amazon Cognito が直接やり取りすることで、バックエンド側に認証のための API を持つ必要がなくなります。この際、Amplify Libraries を利用することで Amazon Cognito の API 呼び出しを抽象化し、認証後のトークンの管理など実装を簡略化することができます。

さらに、Amplify UI Components という組み込みのコンポーネントを使うことで認証のためのフォームをご自身で作る必要がなくなります。単純な ID、パスワードだけの認証であれば良いのですが、実際には MFA やパスワードリカバリー、メールアドレスの検証など、認証のワークフロー中のユーザーとのやり取りのための複数のフォームが必要となります。これに対し、 Amplify UI Components を利用することで、最初から上記のような画面遷移に対応したフォームが以下のような簡単なコードで簡単にアプリケーションに組み込めます。

Auth.configure({
    region: REGION,
    userPoolId: USER_POOL_ID,
    userPoolWebClientId: APP_CLIENT_ID,
   ...
});
...
<Authenticator hideSignUp={true}>
  ...
</Authenticator>
...

下記のように、テーマカラーやフォームのスタイル、フォームの言語もカスタマイズも可能です。詳細はこちら をご覧ください。 

[デフォルトテーマ]

[カスタマイズテーマ]

Amplify Libraries はユーザー名とパスワードや MFA を用いたログイン以外にもテナントの管理する外部 ID とのフェデレーションサインインも実装を大幅に抑えながら実現することが可能です。画面の実装をされる際はぜひ Amplify Libraries や Amplify UI Components のご利用をご検討ください。

Hosted UI

認証画面を実装するための他の選択肢としては Amazon Cognito の提供する OAuth 準拠の認証画面である Hosted UI もご利用いただけます。2022 年 12 月現在画面表示は英語のみとなっていますが、コードを書かずにドメインの設定とクライアントの設定だけで利用できるので小規模なアプリケーションで簡易なログイン画面を提供したい場合には有用です。

また、Hosted UI 経由で一度ログインすると、セッション情報が Cookie に保存され、次回以降はシングルサインオンが実現できます。自社の複数の SaaS 製品でシングルサインオンさせたいという要件がある場合にも検討いただけます。


テナントごとの認証要件のカスタマイズ

SaaS 事業者は利用企業側の認証に関する要件にも対応していく必要があります。例えば他の顧客とユーザーの保存領域を明確に切り離したい、社内規定でパスワードポリシーが定まっていたり MFA を必須にする必要があるなどです。マルチテナントの環境でどこまで対応するかはビジネス戦略次第ですが、SaaS においては、上位プランを契約している要求の厳しい顧客のみ環境を分けるというデプロイオプション も検討いただけます。

Amazon Cognito でユーザーの認証要件をカスタマイズする場合、テナントごとにユーザープールを分けて実現する方法と、同じユーザープールの中でアプリケーションクライアントを分けることによって実現する方法があります。

ユーザープールの分割

テナント専用のユーザープールを作成することで、コンプライアンス上他テナントと同じ場所にパスワードを保存できないというテナントにも対応可能です。他にもパスワードポリシーをカスタマイズしたい、MFA を必須化したいなど、個別のテナントごとの要件にも柔軟に対応が可能です。さらに、ユーザープール単位で AWS WAF の ACL をアタッチできる ため、特定の IP アドレスからしか認証できないように制御するということも可能です。

認証要件の分離という観点ではわかりやすく、バックエンドアプリケーションもテナント専用に構築されている場合は認可も簡単に実現できます。一方で、バックエンドアプリケーションがマルチテナント構成の場合、動的に増えるユーザープールを識別して JWT を検証するロジックを作り込む必要があるため、実装が複雑になる可能性があります。

アプリケーションクライアントの分割

アプリケーションクライアントはユーザープールの API を呼び出すための認証情報です。同じユーザープールを利用している場合でも、このアプリケーションクライアントに紐づけて、

  1. 外部 IdP を利用するか
  2. パスワードログインを許可するか(認証フローのカスタマイズ) 
  3. 各種トークンの有効期限

などをカスタマイズできます。

こちらはユーザープールが一つであるため、バックエンド側がシングルテナントであってもマルチテナントであっても COGNITO_USER_POOLS オーソライザー等を利用して、比較的シンプルに認可ロジックを実装できます。(別途テナントを分離するためのロジックは用意する必要があります。)

認証設定情報の取得

テナントごとに専用のユーザープールやアプリケーションクライアントを利用する場合、認証の前にテナントが利用する認証設定情報 (ユーザープール ID やアプリケーションクライアント ID) を取得した上で Amazon Cognito にリクエストを行う必要があります。この実現方法としてはいくつかありますが、例えばテナントごとにログインページのドメインを分けて、ドメインの値を元に認証設定情報を取得することが可能です。

フロントエンドアプリケーションで Amplify Library を用いる場合、バックエンドからダウンロードした設定情報を元に Amplify.configure()Auth.configure() を呼び出すことで、動的にテナントごとの設定を切り替えることができます。下記の図は具体的な実装のイメージです。

これ以外にも、画面遷移として最初にテナント ID を入力させる方法や、メールアドレスを最初に入力させて所属するテナントの認証設定情報を取得する方法もあります。実現したい画面遷移に応じて最適なものを選んでいただければと思います。


JWT のカスタマイズ

前述の通り、アクセス制御に必要な情報を認証時に JWT に付与してアプリケーション全体に伝播することで、認証後のアプリケーション側でのアクセス制御のロジックをシンプルに実装することができます。

カスタム属性

Amazon Cognito では JWT (ID トークン) に任意の属性を付与するための仕組みとして、カスタム属性 という機能が備わっています。最もシンプルな JWT のカスタマイズ方法としては、ユーザーのサインアップ時にテナント ID などのカスタム属性をイミュータブル(変更不可能)な属性として付与することです。

ただし、このカスタム属性は検索には利用できず、変更可能な値を入れる場合は、更新時に クォータ の影響を受ける可能性があります。

Lambda トリガー

そこで、別のアプローチとして、Lambda 関数を用いて JWT に任意の属性を付与するということもできます。

トークン生成前の Lambda トリガーは認証成功時に Lambda 関数が呼び出され、JWT (ID トークン) の値を上書きすることができる仕組みです。これにより、Amazon Cognito のクォータを意識することなく DB 内部に保存されたテナントの契約プラン、ユーザーのロールなど変更される可能性のある情報も JWT に付与することが可能です。また、検索の要件がある場合も、DB 側に値が保持されているため、そこから検索を行うことができます。


まとめ

本記事ではマルチテナントな SaaS アプリケーションに求められる要件と、Amazon Cognito を用いて SaaS の認証および、認可に用いる JWT のカスタマイズのテクニックをご紹介しました。

SaaS の認証においては、通常の Web アプリケーションに加えてオンボーディングや、テナントごとの認証要件のカスタマイズ、認可のロジックなどの検討すべき事項が存在します。これらの作り込みは比較的大変な作業になりがちですが、Amazon Cognito やライブラリの機能をうまく活用することで、実装に必要なコード量を削減することができます。本記事がこれからマルチテナントの認証を実装していく皆様の役に立てば幸いです。

このシリーズ記事のその他の記事はこちら

選択
  • 選択
  • ビルダーのビルダーによるビルダーのためのセキュリティ »
  • セキュリティを何から始めれば良いか分からない開発者の方へ »
  • DevSecOps パイプラインを構築してみよう ! »
  • Amazon Inspector と AWS Systems Manager を用いて脆弱性の修復パイプラインを構築しよう
  • マルチテナント SaaS アプリケーションの認証を Amazon Cognito で実現してみよう !
  • すぐに始めて、継続できる AWS のセキュリティ対策

builders.flash メールメンバーへ登録することで
AWS のベストプラクティスを毎月無料でお試しいただけます

筆者プロフィール

柴田 龍平
アマゾン ウェブ サービス ジャパン合同会社
技術統括本部 ISV/SaaS ビジネス本部 ソリューションアーキテクト

コンテナとセキュリティが好きなソリューションアーキテクト。普段はパッケージベンダーや SaaS 事業者のご支援をしております。好きなサービスは AWS Network Firewall、AWS WAF、AWS Fargate です。
最近はふるさと納税の返礼品が冷蔵庫から溢れそうで困ってます。

AWS を無料でお試しいただけます

AWS 無料利用枠の詳細はこちら ≫
5 ステップでアカウント作成できます
無料サインアップ ≫
ご不明な点がおありですか?
日本担当チームへ相談する