テナント別設定管理
このドキュメントの目的
マルチテナントSaaSにおけるテナントごとの設定管理を理解し、コード変更なしでテナントの挙動をカスタマイズする設計ができるようになることが目標です。
テナントオンボーディング設計ではテナントの作成・管理・削除のライフサイクルを学びました。本記事では、作成したテナントの設定・カスタマイズをどう管理するかに焦点を当てます。
具体例について: 本 記事ではIDサービスを題材にした例(MFAポリシー、認証方式、セッション設定等)を使用していますが、設定駆動アーキテクチャの原則はSaaS全般に共通です。
設定駆動アーキテクチャ
基本的な考え方
マルチテナントSaaSでは、テナントごとに異なる要件(認証方式、UIテーマ、機能制限等)があります。これをテナントごとにコードを分岐させて実装すると、コードベースが急速に複雑化します。
アンチパターン: コードによる分岐
if (tenant == "company-a") {
// MFA必須
} else if (tenant == "company-b") {
// パスワードのみ
} else if (tenant == "company-c") {
// FIDO2
}
// テナントが増えるたびにコード変更...
設定駆動アーキテクチャでは、テナントの挙動をコードではなく設定データで制御します。
設定駆動アーキテクチャ:
┌─── ───────────┐ ┌──────────────┐ ┌──────────────┐
│ Tenant A設定 │ │ Tenant B設定 │ │ Tenant C設定 │
│ │ │ │ │ │
│ mfa: required│ │ mfa: disabled│ │ mfa: optional│
│ session: 1h │ │ session: 8h │ │ session: 4h │
└──────┬───────┘ └──────┬───────┘ └──────┬───────┘
│ │ │
└────────────────────┼────────────────────┘
│
▼
┌──────────────────┐
│ 共通エンジン │
│ │
│ 設定を読み取り │
│ 挙動を動的に変更 │
└──────────────────┘
メリット:
- テナント追加時にコード変更が不要
- テナント管理者が自分で設定を変更可能
- テスト容易性(設定のバリエーションをテストすればよい)
- デプロイなしで挙動を変更可能
設定のカテゴリ
テナント設定は大きく以下のカテゴリに分類されます。
1. 認証・セキュリティ設定
テナントの認証ポリシーやセキュリティ要件を制御します。
| 設定項目 | 説明 | 値の例 |
|---|---|---|
| 認証方式 | 許可する認証方式 | password, fido2, sms_otp |
| MFAポリシー | MFAの要求レベル | required, optional, disabled |
| パスワードポリシー | パスワードの複雑性要件 | 最小長: 8, 大文字必須: true |
| セッション有効期限 | セッションタイムアウト | 3600秒, 28800秒 |
| ロックアウトポリシー | 連続失敗時のアカウントロック | 試行回数: 5, ロック時間: 30分 |
2. UI・ブランディング設定
テナントごとのルック&フィールをカスタマイズします。
| 設定項目 | 説明 | 値の例 |
|---|---|---|
| ロゴURL | ログイン画面のロゴ | https://example.com/logo.png |
| プライマリカラー | テーマカラー | #1a73e8 |
| ログインページテキスト | カスタムメッセージ | "Welcome to Company A Portal" |
| フッターリンク | 利用規約等のリンク | [{label, url}, ...] |
3. 機能・ポリシー設定
テナントが利用可能な機能やリソース制限を制御します。
| 設定項目 | 説明 | 値の例 |
|---|---|---|
| 最大ユーザー数 | テナント内のユーザー上限 | 100, 1000, unlimited |
| 許可されるGrant Type | OAuth 2.0のGrant Type | authorization_code, client_credentials |
| API レート制限 | 1秒あたりのリクエスト数 | 100, 1000, 10000 |
| ストレージ容量 | データ保存の上限 | 1GB, 10GB, 100GB |
4. 連携・統合設定
外部サービスとの連携設定です。
| 設定項目 | 説明 | 値の例 |
|---|---|---|
| 外部IdP連携 | フェデレーション設定 | Google, Azure AD, SAML |
| Webhook URL | イベント通知先 | https://customer.com/webhook |
| メール送信設定 | カスタムSMTP設定 | smtp.customer.com |
設定の階層化
オーバーライドモデル
すべてのテナントに個別の設定を1から定義するのは非効率です。階層化により、共通設定を共有しつつテナント固有の差分だけを管理します。
優先度(高い方が優先)
┌─────────────────────────────┐
│ レベル3: テナント個別設定 │ ← テナント管理者が設定
│ 例: session_timeout = 1800 │
├─────────────────────────────┤
│ レベル2: プラン別デフォルト │ ← プラン(Free/Standard/Enterprise)
│ 例: session_timeout = 3600 │
├─────────────────────────────┤
│ レベル1: システムデフォルト │ ← 全テナント共通のベースライン
│ 例: session_timeout = 7200 │
└─────────────────────────────┘
解決結果:
Tenant A (Enterprise, 個別設定あり) → session_timeout = 1800
Tenant B (Standard, 個別設定なし) → session_timeout = 3600
Tenant C (Free, 個別設定なし) → session_timeout = 7200
設定解決アルゴリズム
resolve(tenant_id, key):
1. テナント個別設定にkeyがあるか? → あればその値を返す
2. テナントのプラン別設定にkeyがあるか? → あればその値を返す
3. システムデフォルト設定のkeyの値を返す
階層化の利点
| 観点 | 説明 |
|---|---|
| 運用効率 | 大半のテナントはデフォルト設定で動作する |
| 一貫性 | システムデフォルトを変更すると全テナントに反映 |
| 柔軟性 | 特定テナントだけ異なる設定が可能 |
| 可視性 | テナントの設定がデフォルトからどう異なるか明確 |
設定のマージ戦略
設定がネスト構造(オブジェクト)の場合、マージ方法を明確にする必要があります。
浅いマージ(Shallow Merge):
システムデフォルト:
password_policy:
min_length: 8
require_uppercase: true
require_number: true
テナント個別設定:
password_policy:
min_length: 12
結果(浅いマージ):
password_policy:
min_length: 12
# require_uppercase, require_number は消える!
深いマージ(Deep Merge):
結果(深いマージ):
password_policy:
min_length: 12 ← テナント個別
require_uppercase: true ← デフォルトから継承
require_number: true ← デフォルトから継承
推奨: 一般的に深いマージの方が直感的で安全です。ただし、配列値やnull値の扱いについてルールを明確に定義する必要があります。
Feature Flags
テナント単位のFeature Flags
新機能をテナント単位でON/OFFする仕組みです。全テナント一 斉リリースではなく、段階的にロールアウトできます。
Feature Flags テーブル:
┌─────────────────┬─────────────┬─────────┬─────────┬─────────┐
│ Feature │ Global │ Plan │ Tenant A│ Tenant B│
├─────────────────┼─────────────┼─────────┼─────────┼─────────┤
│ new_login_ui │ disabled │ - │ enabled │ - │
│ fido2_support │ disabled │ Ent:on │ - │ enabled │
│ batch_import │ enabled │ Free:off│ - │ - │
│ audit_export │ enabled │ - │ - │ - │
└─────────────────┴─────────────┴─────────┴─────────┴─────────┘
解決:
Tenant A (Standard): new_login_ui=on, fido2_support=off, batch_import=on
Tenant B (Enterprise): new_login_ui=off, fido2_support=on, batch_import=on
Feature Flagのライフサイクル
1. 導入 2. ロールアウト 3. 全体有効化 4. 削除
(disabled) (段階的に有効化) (全テナントON) (フラグ除去)
┌──────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────┐
│ コード内に │ → │ 一部テナント │ → │ 全テナント │ → │ フラグ │
│ フラグ追加 │ │ で有効化 │ │ 有効化 │ │ コード削除│
└──────────┘ └──────────────┘ └──────────────┘ └──────────┘
重要: Feature Flagは一時的なものです。全テナントで有効化した後は、フラグのチェックコードを削除します。放置すると「Feature Flag地獄」になり、コードの可読性が著しく低下します。
段階的ロールアウト戦略
| 段階 | 対象 | 目的 |
|---|---|---|
| Canary | 社内テナント(1テナント) | 初期バグの発見 |
| Early Adopter | 協力的な顧客(5〜10テナント) | 実環境でのフィードバック |
| Gradual Rollout | プラン別に段階拡大 | リスクの段階的軽減 |
| General Availability | 全テナント | 全体有効化 |
設定変更の安全性
バリデーション
設定変更時には、値の妥当性を検証します。
バリデーション層:
設定変更リクエスト
│
▼
┌──────────────────┐
│ 1. 型チェック │ session_timeout: "abc" → エラー
├──────────────────┤
│ 2. 範囲チェック │ session_timeout: -1 → エラー
├──────────────────┤
│ 3. 整合性チェック │ mfa: required + 認証方式: password_only → エラー
├──────────────────┤
│ 4. 権限チェック │ Free planでEnterprise機能 → エラー
└──────────────────┘
│
▼ すべてパス
設定を適用
バリデーションルールの例
| ルール種別 | 例 | エラーメッセージ |
|---|---|---|
| 型 | session_timeout は整数 | "session_timeout must be an integer" |
| 範囲 | 300 ≤ session_timeout ≤ 86400 | "session_timeout must be between 300 and 86400" |
| 整合性 | MFA必須なら認証方式にMFA対応が含まれること | "MFA-capable auth method required when MFA is mandatory" |
| 権限 | Free planではカスタムドメイン不可 | "Custom domain is not available on Free plan" |
| 依存関係 | FIDO2を有効にするにはRP ID設定が必要 | "rp_id is required when fido2 is enabled" |
ドライラン
設定変更を実際に適用する前に、影響を確認できる仕組みです。
ドライラン リクエスト:
PUT /tenants/{id}/config?dry_run=true
{
"session_timeout": 300,
"mfa_policy": "required"
}
ドライラン レスポンス:
{
"valid": true,
"changes": [
{
"key": "session_timeout",
"current": 3600,
"proposed": 300,
"impact": "全アクティブセッションが5分後に期限切れ"
},
{
"key": "mfa_policy",
"current": "optional",
"proposed": "required",
"impact": "MFA未設定の42ユーザーが次回ログイン時にMFA登録必要"
}
]
}
ロールバック
設定変更が問題を引き起こした場合に、以前の設定に戻す仕組みです。
設定変更の履歴:
Version 1 (2024-01-01) ← 初期設定
Version 2 (2024-03-15) ← MFA有効化
Version 3 (2024-06-01) ← セッション短縮 ← 現在
│
│ 問題発生!
▼
Version 2にロールバック
ロールバック設計のポイント:
- 設定変更のたびにバージョンを記録する
- 任意のバージョンにロールバック可能にする
- ロールバック自体も新しいバージョンとして記録する(履歴の完全性)
- ロールバックにもバリデーションを適用する(古い設定が現在の制約に適合するか)