1つのNeo4jに複数の組織や案件のデータを載せると、必ずテナント分離の問題が出ます。テナントAの利用者から、テナントBのノードが見えてはいけない。SaaSでも社内システムでも同じです。
ここで最初の分かれ道になるのがエディションです。Neo4j Enterprise Editionには、ロールベースのアクセス制御や、ラベル・プロパティ単位で見える範囲を絞るサブグラフアクセス制御があります。ところがCommunity Editionには、この細かなアクセス制御がありません。単一データベースと基本的な認証だけです。つまり、クエリを書けばグラフ全体に触れてしまう。だからCommunityでマルチテナントをやるなら、分離はアプリ層で強制するしかありません。
この記事は、その実運用の設計です。要件トレーサビリティのシステムを1つのNeo4j Community上で複数ワークスペースに分けて運用している、実際の作り方をもとに書きます。ナレッジグラフエージェント全体の作り方はナレッジグラフエージェントの作り方にまとめてあります。
なぜアプリ層で守るしかないのか
Enterpriseの細かなアクセス制御は、データベース側が「このユーザーはこのラベルのこのプロパティまで」と判定してくれます。Community Editionにはこの層がありません。認証は通っても、その先のクエリが何を読むかはデータベースが制限しない。
結果として、テナント境界を守る責任は全部アプリ側に来ます。どこか1つのクエリでWHERE句を書き忘れれば、そこがそのまま情報漏れの穴になる。人の注意力に頼る設計は、いつか必ず破れます。だから「忘れても漏れない」仕組みにします。
原則:全Cypherにテナント境界を差し込む
すべてのクエリに、テナントを絞る条件を必ず入れます。ノードにテナント識別子(ワークスペースID)を持たせ、あらゆる読み書きで WHERE n.workspace_id = $ctx に相当する条件を通す。
この条件は、各所に手書きで散らさないことが肝心です。散らせば必ず抜けます。クエリを組み立てる中央の層を1つ設け、そこを通らないとNeo4jに問い合わせできない構造にする。テナントは認証時に解決してリクエストの文脈(コンテキスト)に載せ、クエリ組み立て層がそこから毎回読み直して差し込みます。
- 入口で解決:認証でトークンからテナントを特定し、リクエストの文脈に固定する。利用者が後から差し替えられない形にする。
- 出口で再注入:実際にNeo4jへ投げる全クエリで、文脈のテナント境界をCypherのWHEREに入れ直す。入口を信じきらず、出口でもう一度縛る二重防御にする。
LLMにCypherを書かせるなら、型で縛る
ナレッジグラフエージェントでは、LLMに検索クエリを組ませる場面が出てきます。ここが無防備だと、テナント境界の回避や、想定外のラベルへのアクセスを、生成されたクエリが引き起こしかねません。
対策は、扱ってよいノードのラベルと関係の種類を、あらかじめ決めた一覧(enum)に限ることです。加えて、識別子は正規表現で形式を検証してから使う。一覧にないラベルや、形式が不正な識別子は、クエリを実行する前に弾かれます。Cypherインジェクションも、LLMが捏造したラベルへのアクセスも、この時点で止まります。オントロジーを型で固定する設計はエンタープライズのナレッジグラフ設計パターンでも触れています。
ノード単位で絞るなら、アクセス権を関係で持つ
テナント境界より細かく、「同じテナント内でも、この文書はこの役割だけ」という制御が要ることがあります。これは、可視性そのものをグラフの関係として持たせると素直に書けます。利用者や役割から、閲覧・編集・管理といったアクセス権のエッジを対象ノードに張り、検索時にそのエッジをたどれるかで可視性を判定する。権限モデルがグラフの一部になるので、Community Editionでも関係をたどるだけで細かな制御ができます。情シス観点の確認ポイントは社内文書を生成AI・RAGで扱う情報漏洩リスクと対策にまとめました。
差し込み忘れは、CIで潰す
ここが本番の肝です。どれだけ中央層を作っても、新しいクエリを足すときに人は境界条件を忘れます。忘れを前提に、テストで捕まえます。
テナントAのトークンで、テナントBのノードを取りにいくテストを書き、結果が必ず空になることを検証する。作成・参照・更新・削除のそれぞれで、越境が0件で返るかを自動テストにする。新しいエンドポイントやツールを追加してこのテストが落ちたら、境界の差し込み忘れがある、とすぐ分かります。
- 越境の読み取り:他テナントのIDを直接指定して取得を試み、空が返ることを確認する。
- 越境の書き込み:他テナントのノードへの更新・削除を試み、1件も変更されないことを確認する。
- 網羅性:公開している全ツール・全エンドポイントを対象にする。1つでも素通りがあれば、そこが穴になる。
アクセス制御は「実装した」で終わらせず、「越えられないことをテストで示せる」状態にして初めて安全と言えます。
どこから始めるか
まず、すべてのノードにテナント識別子を持たせ、クエリ組み立ての中央層を1つに絞るところからです。既存のクエリが散らばっているなら、中央層を通す形に寄せていく。そのうえで越境テストをCIに入れれば、以降の追加でも境界漏れが自動で見つかります。規模が大きくなり、native のアクセス制御や高可用性が要るようになったら、Enterpriseへの移行を手間とコストで判断します。基盤の考え方は生成AIシステムのインフラはVPSで十分かを参考にしてください。
Beekleの取り組み
Beekleは、要件トレーサビリティ・プロジェクト管理のシステムを、1つのNeo4j Community上でワークスペースごとに分けて運用しています。全クエリにワークスペース境界を差し込む二重防御、ラベルと関係のホワイトリスト、アクセス権をグラフのエッジで持つ設計、そして越境を検出するテストまで作り込み、自社サーバー(VPS)で動かしています。この設計は、社内ナレッジをAIで扱う案件にもそのまま応用できます。
マルチテナントのナレッジグラフやAIサポートの構築を検討中の方は、初期費用0円のゼロスタート(PoC開発・MVP開発)からご相談ください。開発会社・SIerの立場で実装力の見極めや協業をご検討の場合も、お問い合わせから承ります。
よくある質問(FAQ)
Q. マルチテナントなら、最初からNeo4j Enterpriseを選ぶべきですか?
A. 必須ではありません。Enterpriseは native のアクセス制御や高可用性を備えますが、ライセンス費用がかかります。中小規模なら、Community上でアプリ層の強制フィルタと越境テストを組めば、安全に運用できます。データ量や可用性の要求が上がったところで、手間とコストのトレードオフでEnterpriseを検討します。
Q. Neo4jに、データベースの行レベルセキュリティ(RLS)のような機能はありますか?
A. ラベルやプロパティ単位で見える範囲を絞る仕組みはEnterprise Editionにあり、Community Editionにはありません。Communityでは、テナント識別子でのフィルタと、可視性を表すアクセス権のエッジを、アプリ層で組み合わせて同等の制御を作ります。
Q. LLMにCypherを書かせて、テナント越えのリスクはありませんか?
A. 型で縛れば抑えられます。扱えるラベルと関係をenumに限り、識別子を検証し、テナント境界はアプリ層が必ず差し込む。LLMが組んだクエリでも、この層を通るので境界を越えられません。生成物を実行前に検査する設計が前提です。
Q. テナント境界の差し込み忘れを、どうやって見つけますか?
A. 越境テストをCIに入れます。あるテナントのトークンで別テナントのデータを読み書きしようとして、結果が空・変更0件になることを自動で検証する。新しいクエリを足して境界を入れ忘れると、このテストが落ちて気づけます。
Beekleにご相談ください Beekleでは、生成AI/CDP/業務システムの企画・要件定義・開発・運用までワンストップで支援しています。「何を作れば成功か」の整理、検証フェーズの設計、本番化判断まで、発注側の判断材料が揃うように伴走します。費用感の概算だけでも歓迎です。