Skip to content

Virtual Private Database

Virtual Private Database(VPD)は、DBMS_RLS パッケージを使ってテーブル・ビューにポリシーを設定し、SQL 実行時に自動的に WHERE 句を付加することで行・列レベルのアクセス制御を実現する機能です。

アプリケーション側のコードを変更せず、データベース層で透過的にアクセス制御できます。同じ SQL でもユーザーやセッション属性によって返される結果が変わります。

ポリシー関数が返す述語を WHERE 句に付加することで、参照できるを制限します。

-- ポリシー関数の例(セッションユーザーで絞り込み条件を切り替え)
CREATE OR REPLACE FUNCTION hr.get_sales_predicate(
p_schema IN VARCHAR2,
p_table IN VARCHAR2
) RETURN VARCHAR2 IS
BEGIN
IF SYS_CONTEXT('USERENV', 'SESSION_USER') = 'SALES_APP' THEN
RETURN 'JOB_ID LIKE ''SA_%'''; -- 営業系のみ
ELSE
RETURN '1=1'; -- 全件
END IF;
END;

DBMS_RLS.ADD_POLICYsec_relevant_cols パラメータで対象列を指定します。指定列がクエリに含まれたときだけポリシーが発動します。

sec_relevant_cols_opt動作
未指定(デフォルト)条件を満たさない行を除外(0件になる場合あり)
DBMS_RLS.ALL_ROWS条件を満たさない行の対象列を NULL で表示
BEGIN
DBMS_RLS.ADD_POLICY (
object_schema => 'HR',
object_name => 'EMPLOYEES',
policy_name => 'employees_salary_col_vpd_policy',
function_schema => 'HR',
policy_function => 'get_masking_salary_col',
sec_relevant_cols => 'SALARY',
sec_relevant_cols_opt => DBMS_RLS.ALL_ROWS -- NULL表示
);
END;
プロシージャ説明
DBMS_RLS.ADD_POLICYテーブル・ビューにポリシーを追加する
DBMS_RLS.DROP_POLICYポリシーを削除する
DBMS_RLS.ENABLE_POLICYポリシーを有効化・無効化する
パラメータ説明
object_schema / object_nameポリシーを適用するスキーマ・テーブル名
policy_nameポリシー名(テーブル内で一意)
function_schema / policy_functionポリシー関数のスキーマと関数名
sec_relevant_cols列レベル制御の対象列(カンマ区切り)
sec_relevant_cols_optDBMS_RLS.ALL_ROWS で NULL 表示モードを指定
statement_types適用する DML 種別(デフォルト: SELECT,INSERT,UPDATE,DELETE
ビュー内容
ALL_POLICIES作成されたポリシー一覧(関数名・適用 DML・ポリシータイプなど)
ALL_POLICY_GROUPSポリシーグループ情報
ALL_POLICY_CONTEXTSポリシーコンテキスト(SYS_CONTEXT の名前空間など)

HR スキーマの EMPLOYEES 表を対象に、SALES_APP ユーザーへの行・列レベル制御を設定します。 HR ユーザーは全 107 行・全列を参照でき、SALES_APP ユーザーは営業系の 35 行のみ・SALARY 列は非表示(または NULL)になることを確認します。

  1. VPD で行制御を行う

    SYS_CONTEXT('USERENV', 'SESSION_USER') を利用したポリシー関数を作成し、DBMS_RLS.ADD_POLICY でポリシーを適用します。HR は全件、SALES_APPJOB_ID LIKE 'SA_%' の 35 行のみ参照できることを確認します。

  2. VPD で列制御を行う

    sec_relevant_cols => 'SALARY' で列を指定したポリシーを追加します。SALES_APP で SALARY 列を含むクエリを実行すると行が除外されること、sec_relevant_cols_opt => DBMS_RLS.ALL_ROWS を指定すると NULL 表示になることを確認します。

  3. VPD の設定を削除する

    DBMS_RLS.DROP_POLICY でポリシーを削除し、ポリシー関数も DROP FUNCTION で削除します。ALL_POLICIES で削除を確認します。

このサイトのチュートリアルをベースに、Oracle Blogs で解説記事を公開しています。記事では手順を再構成し、説明の追加・変更を行っているため、主な差分を以下にまとめます。

  • ブログは Oracle AI Database 26ai FREE / PDB FREEPDB1 を前提とし、ポリシー関数とポリシーの作成・削除をすべて SYS(AS SYSDBA) で実行します。このサイトの手順は実行ユーザーを明示していません(関数は HR スキーマに作成)。

  • ブログでは SALES_APP の作成と権限付与を明示しています。表単位の付与で、SELECT ANY TABLE は使いません。

    create user sales_app identified by "<password>";
    grant create session to sales_app;
    grant select on hr.employees to sales_app;
  • ブログは DBMS_RLS.ADD_POLICYstatement_types => 'SELECT' を明示し、ポリシーを SELECT のみに限定します(DML への予期しない影響を避けるため)。このサイトの手順は statement_types を省略しており、既定の SELECT,INSERT,UPDATE,DELETE が対象になります(ALL_POLICIESUPD / DELYES になる)。
  • DBMS_RLS.ADD_POLICY / DROP_POLICY は処理の前後で暗黙的にコミットします。未コミットの変更があるセッションでは実行しないでください。
  • このサイトは「既定(条件を満たさない行を除外)」→「DBMS_RLS.ALL_ROWS(対象列を NULL 表示)」の順に両方の挙動を確認します。ブログは最初から DBMS_RLS.ALL_ROWS のみを使用します。
  • ブログは列オプションの確認に DBA_SEC_RELEVANT_COLSSEC_REL_COLUMN / COLUMN_OPTIONALL_ROWS)を使用します。このサイトは ALL_POLICIES のみ。
  • ブログでは行制御に業務条件を重ねる確認(WHERE salary >= 10000 と VPD 述語の AND 結合)も追加しています。

統合監査で VPD 述語を確認(#15 で追加、このサイトには無い内容)

Section titled “統合監査で VPD 述語を確認(#15 で追加、このサイトには無い内容)”
  • HR.EMPLOYEES への SELECT を記録する統合監査ポリシーを作成し、SALES_APP に対して有効化します。

    CREATE AUDIT POLICY vpd_employees_audit_policy
    ACTIONS SELECT ON HR.EMPLOYEES;
    AUDIT POLICY vpd_employees_audit_policy BY SALES_APP;
  • UNIFIED_AUDIT_TRAILRLS_INFO 列に、適用された VPD ポリシーごとに POLICY_TYPE / POLICY_SCHEMA / POLICY_NAME / PREDICATE が連結記録されます(複数ポリシーが効く場合は複数分)。CLOB のため SET LONG 100000 / SET LONGCHUNKSIZE 100000 を先に実行します。

  • DBMS_AUDIT_UTIL.DECODE_RLS_INFO_ATRAIL_UNI を使うと、RLS_INFO をポリシーごとの行(RLS_PREDICATE / RLS_POLICY_NAME など)に展開できます。

  • ポイント: SQL_TEXT 自体は書き換わらず、VPD が適用した述語は別項目として記録されます。

  • 後片付けは NOAUDIT POLICY ... BY SALES_APP;DROP AUDIT POLICY ... の順。

  • ブログは ポリシー削除 → 関数削除 の順です(このサイトの手順 3 は関数削除 → ポリシー削除の順)。どちらでも削除自体は可能ですが、関数を先に削除するとポリシーが有効なまま残り、対象表への SELECT がポリシー関数エラーになります。
  • ハンズオン専用に SALES_APP を作成した場合は DROP USER SALES_APP CASCADE; も実施します。

クライアント識別子とアプリケーション・コンテキスト(#14 の補足)

Section titled “クライアント識別子とアプリケーション・コンテキスト(#14 の補足)”

接続プールで同一 DB ユーザーを共有する構成では SESSION_USER で利用者を区別できないため、次のいずれかの値を SYS_CONTEXT で参照してポリシー関数の述語を切り替えます。

項目クライアント識別子アプリケーション・コンテキスト
保持する情報組み込み USERENV 名前空間の単一の識別値独自の名前空間に複数の属性・値
設定方法DBMS_SESSION.SET_IDENTIFIER / OCI・クライアントドライバCREATE CONTEXT で名前空間と PL/SQL パッケージを関連付け、そのパッケージから DBMS_SESSION.SET_CONTEXT
参照方法SYS_CONTEXT('USERENV','CLIENT_IDENTIFIER')SYS_CONTEXT('<名前空間>','<属性名>')

接続プールのセッションを別の利用者へ再利用する際は、前の利用者の値をクリアまたは再設定する必要があります。このサイトの CLIENT_IDENTIFIER を使ったアクセス制御 は、アプリケーション・コンテキストを作らず共通 APP ユーザーに VIEWER / EDITOR / ADMIN のクライアント識別子を設定する例です。