第7章 — アクセス制御の実装
LLM Primer III: RAGで強化するエンタープライズAI を章ごとに紹介していくウォークスルー、第7回です。関係DBやファイルシステムのために設計された権限モデルは、検索にぴたりとは合いません。アクセスの単位はもう行やファイルではなく埋め込みで、その埋め込みは、文書自体にゲートをかけても類似度を介して元を漏らしうるものです。
この章がなぜあるのか
第6章で脅威モデルができました。そこから導かれるもっとも重要な制御 — そして初期の本番システムがもっとも誤りやすい場所 — が、検索層でのアクセス制御です。LLM がユーザーに見えない内容を決して見ないようにすること。素朴な代替「生成時にフィルタする」は混乱した代理人を作ります: モデルはすでにゲート対象を読み終え、言い換えで実質を漏らします。
この章は、機能するアクセス制御スタックを構成する4つの機構を歩きます — 基盤としての文書単位 ACL、企業の既存の機密ラベルと組み合わせる RBAC、企業の知識が実際には関係の形をしている現実に応える ReBAC、そしてそれらすべての下を流れる「事前フィルタ vs 事後フィルタ」の規律。
7.1 文書単位の ACL とメタデータフィルタ
すべてのチャンクが、誰が読めるかを知っている。記述としては単純で、失敗モードは初期の本番システムが少なくとも一度は誤るくらいに細かい。重要な点は3つあります。粒度: 長い報告書には公開の要約と機密の付録があり、文書単位の ACL を一律にチャンクへコピーすると、付録を共有しすぎるか、要約を共有しなさすぎるかになります。スケールするパターンは、レイアウト認識パースを通じてセクション単位の権限を運ぶことです。
鮮度: 権限は変わります。ACL をインデックス時にチャンクに焼き込んで二度と見直さないと、嘘をつくシステムができます。安定識別子をチャンクメタデータに保存し、クエリ時に短いTTLのキャッシュ越しにソースシステムへ生きた ACL を解決してください。否定空間: 答えがゲート文書にあるとき、システムは幻覚を見たり、自信を持って「分かりません」と言ったりするべきではなく、「このトピックに関する素材はあるが、あなたは閲覧を許可されていない」と言うべきです。これには、フィルタなしの2回目の呼び出しか、「該当なし」と「該当ありだがフィルタ済み」を区別できるベクトルDBが要るのですが、たいていの実装はここを先送りにします。
7.2 RBAC と Microsoft Purview の機密ラベル
RBAC は権限空間を圧縮します — 数百万のユーザー対文書のエッジが、数百のロール対分類のエッジに縮み、監査可能で保守可能になります。企業がすでにこれで動いているなら、RAG にきれいに合います。Microsoft 環境では、それは Entra ID のグループと Purview の機密ラベル: Public、General、Confidential、Highly Confidential、必要ならサブラベル。ラベルは文書とともに動き、パーサーがインデックス時にそれを読み、安定したラベルIDをチャンクメタデータに書きます。
統合は素直ですが、ドリフトはそうではありません。インデクサが何でも復号できるサービスアカウントで動き、検索側がインデックスの上でロールベースのフィルタを強制している場合、General から Confidential へ再ラベルされた文書は、インデクサが変化を捕まえなければ、すでにインデックスされたチャンクは再ラベルされません。これを正しくやるシステムは、ソースに対する継続的な突き合わせを動かしています。間違えるシステムは、ドリフトを監査中に発見し、所見は厳しいものになります。
7.3 ReBAC — Zanzibar と SpiceDB
「Sales 部にいて、かつ Acme Corp 案件に割り当てられた人」を、RBAC では表現できません。これにはユーザーとリソースの関係を扱う必要があり、ロールだけでは足りない。Google の Zanzibar 論文で形式化され、SpiceDB と OpenFGA として OSS で使える関係ベースのアクセス制御は、グラフを保ちます: 「Alice は Engineering のメンバー」「Engineering は Specs フォルダの閲覧者」「Spec-101 は Specs にある」。権限チェックはグラフの巡回になります。
RAG との統合パターンはきれいです。SpiceDB は「このユーザーが見られる文書は?」を受け、文書IDの集合を返します。検索側はそれをメタデータフィルタとしてベクトル検索に渡す。Zanzibar の zookie は、最近付与されたアクセスと整合的に検索を行えと指定できるので、10:00 にプロジェクトに追加され 10:01 に質問するユーザーは、新しい文書を見られます。運用上のコストは、SpiceDB がクエリパスの重要依存となり、HA と短TTLのユーザー単位文書リストキャッシュが要ることです。成熟したシステムは RBAC と ReBAC を併用することが多くあります — RBAC で広い機密性ポリシーを、ReBAC で細かい関係ポリシーを、許可集合の交わりとして組み合わせる。
7.4 事前フィルタ、事後フィルタ、その下の規律
事前フィルタはベクトル検索の前に認可述語を適用します — インデックスがまず候補集合を絞り、その制限の中で類似度が走る。概念的にきれいで、既定として安全ですが、性能はインデックス構造に依存します。HNSW で選択性の高いフィルタをかけると、グラフ巡回が非マッチノードを多く歩くために急に劣化することがあります。Weaviate や Qdrant のフィルタ可能 HNSW、Pinecone や Milvus のテナント単位の名前空間がコストを和らげますが、消し去るわけではありません。
事後フィルタは順序を逆にします。HNSW の速度を保てる代わり、セキュリティは弱い: 上位Kの漏洩、タイミングベースの情報漏洩、上位K全体がフィルタアウトされたときの正答性の漏洩。本番の現実解は両者を重ねることです — もっとも粗く速い述語(テナント、広いロール)で事前フィルタ、高価で精密な述語(SpiceDB のリスト、Purview のラベル)で事後フィルタ、そして オーバーフェッチ して上位10ではなく上位50を取ることで、事後フィルタが終わってもまだ十分なランクづけが残るようにする。漏洩する場所がもう2つあります: 機密文書のタイトルを引用するプロンプトテンプレートと、クエリ文字列だけをキーにする応答キャッシュ。どちらも認可の面の一部として扱う必要があります。
第7章を踏まえて
アクセス制御は 誰が 何を 見られるかに答えます。ゲートをかけるべき何かがあることを前提にしています。チャンクがそもそもその形で埋め込まれてよかったのか — 顧客名、社会保障番号、専有のコードパスが、適切な認可を待ってベクトルストアの中に座っていてよかったのか — は問いません。それが匿名化の問いで、次章の主題です。
次回 — 第8章: RAGパイプラインにおけるデータ匿名化。 生成前 vs 生成後、マスキング vs 合成置換 vs 差分プライバシー、そしてどの選択も渡り歩かなければならない有用性とプライバシーのトレードオフ。