EXERCISE 60分

ストーリー

高橋アーキテクト
理論を学んだら、設計に落とし込む番だ

高橋アーキテクトが要件書を渡しました。

高橋アーキテクト
マルチテナント対応のSaaS プロジェクト管理ツールの認証・認可アーキテクチャを設計してほしい。ゼロトラストの原則を取り入れつつ、実用的な設計を目指そう

課題概要

項目内容
対象システムマルチテナント SaaS プロジェクト管理ツール
課題数4つ
合計時間60分
評価基準各課題の設計ドキュメントを作成すること

システム要件

  • テナント(組織)ごとにプロジェクトとタスクを管理
  • ロール: オーナー、管理者、メンバー、ゲスト
  • 外部IdP(Google、GitHub)でのSSO対応
  • APIはモバイルアプリとWebアプリから利用

課題1: 認証方式を選択しよう(15分)

要件に基づいて最適な認証方式を選択し、理由を説明してください。

検討ポイント

  • Web/モバイルの両対応
  • SSO(Google、GitHub)対応
  • セッション管理方式
  • MFAの組み込み方
解答例(自分で設計してから確認しよう)

選択: OIDC + JWT

理由:

  1. OIDC: Google/GitHubとのSSO連携に標準対応
  2. JWT: Web/モバイル両方でステートレスに認証可能
  3. アクセストークン: 短命(15分)のJWT
  4. リフレッシュトークン: 長命(7日)、DBに保存して無効化可能
// 認証フロー設計
const authFlow = {
  // 1. SSO認証
  ssoLogin: "OIDC Authorization Code Flow + PKCE",

  // 2. トークン設計
  tokens: {
    accessToken: {
      type: "JWT",
      expiry: "15min",
      claims: ["sub", "tenantId", "role", "permissions"],
    },
    refreshToken: {
      type: "opaque",
      expiry: "7days",
      storage: "database(無効化可能)",
    },
  },

  // 3. MFA
  mfa: {
    method: "TOTP(Google Authenticator互換)",
    required: "管理者以上は必須、メンバーは任意",
    enforcement: "ログイン時 + 機密操作時",
  },
};

課題2: ロールと権限を設計しよう(15分)

4つのロール(オーナー、管理者、メンバー、ゲスト)の権限マトリクスを作成してください。

解答例(自分で設計してから確認しよう)
type Role = "owner" | "admin" | "member" | "guest";

const permissionMatrix: Record<Role, string[]> = {
  owner: [
    "tenant:manage",        // テナント設定の変更
    "tenant:billing",       // 課金管理
    "members:invite",       // メンバー招待
    "members:remove",       // メンバー削除
    "members:role:change",  // ロール変更
    "projects:create",
    "projects:read",
    "projects:update",
    "projects:delete",
    "tasks:create",
    "tasks:read",
    "tasks:update",
    "tasks:delete",
    "tasks:assign",
  ],
  admin: [
    "members:invite",
    "members:remove",
    "projects:create",
    "projects:read",
    "projects:update",
    "projects:delete",
    "tasks:create",
    "tasks:read",
    "tasks:update",
    "tasks:delete",
    "tasks:assign",
  ],
  member: [
    "projects:read",
    "tasks:create",
    "tasks:read",
    "tasks:update",  // 自分が担当のタスクのみ
    "tasks:assign",  // 自分へのアサインのみ
  ],
  guest: [
    "projects:read",  // 招待されたプロジェクトのみ
    "tasks:read",     // 招待されたプロジェクトのタスクのみ
  ],
};

権限マトリクス表:

操作オーナー管理者メンバーゲスト
テナント設定変更oxxx
メンバー招待ooxx
プロジェクト作成ooxx
プロジェクト閲覧oooo(制限付)
タスク作成ooox
タスク編集ooo(自分のみ)x
タスク削除ooxx

課題3: テナント分離を設計しよう(15分)

テナント分離のモデルを選択し、実装方針を記述してください。

解答例(自分で設計してから確認しよう)

選択: 行レベル分離(RLS) + テナントコンテキスト自動付与

理由:

  • SaaS のスケーラビリティを考慮(テナント数が多くなる想定)
  • PostgreSQL のRLSで DB レベルでの強制分離
  • コスト効率が良い
// 1. テナントIDの伝播
const tenantMiddleware = async (req: Request, res: Response, next: NextFunction) => {
  const tenantId = req.user.tenantId;

  // DBセッションにテナントIDを設定
  await db.query("SET app.current_tenant = $1", [tenantId]);
  req.tenantId = tenantId;
  next();
};

// 2. Prismaでの自動フィルタリング
const tenantPrisma = (tenantId: string) => {
  return prisma.$extends({
    query: {
      project: {
        async findMany({ args, query }) {
          args.where = { ...args.where, tenantId };
          return query(args);
        },
      },
      task: {
        async findMany({ args, query }) {
          args.where = { ...args.where, tenantId };
          return query(args);
        },
      },
    },
  });
};

// 3. キャッシュキーにテナントIDを含める
const cacheKey = (tenantId: string, resource: string, id: string) => {
  return `tenant:${tenantId}:${resource}:${id}`;
};

課題4: ゼロトラストポリシーを定義しよう(15分)

コンテキストベースのアクセス制御ポリシーを3つ以上定義してください。

解答例(自分で設計してから確認しよう)
const zeroTrustPolicies: Policy[] = [
  {
    name: "テナント設定変更はMFA必須",
    condition: (ctx) =>
      ctx.action.startsWith("tenant:") &&
      !ctx.subject.mfaVerified,
    effect: "deny",
    action: "require_mfa",
  },
  {
    name: "不審なIPからのアクセスは追加認証",
    condition: (ctx) =>
      ctx.environment.riskScore > 60 ||
      ctx.environment.geoLocation !== ctx.subject.usualLocation,
    effect: "deny",
    action: "step_up_auth",
  },
  {
    name: "非管理端末からのデータエクスポート禁止",
    condition: (ctx) =>
      ctx.action === "data:export" &&
      ctx.environment.deviceTrust !== "managed",
    effect: "deny",
    action: "block",
  },
  {
    name: "深夜の管理操作は制限",
    condition: (ctx) => {
      const hour = ctx.environment.time.getHours();
      return (
        ctx.subject.role === "admin" &&
        ctx.action.includes("delete") &&
        (hour < 6 || hour > 22)
      );
    },
    effect: "deny",
    action: "block_with_notification",
  },
];

達成度チェック

課題テーマ完了
課題1認証方式の選択[ ]
課題2ロールと権限の設計[ ]
課題3テナント分離の設計[ ]
課題4ゼロトラストポリシーの定義[ ]

まとめ

ポイント内容
認証方式要件に基づいてOIDC + JWTなど最適な方式を選択
権限設計ロールと権限のマトリクスを明確に定義
テナント分離スケーラビリティとセキュリティのバランス
ゼロトラストコンテキストベースのポリシーで動的制御

チェックリスト

  • 認証方式を要件に基づいて選択・設計できた
  • ロールと権限のマトリクスを作成できた
  • テナント分離のモデルを選択し実装方針を定められた
  • ゼロトラストポリシーを具体的に定義できた

次のステップへ

お疲れさまでした。認証・認可の設計演習が完了しました。 次はStep 3のチェックポイントです。


推定所要時間: 60分