複数の顧客企業のデータを1つのPostgreSQLデータベースに同居させるマルチテナントSaaS基盤を運用しているインフラ担当者に向けて、テナント分離を強化する新しいアプローチを整理します。アプリケーション側の実装ミス1つで他社データが見えてしまうリスクに、どこまでインフラ層で備えられるかという話です。
OSSとして公開された「Agata Proxima」は、アプリケーションとPostgreSQLの間に挟み込むRust製のプロキシ(中継サーバー)です。テナント分離(異なる顧客のデータを互いに見えなくする設計)を、アプリケーションコードの外側からもう一段補強することを目的に作られています。
何が新しいのか:境界をインフラ層に持ち込む発想
マルチテナントSaaSのデータ分離は、一般的に3つの方法で実装されます。
- アプリケーションコード内でテナントIDによるWHERE句フィルタを必ず付与する
- PostgreSQLのRow-Level Security(RLS、行単位でアクセス制御をかけるDB標準機能)でDB側に制約を持たせる
- テナントごとにスキーマやデータベース自体を分割する
これらはいずれも有効な手段ですが、弱点があります。アプリケーション側フィルタは実装漏れに弱く、RLSはポリシー設定を誤るとすり抜けが起きます。スキーマ分割は運用コストが跳ね上がります。
Agata Proximaが提案するのは、これらに加えてネットワーク経路上に検証層を追加する発想です。アプリケーションがPostgreSQLに直接つなぐのではなく、必ずRustプロキシを経由させます。プロキシ側でテナントごとのアクセスポリシーを検証し、監査ログ(誰が何にアクセスしたかの記録)を残す構成です。
段階的に見る技術的な仕組み
構成はシンプルです。SaaSアプリケーション、Agata Proximaのエンジン(Rustプロキシ)、PostgreSQLの順に一直線でつながります。アプリケーションからの接続はすべてこのプロキシを通過します。
プロキシが担う役割は大きく2つに分かれます。1つ目はアクセス制御の検証です。接続してきたクエリがどのテナントに属するか判定し、許可されたポリシーの範囲内かをチェックします。2つ目は可観測性(システムの内部状態を外から把握できるようにする仕組み)の提供です。データベースへのアクセス状況をモニタリングし、監査記録として蓄積します。
Rustが採用された理由は、メモリ安全性(不正なメモリアクセスによるクラッシュや脆弱性を防ぐ言語特性)と実行性能です。プロキシはすべてのDBトラフィックの経路上に立つため、ここでの遅延やクラッシュは即座にサービス全体の可用性に影響します。インフラのクリティカルパスに置くソフトウェアとして、Rustの選択は妥当な判断です。似た用途でRustが使われる例としては、データベースプロキシのPgBouncer(CではなくC言語実装ですが)やPgCat、あるいはEnvoy Proxy(RustではなくC++製)のような通信インフラ領域の実装が挙げられます。性能とメモリ安全性を両立したい通信ミドルウェアでRustやC++が選ばれる流れと同じ文脈です。
既存の分離手法との比較で見える立ち位置
RLSと比較すると役割の違いが見えてきます。RLSはPostgreSQL本体に組み込まれたポリシーエンジンで、クエリプランナーのレベルで行をフィルタします。実装が正しければ強力ですが、ポリシー自体のバグやビュー経由の抜け道など、DB内部の設定ミスがそのままリスクになります。
プロキシ方式は、DB内部のポリシー設定に依存しない独立した検証層を追加する考え方です。アプリケーション層・DB層(RLS)・プロキシ層という3層で防御を重ねる、多層防御(defense in depth)の発想に近い構成です。どれか1層が破られても他の層でカバーする設計思想で、SREやセキュリティ領域で馴染みのある考え方です。
ただし新しい層を増やすことは、新しい単一障害点(SPOF)を増やすことと表裏一体です。プロキシがダウンすればDB接続全体が止まります。接続プーリングやフェイルオーバー構成の検討なしに本番導入するのは慎重であるべきです。
今日確認できること・導入判断の基準
実際に検討する場合、まず確認すべきはGitHubリポジトリ(Agata-Proxima/proxima-engine)のコードとREADMEです。OSSとして公開されているため、実装の中身を自分の目で確認できます。
導入を判断する前に、インフラ担当者として確認しておきたい項目を整理します。
- 現在のPostgreSQL接続経路(アプリケーション→DB直結か、PgBouncerなどの既存プロキシを経由しているか)
- 既存のRLSポリシーやアプリケーション側フィルタの実装状況と、それらの監査がいつ最後に行われたか
- 新しいプロキシ層を追加した場合のレイテンシ増加の許容範囲(SLO上どこまで遅延を吸収できるか)
- プロキシ自体の冗長化構成(複数ノードでのフェイルオーバーが可能か)とヘルスチェックの仕組み
- 監査ログの出力先がオブザーバビリティ基盤(PrometheusやDatadogなど)と連携できる形式か
TerraformやPulumiでインフラをコード管理している環境であれば、プロキシノードをどうモジュール化するか、PostgreSQLへの接続文字列やセキュリティグループのルールをどう変更する必要があるかも事前に洗い出しておく価値があります。既存のIaC(Infrastructure as Code、インフラ構成をコードで管理する手法)定義にプロキシを差し込む際、接続先エンドポイントの変更がアプリケーション側のデプロイにどう波及するかも合わせて確認が必要です。
なお、このプロジェクトは記事執筆時点でOSSエンジン部分が公開されたばかりの段階です。本番のマルチテナントSaaSに組み込む前に、負荷テスト環境での検証や、障害時のフォールバック動作(プロキシ障害時にDB接続をどう扱うか)の仕様確認は欠かせません。
まとめ
マルチテナント分離は、アプリケーションコードとRLSだけに頼ると、設定ミス1つが即座に情報漏洩につながるリスクを抱えています。
Rustプロキシによる追加の検証層というアプローチは、多層防御の発想として理にかなっていますが、新しい単一障害点を生む可能性も同時に抱えます。
導入を検討するなら、まずは自社のPostgreSQL接続経路とRLSポリシーの現状を棚卸しし、プロキシ追加によるレイテンシ増加がSLOの許容範囲に収まるかを見積もるところから始めるのが現実的です。
GitHub上のコードを読み、ステージング環境で負荷テストを行ってから本番導入を判断する進め方が、インフラの可用性を守るうえで堅実な一歩になります。