はじめに
カミナシでID管理・認証基盤を開発しているmanaty(@manaty0226)です。ラスベガスで開催されているAWS re:Invent 2024に初めて参加しています。今回はチョークトークセッションで開催された「Next-generation SaaS tenant isolation strategies」に参加したレポートをお届けします。
チョークトークセッションでは登壇者と聴講者が互いにディスカッションしながら進めていきます。登壇者の話している内容について疑問に思えば手を挙げて質問できますし、そこで面白い論点が出てきたら登壇者は深掘りしてくれるので、あらかじめ準備された話を聞くよりも学びの深い時間を過ごすことができます。
テナント分離とはなにか
セッションはまずテナント分離とはなにか、なぜテナント分離する必要があるのかを問いかけて始まります。テナント分離とは単にテナントごとにデータをパーティショニングするだけでなく、何らかの形でアプリケーションから別テナントにアクセスしてしまっても、適切にアクセスを拒否できることが必要というのが今回のセッションの前提となる話です。この考え方についての詳細はAWSの公式ドキュメントで説明がされているようです。
すなわち、データベースなどのデータレイヤーに着目すると、テナント分離とはアプリケーションの入り口で実施される認証認可とは独立したロジックによってアクセス制御を行うことと理解しました
AWSにおけるテナント分離パターン
さて、マルチテナントアプリケーションの実装パターンとしてAWSで従来よく知られていたのは、LambdaオーソライザーでJWTを受け取り、トークンに含まれるテナントIDをいれたIAMポリシーを含むロールをAssume Roleする方法ではないでしょうか。この方法はアプリケーションロジックに不具合があれば別テナントのデータアクセスが容易にできてしまうため、刷新されたパターンが紹介されていました。新しいパターンでは、AWS IAMがJWTを読み取ってAWS STS(Security Token Service)による一時権限を付与します。これにより、アプリケーション自身が制御するのではなく、AWS IAMの判断で適切なデータアクセスができます。詳細は公式ブログなどを参照ください。
SaaS tenant isolation with ABAC using AWS STS support for tags in JWT | Amazon Web Services
テナント分離を整理するとRFC 8693に辿り着いた
セッションではこの後、アプリケーションロジックからデータレイヤーへのアクセス権限の取得を拡張して様々なパターンが紹介されます。一つ目はユーザーのJWTをデータレイヤーへアクセスするクレデンシャルと交換してくれるToken Vending Machineと呼ぶ何らかの独自システムを介して、Secrets Managerからデータレイヤーへアクセスするクレデンシャルを取得するパターン。二つ目はこの仕組みをベースとして粒度の細かいデータアクセス権限を渡すためにAmazon Verified Permissions(AVP)を利用するパターン。
データレイヤーがDynamoDBであれば前述したようにSTSによる一時権限を渡せばよいですし、例えばRow Level Securityが設定されたPostgreSQLであれば適切なデータベースユーザーの認証情報を渡すことでデータレイヤーへのアクセス権をアプリケーション自身が判断することなく取得することができます。
こうしたパターンの紹介をみて、つまり彼らがやりたいことは、ユーザーを認証認可するIdentity Provider(IdP)が払い出すトークンをデータレイヤーのアクセス制御に利用するシステム内部だけで利用可能なトークン(内部トークン)に変換し、データレイヤーは内部トークンを見てアクセス制御を行うことでテナント分離を実現したいのではないかと考え以下のような図で整理してみました。
外部トークンは一般的にOIDCやOAuthのフローで払い出されるアクセストークンになり、内部トークンはDynamoDBなどのAWSサービスがストレージであればSTSの一時権限になりますし、DBがAurora PostgreSQLであればRLSでアクセスするための接続認証情報になります。このように整理することで従来のSTSパターンから今回紹介されたパターンまで全て一般化して説明することができます。
このアーキテクチャで思い出すのはRFC 8693 OAuth 2.0 Token Exchangeです。マイクロサービスアーキテクチャなどにおいて、ユーザーのアクセストークンを受け取ったサービスがToken Exchangeプロトコルを使って内部トークンに変換し、後段のサービスにリクエストするといった構成は過去にも様々なアプリケーションで実装されています。アプリケーションロジックとは分離された判断ロジックによって後段のサービスやデータレイヤーを守る意味で共通の考え方だと思います。
セッション中に私が「Secrets Managerで払い出すクレデンシャルの生存時間がユーザーのJWTよりも長い場合もしくは長期間のライフサイクルを持っている場合、それは別の脆弱性につながらないのか」という質問をしたところ、「内部で交換されるクレデンシャルのライフサイクルを管理する仕組みを作るといいと思っているが、チャレンジングな課題」という回答をもらいました。上述した一般化から考えると、独自の仕組みを作るよりもSTSやRFC 8693といったすでに出来上がっているプロトコルにのせるのが適切かなと感じます。DBの接続認証情報は永続的なのでこれはどうするか難しいですね。
おわりに
本記事ではAWS re:Invent 2024のセッションレポートとして、登壇者が紹介していたマルチテナント分離の考え方および実装パターンと、私が考察した一般化について書きました。今回整理した考え方は運用時のデータベースへの特権アクセスなども含めて綺麗な形でアクセス制御できそうなので、示唆に富むセッションだったと感じます。また、チョークトークセッションは積極的に議論に参加するとすごく楽しめる形式で満足しました。
カミナシではアクセス制御が好きなソフトウェアエンジニアも募集しています。興味がある方はぜひ応募してください。