🤹‍♀️

【アーキテクト】SaaS開発でマルチテナント×RLSを用いる理由

2023/09/25に公開

この記事は?

著者は、現在こそToCの開発に携わっているものの、SaaS開発に関しては3年以上の設計と実装の経験があります。SaaS開発を行う上で必須となるテナントの分離を行う理由は、他企業へのデータアクセスによるセキュリティインシデントを防ぐためです。この記事では、一般のSaaS開発においてマルチテナント×RLSが有力なアーキテクチャとなり得る理由を説明します。

シングルテナントvsマルチテナント

注) テナントの概念に入門する人のためのパート。適宜読み飛ばしてください。

そもそもテナント(tenant)とは、店舗や事務所などを借りて住んでいる人のことを指します。では、SaaSでテナントとは通常誰のことを指すのでしょうか?テナントとはSaaSが展開するサブスクリプションの契約主で、法人と契約しているSaaSであれば企業=テナントになり、個人と契約しているSaaSであれば個人=テナントになります。つまりSaaS開発者は、SaaSを使うためのインフラ(アプリ•DB•ネットワーク)に対してテナントが属するようにして、適切にSaaSを利用できるようにアーキテクトを考える必要があります。シングルテナントでは、それぞれのテナントに対して一式のシステム(アプリ•DB•ネットワーク)を提供するため、企業個別の機能開発のニーズにも対応し、インフラリソースも自由に選べる上に、システムがどのテナントともデータを共有しないのでテナント同士のデータアクセスも発生せず、セキュリティ上非常に強固な状態です。一方で、企業ごとに一式システムを構築するため、企業が増えれば増えるほどインフラにかかる額が嵩むのは、SaaSを開発する多くの資金制限のある企業にとっては費用対効果が悪く、感化し難い事実です。そこで、マルチテナントの考えで複数テナントが1システムに属するようにします。このとき、テナント同士でのデータアクセスがあってはいけないので、セキュリティ面を担保する必要があります。

マルチテナント×RLSを用いる理由

マルチテナントを実現する1つの方法として、データベースのみをインスタンスやスキーマで分離すると言う方法があり、これは実際にSanSanでも取り入れられていた方法です。しかし、

一旦はそれでうまくいきました。スキーマを分離することで、テナント間のデータが混ざる可能性を考慮せずに開発できるためです。しかしローンチ後に順調に契約テナント数が伸びるにつれて、マイグレーションにかかる時間が問題になってきました。普段のリリースではCloud RunやApp Engineのトラフィックを切り替えるだけなので数秒で終わりますが、マイグレーションがある場合は全テナントのマイグレーションを完了するまでに5〜10分程度かかっていました。

さらにBill Oneでは、オンラインでサインアップ可能な無償のスモールビジネスプランを導入することで、それまでの有償契約のみに比べて、テナント数が大幅に増えることが想定されました。

この通り、契約テナントの数が多くなるとマイグレーションにかかる時間の問題が生じるとともに、そういった開発側の事情だけでなくBill Oneのようにビジネスプラン変更など、経営判断によるビジネスモデルの変更に対して柔軟に対応していくためには限界があるように感じられます。

https://buildersbox.corp-sansan.com/entry/2021/05/10/110000

そこで登場するのが RLS(Row Level Security) です。PostgreSQLなどはRLSをサポートしており、RLSを使うことでセキュリテーポリシーを設定できます。tenantIdが同じ場合のみそれぞれのテーブルにアクセス可能なポリシーを作成することで、tenantIdが異なる(他テナントからのアクセスである)場合はアクセスできないと言う設定が可能です。この処理はDBで行われるため、アプリ側でアクセスを弾くよりさらに低レイヤーで、セキュリティとしても強固であると言えます。

RLS(行レベルセキュリティ)の落とし穴

2023年9月現在、RLSをサポートしているのはPostgreSQLと一部の商用DBのみで、MySQL/MariaDBにはRLSは対応していません。つまり、MySQLで仮にtenantテーブルというテーブルを作ってテナントごとにアクセスを分離できたとしても、制御しているのはアプリレイヤーでtenantIdでクエリをフィルターすることだけで、そもそもMySQL/MariaDBにはRLSはないので、DBレイヤーでのRLSはできないため、セキュリティとしてPostgreSQLなど使う場合より欠けてしまう懸念が増してしまうことは問題点です。具体的には、実装者がtenantIdでのフィルターする実装を書き損じた場合に他テナントのデータまで取れてしまったり、厳格なアプリ側でのセキュリティ対策を行おうとすると実装者の負担が増えたりといったデメリットがあります。

参考文献(リファレンス)

・SaaS on AWSの連載
本記事では取り上げなかったが、金融システム開発などではサイロモデルを使うのが良い。
https://aws.amazon.com/jp/builders-flash/202105/tenant-isolation/?awsf.filter-name=*all

・サイロモデルvsプールモデルの詳細な比較
https://medium.com/belong-official-blog/saas-におけるマルチテナント分離モデル-6e3f50b7b2fe

Discussion