データベースのアクセス制御では、利用者やアプリケーションに対して、表の参照や変更を許可するかどうかをオブジェクトを最小単位として権限で制御します。
しかし、表へのSELECT権限を持つ利用者であっても、その表のすべての行を見せてよいとは限りません。

たとえば、次のような例を考えると、同じ表を複数の利用者やテナントで共有する場合は、利用者ごとに参照または変更できる行を分ける必要があります。

  • 自分が担当する顧客の行だけを参照できる
  • 自社テナントの行だけを参照または変更できる
  • 契約中の案件の行だけを処理できる

このような場合、アプリケーションではログインした利用者のロール、所属部門、テナントID、データの所有者などを判定し、SQLのWHERE句、JOINや、API・サービス層の認可ロジックで返すデータを絞り込むことが一般的です。

この設計は多くのアプリケーションで使われていますが、行の絞り込みをアプリケーションだけに任せる場合、制御の有効性は画面、API、バッチ処理など、それぞれの実装に依存します。

結果として、条件の記述漏れがあったり、想定していない経路から表へアクセスできたりすると、アプリケーション側の制御だけでは意図しない行が処理対象になるリスクがあります。

この行レベルの制御をアプリケーションの実装だけに任せず、データベース側でも強制する機能が、Oracle Virtual Private Database(VPD) です。
VPDを設定した表などへアクセスすると、Oracle Databaseは利用者やテナントに応じた条件を自動的に適用します。
同じデータへ複数のアプリケーションや接続方法からアクセスする場合でも、共通のルールで処理対象の行を制限できます。

この記事では、そんなアクセス制御機能としてVPDを紹介します。


1. VPD とは

Oracle Virtual Private Database(VPD) は、利用者やアプリケーションの条件に応じて、表、ビュー、シノニムのどの行を処理対象にするかを制御する、Oracle Database の機能です。
VPDは行レベル・アクセス制御の一つであり、同じ表に対する同じSQLでも、接続している主体やセッションの情報によって異なる結果を返すことが可能です。

たとえば、一つの注文表を複数の企業が共有する場合を考えます。
VPDを設定すると、企業Aの利用者には企業Aの注文だけを、企業Bの利用者には企業Bの注文だけを返すようにできます。同様の考え方で、担当者、所属部門、地域、契約状態などの業務条件にも適用することが可能です。

この仕組みとしては、VPDではポリシー関数が返す条件(述語)をOracle DatabaseがSQLへ動的に追加したものとして実行します。そのため、アプリケーションが個々のSQLに条件を書かなくても、条件に合わない行を検索結果から除外することができます。
また、ポリシーの対象とするSQL操作を指定すれば、INSERTUPDATEDELETEに対しても行の制御を適用が可能です。


2. VPD の構成要素

VPDは、保護対象に適用するVPDポリシーと、アクセス条件を返すポリシー関数の二つで構成されます。

要素役割
ポリシー関数現在のセッション情報などを参照し、適用する条件(述語)を文字列として返す関数
VPDポリシーポリシー関数を保護対象の表、ビュー、またはシノニムへ関連付け、適用するSQL操作を指定する

ポリシー関数

ポリシー関数は、VPDがアクセス条件を生成するために使うPL/SQL関数です。
関数は対象スキーマ名とオブジェクト名を引数に受け取り、適用する条件(述語)を文字列で返します。
そのため、ポリシー関数を作成しただけでは表に制御は適用されません。

ここでは、利用者が個別のデータベース・ユーザーで接続し、表のASSIGNED_USER列に担当者のデータベース・ユーザー名を格納している場合を考えます。
この場合、以下のようなポリシー関数となります。

CREATE OR REPLACE FUNCTION SALES.ORDERS_USER_PREDICATE (
    p_schema IN VARCHAR2,
    p_object IN VARCHAR2
) RETURN VARCHAR2
AS
BEGIN
    RETURN q'[ASSIGNED_USER = SYS_CONTEXT('USERENV', 'SESSION_USER')]';
END;
/

この関数では、Oracle Databaseが提供するUSERENV名前空間から現在のデータベース・ユーザーを取得し、述語として値を返却しています。
この関数が返す述語により、ASSIGNED_USER列が現在のデータベース・ユーザー名と一致する行だけが処理対象になります。

SYS_CONTEXT('USERENV', 'SESSION_USER')は、現在のセッションへログインしたデータベース・ユーザー名を返します。

また、ポリシー関数では必要に応じて条件分岐を行い、利用者や処理に応じて異なる述語を返すこともできます。

VPDポリシー

VPDポリシーは、上記のポリシー関数を保護対象とする表、ビュー、またはシノニムへ関連付けます。
例えば、以下はVPDポリシーを追加する文の例ですが、ここで対象オブジェクト、ポリシー関数、適用するSQL操作を指定します。

BEGIN
    DBMS_RLS.ADD_POLICY(
        object_schema   => 'SALES',
        object_name     => 'ORDERS',
        policy_name     => 'ORDERS_USER_POLICY',
        function_schema => 'SALES',
        policy_function => 'ORDERS_USER_PREDICATE',
        statement_types => 'SELECT'
    );
END;
/

この例では行レベルの制御を設定していますが、VPDは特定の列を対象とする制御にも対応しています。
DBMS_RLS.ADD_POLICYsec_relevant_colsに列名を指定すると、その列がSQLから参照された場合だけポリシーを適用できます。
さらに、sec_relevant_cols_opt => DBMS_RLS.ALL_ROWSを指定したSELECTでは、すべての行を返しながら、ポリシーの条件を満たさない行の対象列をNULLとして返せます。
本記事の以降は、VPDの基本となる行レベルの制御を中心に説明します。


3. SQLに条件が追加される流れ

前節のポリシー関数とVPDポリシーを使い、アプリケーションがSQLを実行してから結果を受け取るまでの流れを確認します。

まず、アプリケーションがSALES.ORDERS表へ次のSQLを送信します。

SELECT order_id, customer_name, amount
FROM sales.orders
WHERE status = 'OPEN';

このSQLには、担当者を限定する条件がありません。
しかし、SALES.ORDERS表にはVPDポリシーが設定されているため、Oracle Databaseはポリシー関数が返す次の述語を適用します。

ASSIGNED_USER = SYS_CONTEXT('USERENV', 'SESSION_USER')

Oracle Databaseは、元のSQLにこの述語を追加したものとして評価します。
元のSQLにはすでにWHERE句があるため、概念的には次のようにAND条件が追加されます。

SELECT order_id, customer_name, amount
FROM sales.orders
WHERE status = 'OPEN'
  AND ASSIGNED_USER = SYS_CONTEXT('USERENV', 'SESSION_USER');

この処理はOracle Database内で行われるため、アプリケーションが元のSQLを書き換える必要はありません。
アプリケーションには、STATUSOPENで、かつASSIGNED_USERが現在のデータベース・ユーザー名と一致する行だけが返ります。

ただし、複数の利用者が同じデータベース・ユーザーを共有する構成では、SESSION_USERだけで実際の利用者を区別できません。
共有アカウントや接続プールで実際の利用者をVPDの判定へ反映する場合は、次の節にて説明します。


4. VPDの判定に使う利用者情報

VPDはVPD関数という形で PL/SQLで条件を記述することになります。
上記の例では、セッションに保持された情報をSYS_CONTEXT関数で参照し、行を制御する条件の判断に使用していましたが、その他条件として使用できる情報としてはどのようなものが使えるのでしょうか。

この記事では、利用できる情報として、データベースが提供するもの、アプリケーションが設定するもの、APEXやMCPサーバーなどの連携機能が伝えるものに分けて解説します。

4-1. データベースが提供するコンテキスト

USERENVには、ログインしたデータベース・ユーザー、認証方式、接続先、クライアント情報など、現在のセッションに関する属性が用意されています。
以下ドキュメントリンクでは利用できる属性と戻り値を見ることができます。

https://docs.oracle.com/en/database/oracle/oracle-database/26/sqlrf/SYS_CONTEXT.html

代表的な属性は次のとおりです。

分類属性主な用途
ログインと認証SESSION_USER
AUTHENTICATED_IDENTITY
AUTHENTICATION_METHOD
PROXY_USER
データベースが認識している接続主体と認証方式
接続先SERVICE_NAME
CON_NAME
CDB_NAME
接続サービスやコンテナ
接続元IP_ADDRESS
CLIENT_PROGRAM_NAME
OS_USER
接続経路やクライアント
アプリケーション識別CLIENT_IDENTIFIER
MODULE
ACTION
CLIENT_INFO
監視や追跡に使うための、共有セッション内の利用者や処理

SESSION_USERは通常、ログインしたデータベース・ユーザーを示しますが、共有アカウントの背後にいる実ユーザーまでは識別できないことに注意します。

また、CLIENT_IDENTIFIERDBMS_SESSION.SET_IDENTIFIERMODULEACTIONDBMS_APPLICATION_INFOを使用してアプリケーションから動的に設定することが可能です。

4-2. 独自のアプリケーション・コンテキスト

業務上で使用されるテナントIDや担当部門などの独自のコンテキストは、通常のUSERENVには含まれません。
このような属性は、アプリケーション専用の名前空間を作り、独自のアプリケーション・コンテキストとして保持および使用することができます。
CREATE CONTEXTでは、通常のセッション・コンテキストについて、指定したパッケージから値設定について説明されていますので参考にしてください。

また、接続プールでは、一つのデータベース・セッションが別の利用者へ再利用されます。
利用者が切り替わるたびにコンテキストを消去または再設定しないと、前の利用者の属性が残る可能性があります。そのため、DBMS_SESSION.CLEAR_CONTEXTCLEAR_IDENTIFIERによる消去を行う必要があることにも注意します。

4-3. 連携サービスが固有に持つコンテキスト

Oracle が提供するローコードのアプリケーション開発ツール「Oracle APEX」や、OCI で提供されるマネージドMCPサーバー「Database Tools MCP Server」や「ADB MCP Server」では、固有の名前空間にセッションコンテキストを持っており、これをVPDの判断材料として使用することが可能です。

APEX

Oracle APEXは受信したリクエストの処理を開始するとき、APEX$SESSION名前空間へAPEXセッションの情報を設定します。
ドキュメントでは、以下リンクよりVPDのポリシー関数から次の属性を参照できます。
https://docs.oracle.com/en/database/oracle/apex/26.1/apxdc/referencing-other-context-information.html

属性内容
APP_USER現在のAPEX利用者
APP_IDアプリケーションID
APP_SESSIONAPEXセッションID
APP_TENANT_IDアプリケーションが設定したテナントID

DB Tools MCP サーバー

OCI では、マネージド MCP サーバーとして以下の2つが現在展開されており、これらMCPサーバーサービスでは、コンテキストが自動で付与されます。これを用いることで、AIエージェントに限定したアクセス制御を効かせることも可能です。

サービス名前空間主な属性ドキュメントリンク
OCI Database Tools MCP ServerCLIENTCONTEXTOAUTH_SUB
OAUTH_SUB_TYPE
IAM_DOMAIN_APP_ROLES
RESOURCE_OCIDなど
https://docs.oracle.com/ja-jp/iaas/database-tools/doc/database-identity-propagation.html
Autonomous AI Database MCP ServerMCP_SERVER_CONTEXT$USER_IDENTITYhttps://docs.oracle.com/ja-jp/iaas/autonomous-database-serverless/doc/mcp-server-concepts.html

5. Oracle Label Securityとの違い

前回の記事にて紹介した Oracle Label Security は、VPDと類似のアクセス制御を行うものとなります。
この2つの機能の違いとして、以下に表としてまとめてみます。

機能主な制御単位制御基準設定向いている要件ライセンス
VPD行、または特定の列SQLに動的に追加される述語・PL/SQLでwhere句の述語部分をコーディングする必要がある顧客ごとのデータ隔離、時間帯によるアクセス制限Enterprise Edition に無償で付属
Oracle Label Securityデータの機密性に応じたラベル・各データに対し、ラベルを設定する必要がある
・Enterprise Manager にてGUIで設定が可能
「公開」「社内限定」「機密」のような分類体系の制御Enterprise Edition の追加セキュリティオプション

6. セキュリティと運用上の注意点

VPDによるアクセス制御の強制力は、ポリシー関数が参照するコンテキストの信頼性に依存します。
利用者や業務属性を誰が設定し、どの経路から変更できるかをポリシー作成前に決めることが重要です。

  • コンテキストがない場合は拒否する
    • ポリシー関数がNULLまたは空の述語を返すと、行は制限されません。
    • 必要なコンテキストが未設定、不正、または期限切れの場合は、1=2のように行を返さない述語を返すか、SQLを失敗させます。
    • 許可条件を確認できた場合だけ対象行を返す動作にします。
  • 管理者の除外経路を別に統制する
    • VPDはSYSユーザー、AS SYSDBAなどの管理権限を用いた接続、またはEXEMPT ACCESS POLICYを持つ主体には適用されません。
    • 標準のDBAロールもVPDポリシーを変更または削除でき、SYSスキーマのオブジェクトやTRUNCATEALTER TABLEなどのDDLもVPDでは保護できません。
    • そのため、強権限ユーザーの操作は、Database Vaultや統合監査などの別の統制で補うこととなります

7. ライセンスについて

VPD を利用する場合は、Enterprise Edition 以上にて追加ライセンスなく利用することが必要です。

OCI なども含めると、Oracle Label Security が利用できる環境は以下のとおりです。
https://oracleapex.com/ords/features/r/dbfeatures/licenses?license_id=102

  • Oracle AI Database FREE
  • Enterprise Edition
  • Oracle Base Database Service Enterprise Edition
  • Oracle Base Database Service Enterprise Edition – High Performance
  • Exadata Database Service on Dedicated Infrastructure / Cloud@Customer

Oracle AI Database FREE でも利用できるため、機能検証や簡単な動作確認は無償環境で始めることができます。
一方で、バージョンによって利用可能な機能に違いがありますので、必要に応じて確認しておきましょう。
https://oracleapex.com/ords/r/features/dbfeatures/home


8. まとめ

VPDを使うと、同じ表を共有する利用者やテナントに対し、それぞれに許可された行だけを参照または変更できるように制御できます。
この制御を保護対象へ関連付けるため、複数のアプリケーションや接続方法からアクセスする場合でも、データベース側で共通のルールを適用できます。

アプリケーションの検索条件とVPDは、どちらか一方だけを選ぶ関係ではありません。
アプリケーションは画面や処理に必要なデータを取得し、VPDは利用者が許可された範囲を超えないように制御します。
またVPDでは、セッションから伝播する属性のうち、どの値を誰が設定し、どの接続経路で信頼できるかを設計して初めて、業務上の認可を行の条件へ変換することになります。そのため、SQL自体は透過的な処理になりますが、設計自体はアプリケーションまで含めて考えることが重要です。

次回は、Oracle AI Database Free上で独自のアプリケーション・コンテキストとVPDポリシーを作り、実際の動作を確認してみます。