multitenant について
マルチテナントアプリケーションを構築する開発者向けに、分離方式、セキュリティ上の不変条件、実装例をまとめた資料です。共有スキーマから専用データベースまでの分離段階に加え、RLS、アクセス制御、移行時の考慮点を扱います。
主な機能
- 01テナントデータ分離の3段階
- 02tenant_idの伝播とPostgreSQL RLS
- 03テナント分離テストの要件
- 04監査証跡とフィールド単位の暗号化
- 05RBACとABACの選択指針
- 06LaravelとSymfonyの例
活用シーン
- 01顧客区分に応じた分離方式の選択
- 02テナント間の誤ったデータアクセスの防止
- 03テナント専用構成への移行計画
- 04アクセス制御と機密フィールド保護の設計
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ thebeardedbearsas/ claude-craft --skill multitenantインストール後、Claude Code で/multitenantを入力して読み込まれたか確認します。
同梱ファイルREFERENCE.md
詳細
マルチテナント — クイックリファレンス
厳格な分離とインフラコストの管理を両立しながら、同じコードベースで複数のクライアント(テナント)にサービスを提供します。
3 段階の分離
| ティア | 分離方式 | コスト | ユースケース |
|---|---|---|---|
| ティア 1 — 共有スキーマ | すべての場所に tenant_id 列を追加し、SQL フィルターを自動適用 | 低 | スタートアップ、無料プラン/小規模クライアント |
| ティア 2 — 専用スキーマ | テナントごとに PostgreSQL スキーマを用意 | 中 | 中小企業、厳格な要件を持つクライアント |
| ティア 3 — 専用 DB | テナントごとにデータベース全体を用意 | 高 | 大企業、厳格なコンプライアンス要件(HDS、FedRAMP) |
移行ルール:まずティア 1 から始め、クライアントの売上比率が 20 % を超えた場合、または専用 SLA を求められた場合に、ティア 2/3 へ移行します。
絶対に守るべき 5 つの不変条件
- すべてのリクエストに
tenant_idを伝播させる(AsyncLocalStorage/SecurityContext/ミドルウェア)。 - PostgreSQL の行レベルセキュリティ(RLS)をすべてのテーブルで有効にする。 アプリケーション側の設定漏れを防ぐ安全網です。
- 分離テストを必須にする。 テナント A がテナント B のデータを読み書きできてはなりません。ソート、サブクエリ、集計を介したアクセスも対象です。
- 監査証跡をテナントごとに分離する。 明示的な許可なしに、複数テナント間で相互参照できるログを作成してはなりません。
- PII/機密性の高いシークレットにフィールドレベル暗号化を適用する(Halite PHP、Eloquent Casts、libsodium)。
最小パターン — 共有スキーマ + RLS
ALTER TABLE invoices ADD COLUMN tenant_id UUID NOT NULL;
ALTER TABLE invoices ENABLE ROW LEVEL SECURITY;
CREATE POLICY tenant_isolation ON invoices
USING (tenant_id = current_setting('app.tenant_id')::uuid);
// Symfony — middleware qui set la variable session pour RLS
$conn->executeStatement(
'SET LOCAL app.tenant_id = :tid',
['tid' => $tenantId]
);
重大なアンチパターン
- ❌ raw クエリで
tenant_idフィルターを忘れる → テナント間のデータ漏えいにつながります。 - ❌ Redis キャッシュにテナントのプレフィックスがない → A のデータが B に返されます。
- ❌ 非同期ジョブのワーカーで
tenant_idが失われる → コンテキストを特定できなくなります。 - ❌ 署名付き URL/トークンのペイロードに
tenant_idがない → テナントをまたいで利用できます。 - ❌ 共有の単一キーでフィールドを暗号化する → 侵害されるとすべてのデータが露出します(テナントごとのキーを推奨)。
RBAC/ABAC
- RBAC:グローバルロール(
admin、member、viewer)で、ケースの 80 % に対応できます。 - ABAC:ルールが属性(地域、金額、ステータス)に依存する場合は、ポリシー(Casbin、Cerbos、OPA)に移行します。
さらに詳しく
各ティアの詳細なパターン、ダウンタイムなしでのティア 1 → ティア 2 移行、分離テスト(Pest + テナントのフィクスチャ)、RBAC/ABAC、Laravel + Symfony の例、フェーズ別チェックリストについては、
@.claude/skills/multitenant/REFERENCE.mdを参照してください。
コメント
Markdown 対応