DBMS_RLS パッケージは、PolarDB データベースオブジェクトで仮想プライベートデータベース (VPD) を有効にします。VPD は、コード変更を必要とせずに、すべてのアプリケーションで透過的に適用される行レベルのきめ細かなアクセス制御を提供します。
PolarDB は、Oracle DBMS_RLS パッケージのサブセットを実装しています。以下のストアドプロシージャがサポートされています。
| ストアドプロシージャ | 説明 |
|---|---|
ADD_POLICY(object_schema, object_name, policy_name, function_schema, policy_function [, statement_types [, update_check [, enable [, static_policy [, policy_type [, long_predicate [, sec_relevant_cols [, sec_relevant_cols_opt ]]]]]]]]]]) | データベースオブジェクトにセキュリティポリシーを追加します。 |
DROP_POLICY(object_schema, object_name, policy_name) | データベースオブジェクトからセキュリティポリシーを削除します。 |
ENABLE_POLICY(object_schema, object_name, policy_name, enable) | セキュリティポリシーを有効または無効にします。 |
VPD の仕組み
セキュリティポリシーは、ポリシー関数とデータベースオブジェクト (通常はテーブル) の間の関連付けです。SQL ステートメントがそのオブジェクトにアクセスすると、データベースエンジンはポリシー関数を呼び出し、それが返す WHERE 句述語を取得し、それを AND 条件としてステートメントに追加します。述語を満たさない行は、結果セットからフィルタリングされます。
VPD は、標準のオブジェクトレベルの権限と比較して、いくつかの利点を提供します。
行レベルの制御:GRANT ベースの権限はテーブル全体へのアクセスを制御します。VPD は個々の行へのアクセスを制限します。
ステートメント固有のポリシー:INSERT、UPDATE、DELETE、および SELECT 操作に対して異なるポリシーを適用します。
動的な適用:ポリシーはステートメントごとに評価され、セッションユーザーなどの要因に基づいて異なる場合があります。
透過的な適用:新しいアプリケーションを含むすべてのアプリケーションは、コード変更なしでポリシーの対象となります。
バイパスパスなし:スーパーユーザーであっても、EXEMPT ACCESS POLICY システム権限が明示的に付与されていない限り、アクティブなポリシーを回避することはできません。
ポリシー関数
ポリシー関数は、セキュリティポリシーのルールを定義します。以下の要件を満たす必要があります。
VARCHAR2 型の入力パラメーターを 2 つ持ちます。1 つ目はスキーマ名用、2 つ目はデータベースオブジェクト名用です。
VARCHAR2 型の戻り値の型を持ちます。
有効な WHERE 句述語の形式で文字列を返します。
PolarDB では、ポリシー関数はデータベースがサポートする任意の言語 (Oracle-compatible SPL、SQL、または PL/pgSQL) で記述できます。
VPD の実装
テーブルに VPD を実装するには、次の手順を実行します。
セッションコンテキストまたはその他の条件に基づいて WHERE 句述語を返すポリシー関数を作成します。
ADD_POLICYを使用して関数をテーブルに関連付け、適用する SQL ステートメントのタイプを指定します。ENABLE_POLICYを使用して、作成後にいつでもポリシーを有効または無効にします。不要になったポリシーを削除するには、
DROP_POLICYを使用します。ポリシーを削除しても、ポリシー関数やデータベースオブジェクトは削除されません。
ポリシーを作成した後、Oracle データベースと互換性のあるカタログビューをクエリして、どのアクティブなポリシーがあるかを確認します。
SYS_CONTEXT
SYS_CONTEXT 関数は、現在のセッションに関する情報を返すためにポリシー関数内で一般的に使用されます。構文:
SYS_CONTEXT(namespace, attribute)パラメーター:
`namespace` — VARCHAR2。唯一の有効な値は USERENV です。その他の値は NULL を返します。
`attribute` — VARCHAR2。サポートされている値:
| 属性値 | 同等の PostgreSQL 値 |
|---|---|
SESSION_USER | pg_catalog.session_user |
CURRENT_USER | pg_catalog.current_user |
CURRENT_SCHEMA | pg_catalog.current_schema |
HOST | pg_catalog.inet_host |
IP_ADDRESS | pg_catalog.inet_client_addr |
SERVER_HOST | pg_catalog.inet_server_addr |
SYS_CONTEXT の USERENV 名前空間での特殊な使用をサポートしていますが、アプリケーションコンテキストはサポートしていません。サンプルテーブルの設定
このトピックの例では、emp テーブルの変更されたコピーである vpemp という名前のテーブルを使用します。テーブルと salesmgr ロールを作成するには、以下を実行します。
CREATE TABLE public.vpemp AS SELECT empno, ename, job, sal, comm, deptno FROM emp;
ALTER TABLE vpemp ADD authid VARCHAR2(12);
UPDATE vpemp SET authid = 'researchmgr' WHERE deptno = 20;
UPDATE vpemp SET authid = 'salesmgr' WHERE deptno = 30;
SELECT * FROM vpemp;出力:
empno | ename | job | sal | comm | deptno | authid
-------+--------+-----------+---------+---------+--------+-------------
7782 | CLARK | MANAGER | 2450.00 | | 10 |
7839 | KING | PRESIDENT | 5000.00 | | 10 |
7934 | MILLER | CLERK | 1300.00 | | 10 |
7369 | SMITH | CLERK | 800.00 | | 20 | researchmgr
7566 | JONES | MANAGER | 2975.00 | | 20 | researchmgr
7788 | SCOTT | ANALYST | 3000.00 | | 20 | researchmgr
7876 | ADAMS | CLERK | 1100.00 | | 20 | researchmgr
7902 | FORD | ANALYST | 3000.00 | | 20 | researchmgr
7499 | ALLEN | SALESMAN | 1600.00 | 300.00 | 30 | salesmgr
7521 | WARD | SALESMAN | 1250.00 | 500.00 | 30 | salesmgr
7654 | MARTIN | SALESMAN | 1250.00 | 1400.00 | 30 | salesmgr
7698 | BLAKE | MANAGER | 2850.00 | | 30 | salesmgr
7844 | TURNER | SALESMAN | 1500.00 | 0.00 | 30 | salesmgr
7900 | JAMES | CLERK | 950.00 | | 30 | salesmgr
(14 rows)CREATE ROLE salesmgr WITH LOGIN PASSWORD 'password';
GRANT ALL ON vpemp TO salesmgr;ADD_POLICY
ポリシー関数をデータベースオブジェクトに関連付けて、セキュリティポリシーを作成します。
スーパーユーザー権限が必要です。
ADD_POLICY(
object_schema VARCHAR2,
object_name VARCHAR2,
policy_name VARCHAR2,
function_schema VARCHAR2,
policy_function VARCHAR2
[, statement_types VARCHAR2
[, update_check BOOLEAN
[, enable BOOLEAN
[, static_policy BOOLEAN
[, policy_type INTEGER
[, long_predicate BOOLEAN
[, sec_relevant_cols VARCHAR2
[, sec_relevant_cols_opt INTEGER ]]]]]]]])パラメーター
`object_schema`
ポリシーが適用されるデータベースオブジェクトを含むスキーマの名前。
`object_name`
データベースオブジェクトの名前。特定のデータベースオブジェクトには、複数のポリシーを適用できます。
`policy_name`
ポリシーの名前。データベースオブジェクト (object_schema と object_name で識別される) とポリシー名の組み合わせは、データベース内で一意である必要があります。
`function_schema`
ポリシー関数を含むスキーマ。
function_schema はパッケージが定義されているスキーマである必要があります。`policy_function`
ポリシー関数の名前。同じ関数を複数のポリシーで参照できます。
package_name.function_name) を使用します。`statement_types`
ポリシーが適用される SQL ステートメントのタイプのカンマ区切りのリスト。有効な値: INSERT、UPDATE、DELETE、SELECT。デフォルト: INSERT,UPDATE,DELETE,SELECT。
INDEX ステートメントタイプを受け入れますが、無視します。ポリシーはインデックス操作には適用できません。`update_check`
INSERT および UPDATE ステートメントにのみ適用されます。
TRUEに設定すると、ポリシーは新しく挿入された行と、更新された行の変更されたイメージにも適用されます。新しい行または変更された行がポリシー述語を満たさない場合、INSERT または UPDATE ステートメントは例外をスローし、行は挿入または変更されません。FALSEに設定すると、ポリシーは新しく挿入された行または更新された行の変更されたイメージには適用されません。したがって、新しく挿入された行は、同じポリシーを呼び出す後続のステートメントの結果セットに表示されない場合があります。
デフォルト: FALSE。
`enable`
TRUEに設定すると、ポリシーはすぐに有効になり、statement_typesで指定されたステートメントタイプに適用されます。FALSEに設定すると、ポリシーは作成されますが無効になります。後で有効にするには、ENABLE_POLICYを使用します。
デフォルト: TRUE。
`static_policy`
Oracle では、TRUE に設定すると、ポリシー関数は最初の呼び出し時にデータベースオブジェクトごとに 1 回評価され、結果の述語は再利用のためにキャッシュされます。FALSE に設定すると、ポリシー関数は呼び出しごとに再評価されます。
static_policy パラメーターは受け入れられますが、無視されます。デフォルト: FALSE。
`policy_type`
Oracle では、ポリシー関数が再評価されるタイミングを決定します。NULL 以外の値に設定すると、static_policy をオーバーライドします。
policy_type パラメーターは受け入れられますが、無視されます。デフォルト: NULL。
`long_predicate`
Oracle では、TRUE に設定すると、述語は最大 32 KB になります。それ以外の場合、述語は 4 KB に制限されます。
デフォルト: FALSE。
`sec_relevant_cols`
object_name 内の列のカンマ区切りのリスト。指定した場合、SQL ステートメントがリストされた列の少なくとも 1 つを参照する場合にのみポリシーが適用されます。リストされた列が参照されない場合、ポリシーは適用されません。
デフォルト: NULL (すべての列をリストするのと同等)。
`sec_relevant_cols_opt`
Oracle では、DBMS_RLS.ALL_ROWS (整数値 1) に設定すると、すべての行が返されますが、ポリシー述語が false と評価される行の場合、sec_relevant_cols 列は NULL に設定されます。
DBMS_RLS.ALL_ROWS をサポートしていません。sec_relevant_cols_opt を 1 に設定するとエラーがスローされます。デフォルト: NULL。
例
セッションユーザーによる行レベルのフィルタリング
このポリシー関数は、authid 列が現在のセッションユーザーと一致する行へのアクセスを制限します。
CREATE OR REPLACE FUNCTION verify_session_user (
p_schema VARCHAR2,
p_object VARCHAR2
)
RETURN VARCHAR2
IS
BEGIN
RETURN 'authid = SYS_CONTEXT(''USERENV'', ''SESSION_USER'')';
END;この関数は、authid = SYS_CONTEXT('USERENV', 'SESSION_USER') という述語を返します。これは、条件を満たす各 SQL ステートメントに AND 条件として動的に追加されます。
SYS_CONTEXT は現在のセッションの属性を返します。USERENV は現在のセッションコンテキストを表す組み込みの名前空間です。PolarDB は USERENV を使用した SYS_CONTEXT をサポートしていますが、カスタムアプリケーションコンテキストはサポートしていません。以下の匿名ブロックは、vpemp テーブルに secure_update という名前のポリシーを作成します。このポリシーは INSERT、UPDATE、および DELETE ステートメントに適用され、update_check が有効になっているため、新しく挿入または変更された行も述語を満たす必要があります。
DECLARE
v_object_schema VARCHAR2(30) := 'public';
v_object_name VARCHAR2(30) := 'vpemp';
v_policy_name VARCHAR2(30) := 'secure_update';
v_function_schema VARCHAR2(30) := 'polardb';
v_policy_function VARCHAR2(30) := 'verify_session_user';
v_statement_types VARCHAR2(30) := 'INSERT,UPDATE,DELETE';
v_update_check BOOLEAN := TRUE;
v_enable BOOLEAN := TRUE;
BEGIN
DBMS_RLS.ADD_POLICY(
v_object_schema,
v_object_name,
v_policy_name,
v_function_schema,
v_policy_function,
v_statement_types,
v_update_check,
v_enable
);
END;salesmgr ユーザーとして接続し、SELECT を実行して現在のテーブルを確認します。
\c polardb salesmgr
Password for user salesmgr:
You are now connected to database "polardb" as user "salesmgr".
SELECT * FROM vpemp;出力:
empno | ename | job | sal | comm | deptno | authid
-------+--------+-----------+---------+---------+--------+-------------
7782 | CLARK | MANAGER | 2450.00 | | 10 |
7839 | KING | PRESIDENT | 5000.00 | | 10 |
7934 | MILLER | CLERK | 1300.00 | | 10 |
7369 | SMITH | CLERK | 800.00 | | 20 | researchmgr
7566 | JONES | MANAGER | 2975.00 | | 20 | researchmgr
7788 | SCOTT | ANALYST | 3000.00 | | 20 | researchmgr
7876 | ADAMS | CLERK | 1100.00 | | 20 | researchmgr
7902 | FORD | ANALYST | 3000.00 | | 20 | researchmgr
7499 | ALLEN | SALESMAN | 1600.00 | 300.00 | 30 | salesmgr
7521 | WARD | SALESMAN | 1250.00 | 500.00 | 30 | salesmgr
7654 | MARTIN | SALESMAN | 1250.00 | 1400.00 | 30 | salesmgr
7698 | BLAKE | MANAGER | 2850.00 | | 30 | salesmgr
7844 | TURNER | SALESMAN | 1500.00 | 0.00 | 30 | salesmgr
7900 | JAMES | CLERK | 950.00 | | 30 | salesmgr
(14 rows)salesmgr として非修飾 UPDATE を発行します。
UPDATE 6出力:
UPDATE 6ポリシーは、authid = 'salesmgr' の行に UPDATE を制限し、セッションユーザーと一致させます。これらの 6 行のみが変更されます。
結果を確認します。
SELECT * FROM vpemp;出力:
empno | ename | job | sal | comm | deptno | authid
-------+--------+-----------+---------+---------+--------+-------------
7782 | CLARK | MANAGER | 2450.00 | | 10 |
7839 | KING | PRESIDENT | 5000.00 | | 10 |
7934 | MILLER | CLERK | 1300.00 | | 10 |
7369 | SMITH | CLERK | 800.00 | | 20 | researchmgr
7566 | JONES | MANAGER | 2975.00 | | 20 | researchmgr
7788 | SCOTT | ANALYST | 3000.00 | | 20 | researchmgr
7876 | ADAMS | CLERK | 1100.00 | | 20 | researchmgr
7902 | FORD | ANALYST | 3000.00 | | 20 | researchmgr
7499 | ALLEN | SALESMAN | 1600.00 | 1200.00 | 30 | salesmgr
7521 | WARD | SALESMAN | 1250.00 | 937.50 | 30 | salesmgr
7654 | MARTIN | SALESMAN | 1250.00 | 937.50 | 30 | salesmgr
7698 | BLAKE | MANAGER | 2850.00 | 2137.50 | 30 | salesmgr
7844 | TURNER | SALESMAN | 1500.00 | 1125.00 | 30 | salesmgr
7900 | JAMES | CLERK | 950.00 | 712.50 | 30 | salesmgr
(14 rows)update_check が TRUE のため、authid = 'researchmgr' の行を挿入すると失敗します。これは、新しい行が salesmgr セッションユーザーのポリシー述語を満たさないためです。
INSERT INTO vpemp VALUES (9001,'SMITH','ANALYST',3200.00,NULL,20, 'researchmgr');出力:
ERROR: policy with check option violation
DETAIL: Policy predicate was evaluated to FALSE with the updated valuesupdate_check が FALSE に設定されている場合、同じ INSERT は成功します。
列レベルの VPD
sec_relevant_cols を使用して、特定の列が SQL ステートメントに表示される場合にのみポリシーを適用します。この例では、sal または comm が選択されたときに返される行を制限し、給与が 2000 未満の従業員のみを保持します。
CREATE OR REPLACE FUNCTION sal_lt_2000 (
p_schema VARCHAR2,
p_object VARCHAR2
)
RETURN VARCHAR2
IS
BEGIN
RETURN 'sal < 2000';
END;sec_relevant_cols を 'sal,comm' に設定してポリシーを作成します。
DECLARE
v_object_schema VARCHAR2(30) := 'public';
v_object_name VARCHAR2(30) := 'vpemp';
v_policy_name VARCHAR2(30) := 'secure_salary';
v_function_schema VARCHAR2(30) := 'polardb';
v_policy_function VARCHAR2(30) := 'sal_lt_2000';
v_statement_types VARCHAR2(30) := 'SELECT';
v_sec_relevant_cols VARCHAR2(30) := 'sal,comm';
BEGIN
DBMS_RLS.ADD_POLICY(
v_object_schema,
v_object_name,
v_policy_name,
v_function_schema,
v_policy_function,
v_statement_types,
sec_relevant_cols => v_sec_relevant_cols
);
END;sal または comm を参照しないクエリは、14 行すべてを返します。ポリシーはトリガーされません。
SELECT empno, ename, job, deptno, authid FROM vpemp;出力:
empno | ename | job | deptno | authid
-------+--------+-----------+--------+-------------
7782 | CLARK | MANAGER | 10 |
7839 | KING | PRESIDENT | 10 |
7934 | MILLER | CLERK | 10 |
7369 | SMITH | CLERK | 20 | researchmgr
7566 | JONES | MANAGER | 20 | researchmgr
7788 | SCOTT | ANALYST | 20 | researchmgr
7876 | ADAMS | CLERK | 20 | researchmgr
7902 | FORD | ANALYST | 20 | researchmgr
7499 | ALLEN | SALESMAN | 30 | salesmgr
7521 | WARD | SALESMAN | 30 | salesmgr
7654 | MARTIN | SALESMAN | 30 | salesmgr
7698 | BLAKE | MANAGER | 30 | salesmgr
7844 | TURNER | SALESMAN | 30 | salesmgr
7900 | JAMES | CLERK | 30 | salesmgr
(14 rows)sal または comm を含むクエリはポリシーをトリガーし、sal >= 2000 の行をフィルタリングします。
SELECT empno, ename, job, sal, comm, deptno, authid FROM vpemp;出力:
empno | ename | job | sal | comm | deptno | authid
-------+--------+----------+---------+---------+--------+-------------
7934 | MILLER | CLERK | 1300.00 | | 10 |
7369 | SMITH | CLERK | 800.00 | | 20 | researchmgr
7876 | ADAMS | CLERK | 1100.00 | | 20 | researchmgr
7499 | ALLEN | SALESMAN | 1600.00 | 1200.00 | 30 | salesmgr
7521 | WARD | SALESMAN | 1250.00 | 937.50 | 30 | salesmgr
7654 | MARTIN | SALESMAN | 1250.00 | 937.50 | 30 | salesmgr
7844 | TURNER | SALESMAN | 1500.00 | 1125.00 | 30 | salesmgr
7900 | JAMES | CLERK | 950.00 | 712.50 | 30 | salesmgr
(8 rows)DROP_POLICY
データベースオブジェクトからセキュリティポリシーを削除します。ポリシーを削除しても、ポリシー関数やデータベースオブジェクト自体は削除されません。
スーパーユーザー権限が必要です。
DROP_POLICY(
object_schema VARCHAR2,
object_name VARCHAR2,
policy_name VARCHAR2
)パラメーター
| パラメーター | 説明 |
|---|---|
object_schema | ポリシーが適用されるデータベースオブジェクトのスキーマ。 |
object_name | データベースオブジェクトの名前。 |
policy_name | 削除するポリシーの名前。 |
例
public.vpemp テーブルから secure_update ポリシーを削除します。
DECLARE
v_object_schema VARCHAR2(30) := 'public';
v_object_name VARCHAR2(30) := 'vpemp';
v_policy_name VARCHAR2(30) := 'secure_update';
BEGIN
DBMS_RLS.DROP_POLICY(
v_object_schema,
v_object_name,
v_policy_name
);
END;ENABLE_POLICY
データベースオブジェクトの既存のセキュリティポリシーを有効または無効にします。
スーパーユーザー権限が必要です。
ENABLE_POLICY(
object_schema VARCHAR2,
object_name VARCHAR2,
policy_name VARCHAR2,
enable BOOLEAN
)パラメーター
| パラメーター | 説明 |
|---|---|
object_schema | ポリシーが適用されるデータベースオブジェクトのスキーマ。 |
object_name | データベースオブジェクトの名前。 |
policy_name | 有効または無効にするポリシーの名前。 |
enable | ポリシーを有効にするには TRUE に、無効にするには FALSE に設定します。 |
例
public.vpemp テーブルの secure_update ポリシーを無効にします:
DECLARE
v_object_schema VARCHAR2(30) := 'public';
v_object_name VARCHAR2(30) := 'vpemp';
v_policy_name VARCHAR2(30) := 'secure_update';
v_enable BOOLEAN := FALSE;
BEGIN
DBMS_RLS.ENABLE_POLICY(
v_object_schema,
v_object_name,
v_policy_name,
v_enable
);
END;