• ホーム
    • 企業別練習
    • 面接練習
    • 求人募集
    • 対策記事
    • Webテスト対策
    • メッセージ
  1. トップ
  2. /
  3. 対策記事
  4. /
  5. 中途向け
  6. /
  7. ケース面接
  8. /
  9. 技術設計面接の解説と模範解答|SaaSの権限分離

技術設計面接の解説と模範解答|SaaSの権限分離

ケース面接

2026/11/03

技術設計面接の解説と模範解答|SaaSの権限分離

目次
  • より詳しい情報はこちら


  • 事前知識:権限モデルと最初の仮説


  • 申請を開いてよいかを決めるデータ


  • それぞれの方式で何が起きるか


  • 方式を比べる


  • 他社のデータをどこで止めるか


  • 最初の仮説


  • お題と要件


  • 権限モデルの選び方に関わる前提


  • それ以外の前提


  • 隠れていた前提を見直す


  • 前提どうしのぶつかり


  • 仮説の答え合わせ


  • 解説:このお題の論点


  • 模範解答


  • 1. 作る範囲


  • 2. 見積もり


  • 3. データモデル


  • 4. 全体構成


  • 5. 深掘り:テナントの境界


  • 6. 深掘り:判定の置き場所


  • 7. 深掘り:権限モデル


  • 8. 障害への備えと監視


  • 9. 条件の変更への対応


  • まとめ:選んだものと捨てたもの


  • よくあるつまずき


  • 参照元


技術設計面接(システムデザイン面接)のお題「SaaSの権限分離」を題材に、事前に押さえておく知識、面接で引き出せる前提、論点、模範解答、よくあるつまずきを順に解説します。

ほかのお題の解説は技術設計面接の解説と模範解答まとめにあります。

より詳しい情報はこちら

この記事で使う設計の基礎は、日本語のシステムデザイン面接の教材 SystemDesign InterviewCat で詳しく学べます。この記事の各節に関係する章は次のとおりです。

InterviewCat の章

この記事で関係する節

イントロダクション(無料)

SystemDesign InterviewCat の全体像

システムデザイン面接のコンプリートガイド

面接で見られることと進め方

ユーザーを認証・認可する

事前知識、6. 判定の置き場所

SaaSのマルチテナントを設計する

5. テナントの境界

API Gatewayでマイクロサービスの入口を作る

4. 全体構成(入口で必ず通す判定)、代わりの案

キャッシュを使ったパフォーマンスの向上

6. 判定の置き場所(権限データのキャッシュと反映)

データベースインデックス

2. 見積もり、6. 一覧の絞り込み

全文検索を導入する

5. テナントの境界(検索の境界)

メッセージキューとデータベースの書き込みを同一のトランザクション内で実行する

3. データモデル(権限の変更と変更履歴を同時に書く)

事前知識:権限モデルと最初の仮説

設計面接では、お題を聞いた時点で「たぶんこの作りだろう」という仮説を持ち、前提を聞くたびにそれを確かめたり崩したりします。権限の仕組みのお題なら、まず「誰が、どのデータに、どの操作をしてよいか」をどういう形のデータと規則で表すかの選択肢を押さえておきます。この表し方を権限モデルと呼びます。あわせて、他社のデータをどこで止めるかも押さえておきます。

申請を開いてよいかを決めるデータ

経理担当の佐藤さんが、営業第一課の鈴木さんが出した申請を開こうとしたとします。開いてよいかを決めるとき、判定は次のデータをたどります。権限モデルの違いは、このうちどこまでを見るかの違いです。

佐藤さんから割り当てを通ってロールと範囲へ、範囲から申請へたどるデータのつながりと、方式ごとに見る範囲
判定がたどるデータ。下の 3 本の線と上の線は、方式ごとに判定がどこまでを見るか
  • 認可:利用者に、その操作を許すかを決めること
  • 操作:「申請を見る」「申請を承認する」のような、許すかどうかを決める単位
  • ロール:操作をまとめて名前を付けたもの(管理者、経理担当など)
  • 割り当て:利用者にロールを与える記録。図では佐藤さんに経理担当を与えている
  • 範囲:割り当てが当てはまるデータの広さ(全社、ある部署とその配下、あるプロジェクト)

それぞれの方式で何が起きるか

佐藤さんが鈴木さんの申請を開いたとき、方式ごとに判定で起きることを並べます。

RBAC(ロールベースのアクセス制御):利用者にロールを割り当て、ロールに操作を持たせます。図の 1 本目の線のとおり、判定は「佐藤さんのロールのどれかが『申請を見る』を含むか」で終わるので速く、各社の管理者にも仕組みが分かりやすいです。弱いところは、どのデータに対して許すかを表せないことです。佐藤さんは営業部の申請も開発部の申請も同じように開けます。「自部署の申請だけ見られる経理」を作るには「営業部の経理」「開発部の経理」のように部署の数だけロールを作ることになり、部署が増えるたびにロールも増えます。

範囲つきの RBAC:RBAC の割り当てに範囲を持たせます。図の 2 本目の線のとおり、判定は範囲の箱まで進み、申請の部署(営業第一課)が佐藤さんの範囲(営業部とその配下)に入るかを見ます。ロールは経理担当 1 つのまま「自部署だけ」「特定プロジェクトだけ」を表せます。一覧の絞り込みも「申請の部署がこの部署 ID のどれかに入る」という SQL の条件にそのまま変えられます。RBAC と比べて管理者が選ぶものは範囲が 1 つ増えるだけです。弱いところは、データ 1 件ごとに変わる関係を表せないことです。「自分の申請だけ編集できる」「申請者の上位役職者だけが承認できる」は、どの割り当てを作っても書けません。

ABAC(属性ベースのアクセス制御):利用者、データ、操作、環境(時刻や接続元など)の属性を、規則に当てはめて判定します。図の 3 本目の線のとおり申請の属性まで見るので、「申請の部署が、佐藤さんの所属部署の配下にあり、佐藤さんの役職が鈴木さんより上」のような条件も規則として書けます。表せる条件は RBAC よりずっと広いです。RBAC と比べると、管理者が規則を条件式で書く必要があり、「この人は何ができるか」を一覧で答えにくくなります。また、規則が複雑になると一覧の絞り込みを SQL の条件に変えにくくなります。

ReBAC(関係ベースのアクセス制御):利用者とデータの関係(作成者、共有された人、上位の部署など)をグラフとして持ち、図の上の線のように佐藤さんと申請の関係をたどって判定します。Google の Zanzibar が代表例で、共有の多い文書サービスのように、データごとに見てよい人が変わるサービスに向いています。弱いところは、関係のデータを業務データとは別に持つと、両者をそろえ続ける仕組みが要ることです。一覧の絞り込みにも「見てよい ID の一覧」を取り出す処理が別に要ります。1 つのモノリスと 1 つの RDB に入れるには、仕組みが大きくなります。

方式名は分類の名前で、実際のサービスは組み合わせて使います。設計面接で比べたいのは名前ではなく、各社の管理者が設定する部分と、開発者がコードで決める部分をどこで分けるかです。

方式を比べる

方式の違いは、このお題で出てくる 2 つの要望と、1,000 件の一覧、管理者による設定の 4 つで比べると分かりやすくなります。

方式

自部署の申請だけ見られる経理

申請者の上位役職者だけが承認

1,000 件の一覧を絞る

各社の管理者が設定できるか

RBAC

部署の数だけロールを作る

表せない

ロールで決まるので全件か 0 件

できる

範囲つきの RBAC

割り当ての範囲で表せる

表せない

範囲の部署 ID を SQL の条件にできる

できる(範囲を選ぶだけ)

ABAC

規則で表せる

規則で表せる

規則を SQL の条件に変える仕組みが要る

難しい(条件式を書かせることになる)

ReBAC

部署との関係で表せる

部署の上下はたどれる。役職の上下の比較は別に要る

見てよい ID の一覧を取り出す処理が要る

関係の種類は開発者が決め、管理者は関係を結ぶだけ

表から分かるとおり、管理者が設定しやすい方式(RBAC、範囲つきの RBAC)はデータ 1 件ごとの関係を表せません。それを表せる方式(ABAC、ReBAC)は、規則を条件式で書くか、関係のデータを別に持つ必要があり、一覧の絞り込みにも別の仕組みが要ります。そのため、管理者が設定するのはロールと範囲までにし、データ 1 件ごとの関係は開発者が書く少数の規則に任せる組み合わせが、このお題の出発点になります。

他社のデータをどこで止めるか

権限モデルとは別に、このお題で一番重いのは他社のデータを見せないことです。テナントは、SaaS を契約した単位のことで、このお題では顧客の企業です。多くの企業のデータを 1 つの DB に入れ、どの表にも企業 ID の列を持たせる作りでは、企業 ID の条件をどこで足すかがテナントの境界になります。条件に使う企業 ID は、ログインのときに外部の認証サービス(IdP)が渡す証明(トークン)に、利用者 ID と一緒に入っています。

止める場所

何が起きるか

書き忘れたとき

各 SQL に企業 ID の条件を書く

API ごとに書く

1 か所忘れると他社の行が返る

DB を読み書きする共通処理(リポジトリ層)で条件を足す

共通処理を通る SQL には必ず付く

共通処理を通らない SQL と、DB の外(検索、ファイル)が残る

DB の行レベルセキュリティ(DB 自身が、接続ごとに設定した企業 ID と違う行を返さない機能)

アプリが条件を忘れても DB が絞る

制限を有効にして方針を書き忘れた表は何も返さない。有効にし忘れた表は絞られない

上の 2 つはアプリの中で止め、3 つ目は DB が止めます。止める場所を 2 か所以上に分けておけば、1 か所で書き忘れても他社の行は返りません。

最初の仮説

お題文だけを読んだ段階では、次の仮説を置きがちです。どれも筋は悪くありませんが、前提を聞くと一部が崩れます。答え合わせは「隠れていた前提を見直す」で行います。

仮説

中身

確かめること

1

企業ごとにカスタムのロールを作れる RBAC にすればよい

ロールで表せない条件の要望があるか、設定するのは誰か

2

判定を共通の関数にまとめ、各 API の先頭で呼べばよい

API の数、開発の体制、確認漏れの事故があったか、一覧の速さ

3

トークンの企業 ID を各 SQL の条件に書けば、他社のデータは見えない

書き忘れの事故があったか、1 人が複数の企業を扱う場面、DB 以外の置き場所、代理ログイン

4

権限はログインのときに読み、セッションの間は使い回せばよい

変更の反映までの許容時間、変更履歴の保存

お題と要件

面接官から示されるお題は次のとおりです。

本日はシステムの設計方法についてディスカッションしたいと思います。今、経費精算SaaSで、顧客の会社ごとに誰が何をできるかを細かく設定できる権限の仕組みを作ることを考えています。今は管理者と一般の2つのロールしかないので、申請・承認・差し戻し・支払いデータの出力・マスタの設定などの操作ごとに、誰に許すかを企業ごとに設定できるようにしたいです

▼このお題は CaseMatch の AI 面接で、面接官に前提を質問しながら練習できます。

前提は質問すれば答えてもらえます。面接で引き出せる前提を、権限モデルの選び方に関わるものとそれ以外に分けて並べます。種類の列は、機能要件、非機能要件、制約、将来のどれにあたるかです。設計への影響の列は、次の節の問いを考えてから読んでください。

権限モデルの選び方に関わる前提

事前知識の比較表の 4 つの比べ方(自部署だけ、上位役職者だけ、一覧の絞り込み、管理者による設定)と、判定の速さ、反映の速さを決める前提です。

種類

前提

値

設計への影響

機能

要望

大口企業から「自部署の申請だけ見られる経理」「特定プロジェクトの申請だけ承認できる人」の要望がある

ロールだけでは表せず、割り当てに範囲が要る

機能

承認者

承認できるのは申請者の所属部署の上位役職者に限る。部署は最大6階層で、異動や兼務(1人が複数部署)がある

申請ごとに変わる関係で、開発者が書く規則になる

機能

自社定義

経理担当・承認者などを自社定義したい大口企業が多い

企業ごとのカスタムのロールが要る

制約

設定する人

ロールを設定するのは各社の管理者で、ITに詳しくない人が多い

管理者に規則を書かせられない

非機能

操作の数

約150操作、新機能で増加

操作を画面で 1 つずつ選ばせると管理者が迷う

非機能

操作の増え方

新機能は月に2〜3個増え、そのたびに操作が増える

新しい操作を誰に許すかの既定値が要る

非機能

性能

判定10ms以内、1,000件一覧1秒以内

一覧を 1 件ずつ判定できない

非機能

反映

ロール・割り当て変更は1分以内に反映

権限をセッションの間ずっと使い回せない

制約

移行

今の「管理者」「一般」の利用者は、移行後も今と同じ操作ができる必要がある

今の 2 つを標準のロールとして再現する

それ以外の前提

テナントの境界、判定の置き場所、移行の進め方のように、どの権限モデルを選んでも別に設計が要る前提です。

種類

前提

値

設計への影響

機能

目標

新しい操作を足すたびに権限チェックを書き忘れる事故を、仕組みで起きないようにしたい

判定を呼ぶかどうかを各 API に任せない

制約

範囲

ログインや認証の仕組みは変えない

トークンの中身を前提に作る

非機能

規模

400社、最大2万人

1 人分の権限データは小さく、利用者ごとにキャッシュできる

非機能

企業の大きさ

1社あたりの平均は約50名、1万人を超える企業が5社

大きな企業では範囲の部署が多く、一覧の条件が重くなる

制約

DB

DBはRDB 1つで、全テーブルに企業IDの列がある

企業 ID の絞り込みを書き忘れると他社の行が返る

制約

API

バックエンドはモノリスで、APIは約400本

判定は同じプロセスの中のモジュールで足りる

制約

認証

認証は外部のIdPで、トークンには利用者IDと企業IDが入っている

企業 ID は 1 つしか入っていない

制約

モバイル

承認用のモバイルアプリも同じAPIを使い、古い版のアプリが残り続ける

画面でボタンを隠すことを守りにできない

制約

今の判定

APIごとのif文で判定、確認漏れで別企業データが見えた事故が1件

書き忘れても漏れない作りが要る

非機能

漏えい

他社データの漏えいを絶対に許さない

判定とは別の層でも他社の行を止める

非機能

履歴

権限の変更履歴は7年保存する(SOC2の取得を予定)

変更と同時に、書き換えない履歴を残す

機能

代理ログイン

サポート担当が、顧客の許可を得て代理でログインする運用がある

誰が誰として操作したかを両方残す

制約

体制

開発はバックエンド8名で、機能ごとのチームが並行して開発している

判定の書き方をチームごとにばらつかせない

機能

会計事務所

会計事務所が、顧問先の複数の企業を1つのアカウントで操作したい

トークンの企業 ID だけでは操作中の企業が決まらない

制約

移行期間

移行は1年かけて段階的に進め、その間も機能開発は止めない

古い判定と新しい判定を並べて切り替える

隠れていた前提を見直す

お題文は「操作ごとに、誰に許すかを企業ごとに設定したい」としか言っていません。前提の表は、質問して初めて出てきたものです。設計への影響を見る前に、あらためて前提を読み直し、お題文の裏に何が隠れていたかを考えます。先に次の問いを考えてから、前提の表の「設計への影響」の列と見比べてください。

  1. 前提のうち、互いにぶつかっている 2 つの組を 3 組挙げてください。
  2. トークンの企業 ID だけで絞れない場面を、前提から 2 つ挙げてください。
  3. 最初の仮説 1〜4 のうち、どれがどの前提で崩れますか。
  4. お題文からは読み取れなかったのに、設計を一番大きく変えた前提はどれですか。

前提どうしのぶつかり

前提の多くは単独では難しくありません。難しいのは 2 つが互いに逆を向いているところで、このお題では次の 3 組です。これがそのまま、面接の後半で詳しく問われる 3 つの論点(深掘り)になります。

ぶつかる前提

なぜぶつかるか

解き方

他社データの漏えいを許さない × 会計事務所が複数企業を 1 つのアカウントで操作、サポートの代理ログイン

1 人が複数の企業に入れるようにすると、トークンの企業 ID で絞るだけでは足りず、境界の決め方が緩くなる

1 つのリクエストで扱う企業を 1 つに決め、その企業 ID の条件をリポジトリ層と DB の 2 か所で必ず付ける

判定を 1 か所に集めて書き忘れをなくす × 1,000 件の一覧を 1 秒以内

1 か所の判定関数を 1 件ずつ呼ぶと、一覧では判定が 1,000 回になる

同じ規則から、1 件の判定と一覧の SQL の条件の両方を作る

大口企業の細かい要望 × 設定するのは IT に詳しくない管理者

表せる条件を増やすほど、管理者が設定する項目が増えて難しくなる

管理者が選ぶのはロールと範囲だけにし、データ 1 件ごとの関係は開発者が書く規則にする

仮説の答え合わせ

仮説

崩した前提

置き換え

1. カスタムのロールを作れる RBAC

自部署だけ、特定プロジェクトだけ、上位役職者だけ

カスタムのロールは残す。割り当てに範囲を持たせ、上位役職者や自分の申請のような関係は開発者が書く規則にする

2. 共通の関数を各 API の先頭で呼ぶ

API 400 本、8 名が並行開発、確認漏れの事故、1,000 件一覧 1 秒

呼ぶかどうかを各 API に任せず、操作の宣言が無い API は動かないようにする。一覧は SQL の条件で絞る

3. トークンの企業 ID を各 SQL に書く

会計事務所、代理ログイン、確認漏れの事故

操作中の企業は、全 API が最初に通る共通処理(入口)で 1 つに決めてから絞る。絞り込みはリポジトリ層と DB の両方で行い、検索やファイル置き場にも企業 ID を持たせる

4. ログイン時に読んで使い回す

1 分以内の反映

企業ごとの権限の更新番号をキャッシュのキーに入れ、変更のたびに番号を上げる

このお題はロールの種類を増やす話に見えます。しかし実際に問われるのは、400 社が 1 つの DB を使う中で、絞り込みを 1 つ書き忘れても他社のデータが出ない作りと、判定を 1 か所に集めて一覧や画面と食い違わない作りです。

解説:このお題の論点

論点は 3 つあり、重さの順にテナントの境界、判定の置き場所、権限モデルです。一番重いのは他社のデータが見えないことで、DB、検索、キャッシュ、ファイル置き場のどこで境界を守るかを決め、条件を 1 つ書き忘れても漏れない作りにできるかが問われます。次に、判定を 1 か所に集め、API、一覧の絞り込み、画面の表示が食い違わないようにできるかです。権限モデル(標準とカスタムのロール、ロールで表せない条件の扱い)はその次で、ログインの方式には深入りしなくて構いません。

模範解答の深掘り(5〜7)では、論点ごとに「弱い答え」「よい答え」「より良い答え」を並べ、何が足りないかを示しています。

模範解答

面接での問答の順には合わせず、このお題への答えを 1 つの設計としてまとめた解答例です。設計の筋は、判定を 1 つの認可モジュールに集めて API の入口で必ず通し、他社のデータはそれとは別にリポジトリ層と DB の 2 か所でも止め、管理者にはロールと範囲だけを設定させる、というものです。前提に無いことは仮定として置き、その旨を書いています。

1. 作る範囲

前提を確かめたうえで、最初に作る範囲を次のように切ります。

  • 作る:操作の一覧の宣言、標準とカスタムのロール、範囲つきの割り当て、認可モジュール(1 件の判定と一覧の条件)、リポジトリ層と DB でのテナントの境界、権限の管理画面、変更履歴、会計事務所の企業の切り替え、代理ログインの記録、今の 2 つのロールからの移行
  • 作らない:ログインと認証の仕組み、認可専用の別サービス、項目単位の権限(金額の列だけを隠すなど。最初は作らないと仮定)

判定は 1 つのモジュールに集めますが、他社のデータを止める役目だけはそのモジュールに任せきらず、リポジトリ層と DB にも持たせます。

2. 見積もり

見積もりで出すのは、構成を決める 3 つの数字だけです。どれも前提の値から計算できます。

見積もり

計算

決まること

一覧の判定

1,000 件を 1 件ずつ判定すると、判定 10ms × 1,000 件 = 最大 10 秒

一覧は 1 件ずつ判定せず、SQL の条件にして 1 回で絞る

移行の速さ

API 400 本 ÷ 約 50 週 = 週に約 8 本

一度に切り替えられないので、新旧の判定を並べ、API ごとに切り替える

操作の数

約 150 操作に、新機能が月に 2〜3 個 × 12 か月 = 年に 24〜36 個加わる

管理者が 1 つずつ選べないので業務のまとまりで並べ、新しい操作の既定値を決める

1 分以内の反映はキャッシュの期限で満たせますが、権限を外したら次のリクエストから拒否したいので、変更のたびに企業ごとの更新番号(権限のデータを変えるたびに 1 つ増やす番号)を上げます(6)。

3. データモデル

操作の一覧はコードで宣言し、DB には「どのロールがどの操作を持ち、誰にどの範囲で割り当てたか」と、規則が使う所属と部署の上下だけを置きます。中心になる表は次の 4 つで、どれも企業 ID の列を持ちます。

表

主な項目

書き換え

ロール

企業 ID、ロール ID、名前、標準かカスタムか、許す操作の一覧

管理者が変えるたびに企業の更新番号を上げる

割り当て

企業 ID、利用者 ID、ロール ID、範囲の種類(全社、部署とその配下、プロジェクト)、範囲 ID

管理者が変えるたびに企業の更新番号を上げる

所属

企業 ID、利用者 ID、部署 ID、役職(兼務は複数行)

異動のたびに企業の更新番号を上げる

部署の上下

企業 ID、上位の部署 ID、配下の部署 ID、階層の差

部署の構成を変えたときに作り直す

部署の上下は、ある部署とそのすべての配下の組を前もって展開した表です。6 階層あっても「この部署の配下すべて」が 1 回の検索で取れるので、範囲の判定にも一覧の条件にも使えます。ロール、割り当て、所属を変えるときは、変更前と変更後の値、操作した人、日時を、同じトランザクションの中で追記のみの変更履歴に書き、7 年残します。

4. 全体構成

利用者のリクエストは、必ず入口と認可モジュールを通ってからデータに届きます。データを取り出すときは、認可モジュールとは別にリポジトリ層と DB が企業 ID で絞ります。

判定は認可モジュールに集め、企業 ID の絞り込みはリポジトリ層と DB でも行う
全体構成:リクエストの処理と権限の設定

色を付けた認可モジュールがこの設計の要で、可否を決める規則はすべてここにあります。

  1. 入口(全 API が最初に通る共通処理):トークンを検証し、利用者 ID と、このリクエストで操作する企業(操作中の企業)を 1 つに決めます。各 API は定義の中で「どの操作にあたるか」を宣言し、入口はその操作を持つロールがあるかを認可モジュールに問い合わせます。宣言の無い API は拒否します。
  2. 認可モジュール(自前):「この利用者は、このデータに、この操作をしてよいか」の判定と、「この利用者がこの操作で見てよい行」を表す SQL の条件の両方を、同じ規則から作ります。
  3. 各 API の処理:申請を読んだあと、その申請に対する判定(範囲に入るか、上位役職者か)を認可モジュールに問い合わせます。
  4. リポジトリ層と RDB:リポジトリ層は操作中の企業の ID を必ず条件に付け、RDB は行レベルの制限で企業 ID の違う行を返しません。
  5. 権限データ:ロール、割り当て、所属、部署の上下を、企業ごとの更新番号つきでキャッシュします。
  6. 権限の管理画面と変更履歴:各社の管理者がロールと範囲を設定します。変更のたびに更新番号を上げ、変更履歴に追記します。
  7. 検索とファイル置き場:申請の検索インデックスと領収書の画像にも企業 ID を持たせ、取り出すときに必ず絞ります。

バックエンドはモノリスで DB も 1 つなので、認可モジュールは同じプロセスの中のライブラリとして置きます。権限データも業務データと同じ RDB に置けるので、両者をそろえ続ける仕組みが要りません。

実例:Airbnb は、モノリスからサービスに分けたときに認可の確認を画面側のサービスに置いたところ、同じ確認があちこちに重複して管理しにくくなりました。そこで確認をデータ側のサービスに移し、判定を集めた Himeji を作っています(InfoQ, 2021)。Figma は、モノリスの中に散らばった権限の判定が DB の負荷の約 2 割を占め、HTTP の API とリアルタイムの API で判定を別々に書いて食い違っていました。規則を宣言的に書く仕組みを作り、規則とデータの読み込みを分けて、どちらの API も同じ規則を使うようにしています(Figma, 2024)。

代わりの案:認可を別のサービスに切り出し、Zanzibar のように関係のデータを専用の保存先に持つ構成もあります。複数のプロダクトで権限を共有したい場合や、サービスを分けたあとで判定を 1 か所に集めたい場合には有力です。今回は、モノリスで DB が 1 つ、開発が 8 名なので、関係のデータを業務データと別に持ってそろえ続ける手間のほうが大きくなります。認可モジュールの関数を「判定」と「一覧の条件」の 2 つに絞っておけば、あとで中身を別サービスに入れ替えても呼び出し側は変わりません。

5. 深掘り:テナントの境界

他社のデータは、認可の判定とは別に、リポジトリ層と DB の 2 か所で止めます。どちらか一方で絞り込みを書き忘れても、もう一方が他社の行を返しません。最初の仮説の 3 は、ここで崩れます。

答えの段階

答え

足りないところ

弱い答え

トークンの企業 ID で、各クエリに WHERE を付けます

1 か所書き忘れると漏れる。前提にある事故がまさにこれ

よい答え

企業 ID の絞り込みをリポジトリ層の共通処理にまとめます

共通処理を通らない SQL と、DB の外(検索、キャッシュ、ファイル置き場)が残る

より良い答え

共通処理と DB の 2 か所で絞り、DB の外にも企業 ID を持たせます

なし(中身は下の 6 つ)

より良い答えの中身は次のとおりです。

  • 操作中の企業を 1 つに決める:入口で、このリクエストが扱う企業を 1 つ決め、リクエストの文脈に入れます。以降の処理は、この企業 ID しか使えません。
  • リポジトリ層で必ず付ける:クエリを組み立てる共通処理が、文脈の企業 ID を必ず条件に足します。文脈に企業 ID が無ければ、クエリを実行せずにエラーにします。共通処理を通らない手書きの SQL は、レビューと静的検査で止めます。
  • DB の行レベルの制限:DB が PostgreSQL なら行レベルセキュリティを使い、接続ごとに設定した企業 ID と一致しない行を返さない方針を全表に付けます。アプリはテーブルの所有者ではない DB ユーザーで接続します(所有者は既定で方針の対象外になるため)。接続プールで前のリクエストの企業 ID が残らないよう、トランザクションを始めるたびに設定し直します。行レベルセキュリティの無い DB なら、この役目はテストで補います。
  • DB の外の境界:検索インデックスの全文書に企業 ID を持たせ、検索の共通処理で必ず条件に足します。キャッシュのキーは企業 ID から始めます。ファイル置き場はパスの先頭を企業 ID にし、取り出すときは認可を通したあとに期限つきの URL を出します。
  • 他社の ID で取れないことのテスト:2 社分のデータを入れ、API の一覧から全 API に他社のデータの ID を渡して、見つからないと返ることを確かめるテストを自動で作ります。新しい API を足すと、テストも自動で増えます。
  • 書き忘れに気づく:リポジトリ層の書き忘れは、DB が同じ企業 ID で絞るので結果に出ず、DB も除いた行を知らせません。そこで上の他社の ID のテストを、行レベルセキュリティの対象外の DB ユーザー(BYPASSRLS を持つもの)でも流し、共通処理だけで他社の行が返らないことを確かめます。

会計事務所と代理ログインは、1 人が自分の企業以外を扱う場面です。どちらも「1 つのリクエストで扱う企業は 1 つ」を守ったまま扱います。

  • 会計事務所:事務所の利用者が操作してよい顧問先を、顧問契約の表に持ちます。顧問契約の表が決めるのは、どの企業に入れるかだけです。顧問先で何ができるかは、顧問先の管理者が顧問先の中で事務所の利用者に付けた割り当てで決めます。利用者は画面で顧問先を選び、リクエストには選んだ企業 ID を付けます。入口は、それが本人の企業か顧問契約の表にある企業のときだけ、操作中の企業として受け入れます。トークンの企業 ID は事務所のままなので、ログインと認証の仕組みは変えずに済みます。
  • 代理ログイン:顧客の許可を、期限と対象の利用者つきの記録として持ちます。代理中のリクエストには「サポート担当の ID」と「代理している利用者の ID」の両方を持たせ、操作の記録に両方を残します。支払いデータの出力や権限の変更のような操作は、代理中は許さないと仮定します。

実例:AWS の SaaS のテナント分離の解説は、認証のときにテナントの文脈を返し、その文脈が以降のすべての処理に渡って、DB などへのアクセスの範囲を決める形を基本に置いています(AWS, 2020)。PostgreSQL の行レベルセキュリティでテナントを分ける方法は、AWS のブログが current_setting で接続ごとのテナント ID を読む方針の例とともに解説しており、テーブルの所有者で接続すると方針が適用されないこと、接続プールとの組み合わせに注意が要ることも挙げています(AWS, 2020)。行レベルセキュリティを有効にして方針が 1 つも無い表は、どの行も見えない状態になります(PostgreSQL)。方針を付け忘れた表は、他社の行を返すのではなく何も返さないということです。

6. 深掘り:判定の置き場所

判定は認可モジュールに集め、API の入口で必ず通します。呼ぶかどうかを各 API に任せず、操作の宣言が無い API は動かないようにします。最初の仮説の 2 と 4 は、ここで崩れます。

答えの段階

答え

足りないところ

弱い答え

認可を共通の関数にまとめます

どこで呼ぶかが決まっておらず、呼び忘れは残る

よい答え

API の入口で、操作の宣言を見て判定します

一覧の絞り込みが別の場所に残り、判定と食い違う

より良い答え

操作の宣言を必須にし、1 件の判定と一覧の条件を同じ規則から作ります

なし(中身は下の 6 つ)

  • 判定は 2 回:入口で 1 回、データを読んだあとに 1 回です。入口では「この操作を持つロールがあるか」だけを見ます。データを読んだあと、各 API の処理が「この申請が範囲に入るか、規則を満たすか」を問い合わせます。どちらも認可モジュールの関数で、規則を書く場所は 1 か所です。
  • 既定で拒否:API の定義に操作の宣言が無いと、起動時と CI で失敗します。ヘルスチェックのように認可の要らない API も「認可不要」と明示して宣言します。新しい API で書き忘れても、拒否されるだけで漏れません。
  • 一覧と詳細の整合:一覧は、認可モジュールが規則から作った SQL の条件(「申請の部署がこの部署 ID のどれか」「申請者が本人」など)をリポジトリ層が付けて、1 回で絞ります。詳細の判定と同じ規則から作るので、一覧には出るのに開くと拒否される、という食い違いが起きません。
  • 画面の表示:API の応答に、そのデータに対してこの利用者ができる操作の一覧を入れ、画面はそれでボタンを出し分けます。古い版のモバイルアプリがボタンを出し続けても、押したときにサーバーで拒否されるので、許されない操作は通りません。
  • 10ms に収める:リクエストの最初に、その利用者の割り当て、所属、範囲の部署の一覧を 1 回で読み、キャッシュします。キャッシュキーは企業 ID、利用者 ID、企業の権限の更新番号の 3 つです。判定はメモリの上で済むので、DB を待ちません。
  • 1 分以内の反映:ロール、割り当て、所属を変えたら、同じトランザクションで企業の更新番号を上げます。次のリクエストは新しい番号のキャッシュキーで読み直すので、すぐに反映されます。更新番号の読み取りに失敗したときに備え、キャッシュの期限も 1 分より短くしておきます。

移行は 1 年かけて API ごとに進めます。新しい認可モジュールを今の if 文と並べて動かし、結果が食い違ったら記録だけします。食い違いが無くなった API から新しい判定に切り替え、今の if 文を消します。機能チームは新しい API から宣言の形で書くので、移行の間も機能開発は止まりません。

実例:OWASP の認可のチートシートは、既定で拒否すること、すべてのリクエストで権限を確かめること、認可の処理に単体テストと結合テストを書くことを挙げています(OWASP)。一覧の絞り込みについては、Oso の文書が、1 件ずつ判定するのではなく見てよいものだけを 1 回で取り出す方法として、認可の規則から SQL の WHERE 句を作ってアプリの DB で絞る形を説明しています(Oso)。Airbnb の Himeji は判定の結果をキャッシュで返し、権限のデータが変わると変更を検出してキャッシュを消しています(InfoQ, 2021)。

7. 深掘り:権限モデル

管理者が選ぶのはロールと範囲だけにし、データ 1 件ごとの関係(自分の申請、上位役職者)は開発者が操作の定義に添える規則にします。最初の仮説の 1 は、ここで崩れます。

答えの段階

答え

足りないところ

弱い答え

RBAC にして、要望が来るたびにロールを増やします

「自部署だけ」を部署の数だけのロールで表すことになる

よい答え

操作、ロール、割り当てを分けて持ち、企業ごとにカスタムのロールを作れるようにします

「自部署だけ」「自分の申請だけ」のような条件を扱えない

より良い答え

割り当てに範囲を持たせ、データごとの関係は開発者が書く規則で判定します

なし(中身は下の 6 つ)

  • 標準のロール:今の「管理者」「一般」を、今と同じ操作を持つ標準のロールとして作り、移行のときに全員をそのまま割り当てます。標準のロールは各社が書き換えられないようにします。
  • カスタムのロール:標準のロールや「経理担当」「承認者」のひな形を複製して始めます。約 150 の操作は「申請」「承認」「支払い」「マスタ」のような業務のまとまりで並べ、IT に詳しくない管理者でも選べるようにします。
  • 範囲:割り当てごとに、全社、部署とその配下、プロジェクトのどれかを選びます。「自部署の申請だけ見られる経理」は、経理担当のロールを自部署の範囲で割り当てれば表せます。
  • 規則:「自分の申請だけ編集できる」「承認できるのは申請者の所属部署の上位役職者」は、操作の定義に添えた規則で判定し、各社は変えられないと仮定します。兼務の人は、申請のときにどの部署として申請したかを申請に記録し、承認者はその部署の上位の部署に所属し、役職が上の人に限ります。判定は承認する時点の所属で行うので、異動した人は前の部署の申請を承認できなくなります。
  • 新しい操作の既定値:操作をコードで宣言するときに、標準のロールに含めるかを必ず決めます。カスタムのロールには自動で足さず(既定で拒否)、管理画面で新しい操作があることを管理者に知らせます。
  • 設定の確かめ方:管理画面で「この人ができること」と「この操作ができる人」を両方向から表示します。管理者が設定の結果を目で確かめられるようにするためです。

実例:NIST は ABAC を、利用者、データ、操作、環境の属性を規則に当てはめて可否を決める方式と定義しています(NIST SP 800-162)。AWS の規範ガイダンスには、RBAC のロールに ABAC の条件(データがその利用者のテナントに属すること)を組み合わせ、1 つの規則の保存先を全テナントで共有する例があります(AWS 規範ガイダンス)。Auth0 のブログは、マルチテナントの RBAC ではロールをテナントごとに持たせ、同じ人がある企業では管理者、別の企業では閲覧者になれるようにする形を説明しています(Auth0, 2024)。

部署やプロジェクトのような関係がさらに増え、データごとに共有相手が変わる機能(申請を特定の人だけに共有するなど)が出てきたら、ReBAC が次の手になります。Google の Zanzibar は、関係のデータを 1 つのデータモデルで表し、数兆のアクセス制御リストを 95 パーセンタイル 10ms 未満で判定しています(Google, 2019)。範囲つきの RBAC で表せなくなったときの次の手として挙げられると、弱いところとその手当てまで言えます。

8. 障害への備えと監視

判定に要るものが読めないときは、許すのではなく拒否します。他社のデータが見えるより、操作が一時的にできないほうを選びます。

止まるもの

利用者に見えること

手当て

権限データのキャッシュ

少し遅くなる

RDB から読み直す。RDB も読めなければ拒否する

更新番号の更新

権限の変更が反映されない

更新番号の更新を権限の変更と同じトランザクションに入れ、キャッシュの期限でも 1 分以内に切り替わるようにする

認可モジュールの規則の誤り

できるはずの操作が拒否される、または許されすぎる

他社の ID のテストと規則のテストを CI で通してからデプロイし、拒否の急増を監視する

リポジトリ層の書き忘れ

変わらない(DB の制限が同じ企業で絞る)

行レベルセキュリティの対象外の DB ユーザーで流すテストで見つけて直す

外部の IdP

新しくログインできない

認証は変えない前提なので、今の運用のまま

監視するのは、API ごとの拒否の数、判定にかかる時間、代理ログイン中の操作です。権限の変更履歴は、変更と同じトランザクションで書くので、変更だけが残って履歴が欠けることはありません。

9. 条件の変更への対応

面接の後半では、運用で起きた不具合や将来の要望という形で条件が足されます。答え方は、今の設計でなぜ起きたか、何をきっかけに何をどう処理して直すか、変えずに済むところはどこか、の順です。

例 1:異動した人が、異動のあとも前の部署の申請を承認できていた

  • 原因:所属を人事データの取り込みで一括に書き換えており、その経路では企業の権限の更新番号を上げていなかった。そのため、異動前の所属がキャッシュに残っていた。
  • 直し方:所属を書き換える処理を 1 か所にまとめ、どの経路から書き換えても同じトランザクションで更新番号を上げます。取り込みが途中で失敗したら最初から流し直し、同じ取り込みを 2 回流しても結果が変わらないよう、前回との差分だけを書きます。異動の記録は変更履歴に残します。
  • 変えずに済むところ:ロールと割り当て、規則、テナントの境界です。

例 2:申請を特定の人だけに共有したい(範囲の外にいる他部署の担当者に、この 1 件だけ見せる)

  • 原因:範囲つきの RBAC は、部署やプロジェクトの単位でしか許せません。申請 1 件ごとに見てよい人を変えることは、どの割り当てを作っても表せません。
  • 直し方:申請の共有の表(企業 ID、申請 ID、共有された利用者 ID、共有した人、期限)を足し、認可モジュールの規則に「共有された人は見られる」を加えます。一覧の条件にも、同じ規則から「共有の表にこの利用者がある申請」を OR で足すので、一覧と詳細は食い違いません。共有の追加と取り消しは変更履歴に残します。このような 1 件ごとの関係が増え続けるなら、7 の末尾の ReBAC を検討します。
  • 変えずに済むところ:ロールと範囲の割り当て、入口で操作中の企業を 1 つに決める作り、リポジトリ層と DB の絞り込みです。

まとめ:選んだものと捨てたもの

判断

選んだ案

捨てた案、代わりの案

理由

テナントの境界

操作中の企業を 1 つに決め、リポジトリ層と DB の 2 か所で絞る

各クエリの WHERE、リポジトリ層だけ

1 か所の書き忘れで漏れない

判定の置き場所

入口で操作の宣言を必須にし、認可モジュールに規則を集める

各 API の if 文、共通の関数を各自で呼ぶ

新しい API で書き忘れても拒否されるだけで済む

一覧

規則から SQL の条件を作って 1 回で絞る

1 件ずつ判定する

1,000 件を 1 秒以内に返し、詳細の判定と食い違わない

権限モデル

範囲つきの RBAC と、開発者が書く固定の規則

RBAC だけ、管理者が書く ABAC

要望を表せて、IT に詳しくない管理者でも設定できる

反映

企業ごとの更新番号つきのキャッシュ

ログイン時に読んで使い回す

判定 10ms と 1 分以内の反映を両方満たす

認可の置き場所

モノリスの中のモジュール

代わりの案:Zanzibar 型の別サービス

DB が 1 つで 8 名なので、関係のデータを別に持つ手間が見合わない

移行

新旧の判定を並べて比べ、API ごとに切り替える

一度に全 API を切り替える

1 年の間も機能開発を止めない

よくあるつまずき

つまずき

なぜ弱いか

抜け出す一手

面接の最初から権限モデルの話を始める

他社データの漏えいや確認漏れの事故など、設計を決める条件を取りこぼす

テナントの数、DB の形、今の判定の仕方、反映の速さを先に聞く

ロールの種類を増やす話だけをする

「自部署だけ」を部署の数だけのロールで表すことになる

割り当てに範囲を持たせる

企業 ID で絞る、とだけ言う

1 か所の書き忘れで漏れる。前提に事故がすでに 1 件ある

リポジトリ層と DB の 2 か所で絞り、DB の外にも企業 ID を持たせる

認可を共通化する、とだけ言う

どこで呼ぶかが無く、呼び忘れが残る

入口で操作の宣言を必須にし、宣言の無い API は拒否する

一覧も 1 件ずつ判定する

1,000 件で最大 10 秒かかる

規則から SQL の条件を作って 1 回で絞る

画面のボタンを隠して権限を守る

古い版のモバイルアプリや API の直接の呼び出しは通ってしまう

判定はサーバーで行い、画面は応答に入れた操作の一覧で出し分ける

会計事務所のために複数の企業 ID をまとめて扱う

境界の決め方が緩み、他社の行が混ざる余地ができる

操作中の企業を 1 リクエストに 1 つだけ決める

新しい判定に一度に切り替える

今と同じ操作ができなくなる人が出ても気づけない

新旧の判定を並べて比べ、食い違いが無くなった API から切り替える

▼解説を読んだら、同じお題を AI 面接官を相手に通しで解いてみましょう。

参照元

海外の技術ブログ、論文、公式の技術文書です。どれも開いて内容を確かめています。Oso と Auth0 の記事は自社製品の紹介を兼ねています。

節

記事

参照した内容

4, 6

Airbnb Builds Himeji - a Scalable Centralized Authorization System(InfoQ, 2021)

画面側のサービスに置いた確認の重複、データ側への移動、変更の検出によるキャッシュの削除

4

How we built a custom permissions DSL at Figma(Figma, 2024)

判定が DB の負荷の約 2 割、2 つの API で判定が食い違った、規則とデータの読み込みの分離

5

SaaS Tenant Isolation Strategies: Identity and isolation(AWS, 2020)

認証で得たテナントの文脈を以降の処理に渡して範囲を決める

5

Multi-tenant data isolation with PostgreSQL Row Level Security(AWS, 2020)

接続ごとのテナント ID で絞る方針、所有者で接続すると適用されない、接続プールの注意

5

Row Security Policies(PostgreSQL)

方針で除いた行は知らせずに結果から外す、方針の無い表はどの行も見えない、所有者と BYPASSRLS は対象外

6

Authorization Cheat Sheet(OWASP)

既定で拒否、すべてのリクエストで確かめる、認可のテスト

6

List Filtering(Oso)

1 件ずつではなく 1 回で取り出す、規則から WHERE 句を作る

7

Guide to Attribute Based Access Control (ABAC) Definition and Considerations(NIST SP 800-162)

ABAC の定義

7

例 4: RBAC と ABAC を使用したマルチテナントアクセスコントロール(AWS 規範ガイダンス)

ロールにテナントの条件を組み合わせ、規則の保存先を共有する

7

How to Choose the Right Authorization Model for Your Multi-Tenant SaaS Application(Auth0, 2024)

テナントごとのロール、RBAC、ABAC、ReBAC の比べ方

事前知識, 7

Zanzibar: Google's Consistent, Global Authorization System(Google, USENIX ATC 2019)

関係のデータを 1 つのモデルで表す、数兆のリスト、95 パーセンタイル 10ms 未満

▼ほかのお題の解説

技術設計面接の解説と模範解答まとめ

コラム

サカモトエンジニア

サカモトエンジニア監修

外資系企業のソフトウェアエンジニア。エンジニアのキャリアや面接について X や note で発信し、テック企業を目指すエンジニア向けの面接対策プラットフォーム InterviewCat を運営しています。

CaseMatch

公式アカウント

CaseMatch編集部

CaseMatch編集部は、就活・転職における面接対策やキャリア選択に役立つ情報を発信する編集チームです。AI面接練習サービス「CaseMatch」の運営で得た知見や、企業選考・ケース面接・自己分析に関する実践的なノウハウをもとに、候補者が納得感を持って選考に臨めるコンテンツをお届けします。

1分で新規登録完了

新規登録をすると、会員限定の記事や対策情報、面接を見れます。

ログインはこちら
​
​

カテゴリー

年収・手取り

年収

転職体験談

ITコンサルタント体験談戦略コンサルタント体験談

転職の進め方

税金・手取り年収交渉スカウトサービスエージェントの選び方入社手続き退職交渉・手続き在職中の転職活動転職の流れ

属性別ガイド

第二新卒30代20代

職種別ガイド

コンサルタント営業

企業別ガイド

金融コンサル

選考対策

ケース面接人物面接webテスト職務経歴書業界分析自己分析

面接練習で、選考を有利に進めよう。

新卒・中途向けナビゲーションバッジ

1分で完了

他の記事も見る
コンサル2026/10/21
bcg 中途採用は未経験でも応募できる?応募条件・職種選び・面接対策を解説
#中途対策 #企業選考 #戦略コンサル
コンサルタント2026/10/21
ロジックツリー テンプレート|3種類の型とExcel・PowerPointでの作り方
#中途対策
ケース面接2026/10/21
ケース面接 失敗を次に生かす対策|詰まったときの立て直しと練習法
#選考対策 #中途対策 #ケース対策
ケース面接2026/10/21
ケース面接 比較で分かる評価の違いと解き方|例題・練習法を解説
#選考対策 #中途対策 #ケース対策