オライリー出版のマルチテナントSaaSアーキテクチャの構築を読んで、大事なポイントや気づいた点を個人的にまとめたいと思う。
とはいえ、全体で17章もあるボリュームの書籍であるため、このブログでも何回かに分けて取り扱いたい。(最終的な総括も記事にする予定)
前回の記事はこちら。
あくまで読者メモなのでかなり内容を間引いている。
より深く情報を得たい人は実際に書籍を手にとって読んで欲しい。
琵琶湖畔で文鳥と暮らす在宅エンジニア yassan です。仕事の生産性や生活の質を高めるアイデアを共有しています。
4章 オンボーディングとアイデンティティ
- 導入。
- オンボーディング、アイデンティティ、コントロールプレーンはマルチテナントアーキテクチャの出発点。
 
 - ベースライン環境の構築。
- ベースライン環境:インフラストラクチャとそれに付随するリソース、およびコントロールプレーン環境。
 - SaaS環境を稼働するために必要なすべての構造を起動できるスクリプトと自動化の準備。
 - SaaS管理コンソールを用意し、テナントのオンボーディング状況の監視、テナントの有効化/無効化、ポリシーの変更、テナント/ティアのメトリクス表示などの機能を持たせる。
 - コントロールプレーンを専用環境にデプロイするかアプリケーションプレーンと同じ環境に共用にデプロイするかの選択肢がある。
 - コントロールプレーンとアプリケーションプレーンは同じ技術スタックである必要はない。
 
 - オンボーディング体験
- オンボーディングもサービスの一部。後回しやその場しのぎではいけない。
 - オンボーディングの中で決定する例。
- テナントをどのようにサイロ化およびプール化するか。
 - テナントをどのように、どこで認証するか。
 - ティアとデプロイモデルに基づいて、テナントをコンテキストに応じてどのようのルーティングするか。
 
 - オンボーディングの自動化に費やす労力とコードの量は多いが、投資価値がある。
 - オンボーディングにも2種類あるが、重要性に差はない。
- セルフサービス:B2C SaaSに多い、サインアップしたらそのまま利用できる。
 - 内部オンボーディング:B2B SaaSに多い、契約が成立したら、社内管理のオンボーディングを実施する。
 
 - オンボーディングの基本要素
- テナント管理者またはシステムユーザーがオンボーディングを実行し、テナント管理、テナントプロビジョニング・・・と順に(あるいは非同期に)実行する。
- テナント管理:テナントに関する必要な情報を渡すことで、テナント識別子を作成する。ステータスの初期値を設定する。
 - テナントプロビジョニング:インフラリソースのプロビジョニング。サイロの場合は一式、プールの場合は最小限の場合もある。
 - 請求システム:請求システムに必要な情報を渡して、請求サービスにテナントの登録を行う。
 - テナント管理者の作成:テナントの初期ユーザーの作成。アイデンティティプロバイダーの機能を利用する。
 - オンボーディングプロセスが完了したら、ステータスをアクティブに変更する。
 - オンボーディングプロセスは可視化できるようにしておく。
 - ティアごとに異なるオンボーディングプロセスを用意する必要がある場合もある。
 - マルチテナント環境の初期設定で、プール化したリソースをすべて最初にプロビジョニングする戦略もあり。
 
 - オンボーディングの障害対応
- 外部サービスへの統合を非同期化して失敗した際は再試行する。
 
 - オンボーディングのテスト
- 負荷テスト、障害からの復旧能力検証、時間測定・パフォーマンステスト。
 
 
 - テナント管理者またはシステムユーザーがオンボーディングを実行し、テナント管理、テナントプロビジョニング・・・と順に(あるいは非同期に)実行する。
 - SaaSアイデンティティの作成
- マルチテナントのアイデンティティは純粋なユーザー認証ツールとして扱うには不十分。
 - SaaSアイデンティティはユーザーアイデンティティとテナントアイデンティティで構成される。
 - SaaSアイデンティティは、システムのすべてのレイヤーに渡される最上位のアイデンティティ構造になるような方法で実装されなければなりません。
 - テナントアイデンティティの追加
- OAuthとOIDCに自然に組み込む。
 - JWTのカスタムクレームを導入して、独自のプロパティ・値のペアを定義する。
 - 認証トークンはベアラートークンとして発行され、OIDC・OAuth仕様に組み込まれているセキュリティ、ライフサイクルなどの仕様を継承した状態でバックエンドサービスに送信される。
 - JWTベアラートークンはHTTPだけでなく他のプロトコルでもコンテキストの一部として挿入できる。
 - ユーザーに関する情報を追加するときは、そのユーザーに関するテナントコンテキストの情報もすべて追加する。
 - 認可の仕組み上、カスタムクレームで持つか、アクセス制御構造(アイデンティティプロバイダーの範囲外にて管理される)側で持つかは、属性のライフサイクルと役割に基づいて判断する。
- アプリケーションの特徴やきのう、能力の進化に伴って属性が変化する傾向がある場合は、アプリケーションのアクセス制御を通じて管理する。
 
 - テナントアイデンティティをJWTに含めず他システムでUser->Tenantをマッピングするのは適切ではない。
- 他システムがボトルネックになるし、リクエストの回数が異常に多くなる。
 
 - フェデレーションを追加する場合(=アイデンティティプロバイダーが複数ある場合)は、認証マネージャーを介するようにする。
- プロバイダーのJWTにテナントの情報が含まれないので、認証マネージャーで追加する。
 - 拡張性や単一障害点の懸念があるので、導入するときはよく検討すること。
 
 
 - テナントのグループ化 / マッピング構造
- Cognitoを例に挙げると、ユーザープール単位でグルーピングが可能。
- 選択肢1:テナント単位にユーザープールを作成する。
- 認証プロセス中にテナントを指定のプールに割り当てる仕組みが必要。
 - テナントのティアごとに分けるのもあり。
 
 - 選択肢2:すべてのテナントを1つのユーザープールにまとめて、他の仕組み(グループなど)を使用してユーザーとテナントを紐づける。
 
 - 選択肢1:テナント単位にユーザープールを作成する。
 
 - Cognitoを例に挙げると、ユーザープール単位でグルーピングが可能。
 - テナント間でのユーザーIDの共有
- 1つのIDに対して複数のテナントを割り当てるユースケースがある場合は、ログインフローのどこかでSaaSはユーザーがどのテナントにアクセスしているか判別する必要がある。
 - テナントごとにサブドメインを割り当てて、認証プロセスにサブドメインを使用する。
 
 
 
 
5章 テナント管理
- 導入、テナントの管理の概要
- どのように実現するか?:APIやシステム管理コンソールを通じて実現する。
 - 役割;テナントの状態を観測する。テナントのライフサイクルを管理する。
 
 - テナント管理の基礎
- 頻繁に関わる要素:オンボーディング、オフボーディング、請求。
 - 取り扱うデータの種類:
- コアテナント属性:テナント識別子(有効/無効)、ティア、会社名、アカウント開設状況、最終ログイン日など。
 - テナントアイデンティティ構成:テナント管理サービスを通じて構成されるテナント認証情報。
 - テナントルーティング構成:テナントをインフラストラクチャの様々な要素にどのようにルーティングするか決定するために必要な、テナント固有の設定。
 
 - テナントキー/シークレット:例えば、管理されるテナントごとのシークレットや暗号キー。SaaSによっては、全体的な分離とセキュリティ構成において大きな役割を持つ。
 - テナントユーザー:テナント管理者(オンボーディング時に作成される初期ユーザー)とテナントユーザー。
- テナントとユーザーは別々に管理されるべき。ユーザーの役割やその他のアプリケーション関連の設定は、テナントの設定と分ける。
 
 - テナント管理サービスの構築
- サービスとインターフェースは、通常2つの論理的カテゴリーに分けられる。
- 1:基本的な管理。作成、読み取り、更新、削除(CRUD)のインターフェースを介して実行する。
 - 2:より広範囲なテナント管理業務(テナントの無効化、解約など)が中心になる。
 
 - 構成
- 入力:CRUD、有効化、一時停止、廃止、ティアの変更、オンボーディング・・・
 - ストレージ:テナント構成情報を保存する。データサイズと利用率から、NoSQL(例えばDynamoDB)が推奨。
 - サービス廃止/ティアの切り替えサービス:インフラストラクチャの自動化スクリプトやコードを呼び出す。非同期ジョブ。
 - 請求:テナントの状態を更新するイベントをトリガーする場合がある。あるいは請求サービスにリクエストを送信する。
 
 
 - サービスとインターフェースは、通常2つの論理的カテゴリーに分けられる。
 - テナント識別子の生成
- GUID:一意で普遍的で変更不可能な点で良い。
 - サブドメイン、バニティドメイン:外部に公開されるので、内部でマッピングする必要があり非推奨。
 
 - インフラストラクチャ構成の保存
- テナント管理では、テナント固有のインフラストラクチャ構成情報を保存するのにも使用する。
- 具体的には、アイデンティティ設定、ルーティングパターン、その他。
 
 
 - テナント管理では、テナント固有のインフラストラクチャ構成情報を保存するのにも使用する。
 - テナント管理サービス自体が、全体のボトルネックにならないように注意する。
- 理想的には、アプリケーションのサービスがテナント管理データを頻繁にアクセスしないことが望ましい。
 - 重要なテナント属性をJWTに組み込んでおけば、テナント管理サービスがボトルネックになることはない。
 
 
 - テナント構成の管理
- 画面イメージ
- テナント管理サービスから情報を取得して出力する。例えば、各テナントID、名前、状態、作成日など。
 - テナントの状態を調べ解決するときに使用する。ログの検索やトラブルシューティングを行うときにも使用する。
 - 特定のテナントのポリシーやティアの変更などにも使用する。
 - テナントの詳細(一例)
- テナント名、請求ティア、サブドメイン、連絡先、連絡先、ユーザー数、最終変更日
 - アイデンティティプロバイダー、デプロイパイプライン、サイロ化されたストレージリソース、テナントのロードバランサー、テナントのログ、テナントの履歴
- これらはハイパーリンクになっていて、クラウドプロバイダーへ遷移し、特定のテナントに関連したリソースを素早くアクセスさせる。
 - サイロの場合は恩恵が得られるが、プール化されればされるほど価値が低くなる。
 
 
 
 - 画面からでもAPIからでも利用できることが望ましいが、要件に応じてどちらかでも良い。
 - 内部オンボーディングの場合は、社内向けのツールになる。テナント管理コンソールからオンボーディングを実施する。
 
 - 画面イメージ
 - テナントライフサイクルの管理
- テナントの有効化/無効化
- テナントの削除ではなく無効化。つまり、どのようにアクセスを制限するか。
 - 未払いの場合は継続して使わせるのか、メッセージを送るのか、など。
 - 有効化して元に戻せることも考慮しなければならない。
 - テナントの状態はテナント管理サービスによって一元管理されるべき。
 
 - テナントの廃止
- 無効化した後に廃止を実施する。
 - テナント管理サービスに廃止リクエストを送信する流れを示すことで開始する。テナント管理サービスとは別に独自の廃止プロセスを準備しておくべき。
 - プールモデルの場合、廃止プロセスで他のテナントと一緒に配置されているデータを選択的に削除する必要がある。
- テナントIDのGUIDをキーにストレージから削除するコードを準備する必要がある。
 - 場合によってはオンボーディングよりも複雑になる。
 - 細心の注意を払う必要もある。パフォーマンス影響も考えると非同期でやるのが望ましい。
 
 - アーカイブとしてスナップショットを取得する戦略もある。
 
 - ティアの変更
- ティアに関係なくプールモデルの場合、アプリケーション内の機能フラグを切り替えるだけにしておけば楽。
 - ティアに応じてサイロモデルになる場合、重労働な移行が発生する。
- オンボーディングプロセスと似ている。必要なルーティング設定から開始する。
 - ゼロタイムの移行か、環境を改めてもらうか。
 
 - 混在モデルはかなり複雑。
 - 上位ティアへの変更だけでなく、下位ティアへの変更も考慮する。
 
 
 - テナントの有効化/無効化
 
(この記事ではここまで)
