1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

VPDで保護された表にOACセマンティック・モデルから接続する

Posted at

はじめに

OAC(Oracle Analytics Cloud)のセマンティック・モデルでは、接続プールの設定を使用してデータソースに接続します。
通常、接続プールでは特定のユーザー名とパスワードが指定されているので、セマンティック・モデルを経由してデータソースに接続する際は、すべてのOACユーザーが同じユーザーでアクセスすることになります。
このようなケースにおいても、Oracle Databaseの仮想プライベートデータベース(VPD)を使用して行レベルセキュリティを実現することができます。

本記事で実現すること:

  • Autonomous Database(ADB)にある特定の表に行レベルセキュリティを設定する
  • OACにログインするユーザーごとに参照できる範囲(行)を制限する
  • 対象のOACユーザーがどの行を参照できるかは、ADBの表で管理する
  • OACのセマンティック・モデルで実現する

サンプルデータの準備

※ SQLの実行には、SQL Developerを使用しました。
次の記事で使用した、ADBUSERユーザーを流用します。

ADBにADBUSERが存在しない場合は作成します。
※適切なパスワードを指定してください。

CREATE USER adbuser IDENTIFIED BY "************";
GRANT DWROLE TO adbuser;
alter user adbuser quota unlimited on data;

ADBUSERで接続して、SHサンプルスキーマを利用してテスト用のデータを作成します。

テストデータ作成
CREATE TABLE adbuser.sales AS SELECT * FROM sh.sales WHERE prod_id in (13,14,15) ROWNUM <= 10000;
CREATE TABLE adbuser.products AS SELECT * FROM sh.products;

仮想プライベートデータベース(VPD)の設定

VPD用の管理者ユーザーの作成

この記事で作成したVPD用のユーザーである VPDADMIN を使用します。
存在しない場合は、作成します。コンテキストを作成できる権限も付与します。

CREATE USER vpdadmin IDENTIFIED BY "************";
GRANT DWROLE TO vpdadmin;
GRANT CREATE ANY CONTEXT TO vpdadmin; 
alter user vpdadmin quota unlimited on data;

VPDADMINで接続します。
OACユーザーがどの行を参照できるかを管理する表を作成し、データをインサートします。
OAC_USER列にOACのユーザー名を、SECURITY_VALUE列にそのユーザーが検索可能なPROD_IDの値をインサートしました。

セキュリティ表の作成
CREATE TABLE VPDADMIN.SECURITY_TABLE
   (
    OAC_USER VARCHAR2(30), 
    SECURITY_VALUE NUMBER
);

insert into vpdadmin.security_table(oac_user,security_value) values('OACUSER1',13);
insert into vpdadmin.security_table(oac_user,security_value) values('OACUSER2',14);

アプリケーション・コンテキストの作成

Oracle Databaseのアプリケーション・コンテキストは、セッションごとの「属性(キー=値)」を保持し、SQLやPL/SQLから参照できる仕組みです。ユーザーやアプリの状態(役割、地域、テナントID、機能フラグなど)をDB側で一貫して扱うために使われます。

ここでは、OACから通知されるOACユーザー名を保持するために使用します。

アプリケーション・コンテキストの作成
CREATE OR REPLACE CONTEXT OAC_CTX USING VPDADMIN.OAC_CTX_PKG;
CREATE OR REPLACE PACKAGE VPDADMIN.OAC_CTX_PKG
IS
  PROCEDURE set_ctx(OACUSER VARCHAR2);
END;
/
CREATE OR REPLACE PACKAGE BODY VPDADMIN.OAC_CTX_PKG
IS
  PROCEDURE set_ctx(OACUSER VARCHAR2)
  IS
  BEGIN
    DBMS_SESSION.SET_CONTEXT('OAC_CTX', 'OACUSER', OACUSER);
  END;
END;
/
GRANT EXECUTE on VPDADMIN.OAC_CTX_PKG to adbuser;

VPDポリシー関数の作成

次に、行レベルセキュリティを適用するためのポリシー関数を作成します。

ポリシー関数の作成
CREATE OR REPLACE FUNCTION VPDADMIN.vpd_policy_function (
    object_schema IN VARCHAR2,
    object_name IN VARCHAR2
) RETURN VARCHAR2 AS
    v_oac_user_name VARCHAR2(100);
    v_security_value NUMBER;
BEGIN
    -- OACユーザー名を取得
    v_oac_user_name := upper(SYS_CONTEXT('OAC_CTX', 'OACUSER'));

    -- security_tableから該当するセキュリティ値を取得
    BEGIN
        SELECT security_value INTO v_security_value
        FROM VPDADMIN.security_table
        WHERE oac_user = v_oac_user_name;
    EXCEPTION
        WHEN NO_DATA_FOUND THEN
            -- security_tableに該当ユーザーが存在しない場合、アクセスを禁止
            RETURN '1=0';
    END;

    -- PROD_ID列の値がセキュリティ値と一致する行のみ許可
    RETURN 'PROD_ID = ' || TO_CHAR(v_security_value);
END vpd_policy_function;
/

VPDポリシーの設定

表にポリシーを適用します。

ポリシーの適用
BEGIN
    DBMS_RLS.ADD_POLICY(
        object_schema         => 'adbuser',
        object_name           => 'SALES',
        policy_name           => 'sales_vpd_policy',
        function_schema       => 'VPDADMIN',
        policy_function       => 'vpd_policy_function',
        statement_types       => 'SELECT',
        policy_type           => DBMS_RLS.CONTEXT_SENSITIVE
    );
END;
/

※参考:ポリシーの削除

BEGIN
    DBMS_RLS.DROP_POLICY(
        object_schema => 'adbuser',
        object_name   => 'SALES',
        policy_name   => 'sales_vpd_policy'
    );
END;
/

SQL Developerでテスト

adbuserで接続して、検索できるかどうかテストしてみます。

image.png

結果は0件です。
表の所有者であるadbuserにもVPDが適用されており、adbuserは何の権限も持たないからです。

セマンティックモデルの設定

セマンティックモデラーで、セマンティックモデルを作成します。

システム接続の作成

システム接続を作成します。
「新規」ボタンから「接続」をクリックします。

image.png

image.png

接続定義を設定します。
「システム接続」をオンにしておきます。

image.png

物理レイヤーの作成

「新規」ボタンから「セマンティック・モデル」をクリックします。

image.png

任意の名前を入力して「作成」をクリックします。

image.png

「空のモデルで開始」をクリックします。

image.png

「MyDatabase」をダブルクリックし、「一般」タブのデータベースタイプを「Oracle Autonomous Data Warehouse」にします。

image.png

「表」タブに移動し、「SALES」「PRODUCTS」をドラッグ&ドロップします。

image.png

結合を追加します。

image.png

PROD_ID列同士で結合を定義し、「追加」をクリックします。

image.png

ここまでは、通常通りの設定です。

接続プールでのスクリプトの設定

「拡張」タブに移動し、「仮想プライベートデータベース」をオンにします。

image.png

「接続プールタブ」に移動します。
「詳細ビュー」を表示して、接続スクリプト「問合せ前に実行」を追加します。

image.png

次のコードを設定します。行端の「;」を忘れないでください。

問い合わせ前に実行するコード
CALL VPDADMIN.OAC_CTX_PKG.set_ctx('VALUEOF(NQ_SESSION.USER)');

image.png

有効化されていることを確認します。
スクリプトが設定されていても、有効化されていないと実行されません。

残りを定義して保存

セマンティックモデルの残りの部分(論理レイヤー、プレゼンテーション・レイヤー)を設定し、デプロイします。

image.png

動作確認

デプロイしたサブジェクト領域を使用して、ワークブックを作成しました。

OACUser1でテスト

image.png

PROD_ID(すなわち製品ID)が13のデータしか検索されていません。
当然ながら、OAC側で検索条件は何も設定していません。

VPDの対象となっているSALES表を避けて、PRODUCTS表だけを検索するようにすると(この例では、販売数量や販売金額を除外)、たくさんの行が検索されました。

image.png

これを避けるには、PRODUCTS表に対してもVPDを設定する必要があります。

OACUser2でテスト

ログアウトして、OACUser2でログインし直しました。

image.png

「製品ID」が14の行だけが検索されました。

おわりに

セマンティックモデルを経由してデータベースに接続するとき、通常は指定したユーザーで接続することになるので、データベースから見るとどのOACユーザーが接続しているのかを識別できません。

今回は、OACセマンティックモデルの接続プールの「問合せ前に実行」スクリプトを使用して、ADBに「自分が何者か」についての情報を引き渡すことで、同じユーザーでログインしているのに、実際に使用しているOACユーザーが誰かを識別することができました。

参考情報

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?