2025年8月20日水曜日

Entra IDで認証したMCPサーバーにReal Application Securityを適用する

先日の記事「Entra IDで認証したMCPサーバーに仮想プライベート・データベースのポリシーを適用する」では、MCPサーバーからのアクセスに仮想プライベート・データベースのポリシーを適用しました。

本記事では仮想プラベート・データベースの代わりにReal Application Securityを構成してみます。作業の前提などは前出の記事と同じ、また、サンプル・データセットのhuman resourcesのインストールが完了したところから作業を続けます。


管理ユーザーRASADMINの作成と各種権限の付与



Real Application Securityを構成するためのデータベース・ユーザーとしてRASADMINを作成します。

データベースSALESADBに管理者ユーザーADMINで接続し、作業を進めます。

sql admin@salesadb_low

azure % sql admin@salesadb_low



SQLcl: 水 8月 20 11:51:58 2025のリリース25.2 Production


Copyright (c) 1982, 2025, Oracle.  All rights reserved.


パスワード (**********?) **************

Last Successful login time: 水 8月  20 2025 11:52:08 +09:00


接続先:

Oracle Database 23ai Enterprise Edition Release 23.0.0.0.0 - for Oracle Cloud and Engineered Systems

Version 23.9.0.25.08


SQL> 


データベース・ユーザーRASADMINを作成し、最低限必要な権限を与えます。

create user rasadmin identified by <パスワード>;
alter user rasadmin quota 25m on data;
grant create session to rasadmin;
grant create table, create procedure to rasadmin;

SQL> create user rasadmin identified by **********;


User RASADMINは作成されました。


SQL> alter user rasadmin quota 25m on data;


User RASADMINが変更されました。


SQL> grant create session to rasadmin;


Grantが正常に実行されました。


SQL> grant create table, create procedure to rasadmin;


Grantが正常に実行されました。


SQL> 


RASADMINに、Real Application Securityを構成するために必要な権限を与えます。
begin
    sys.xs_admin_cloud_util.grant_system_privilege('PROVISION','RASADMIN');
    sys.xs_admin_cloud_util.grant_system_privilege('ADMIN_ANY_SEC_POLICY','RASADMIN');
end;
/

SQL> begin

  2      sys.xs_admin_cloud_util.grant_system_privilege('PROVISION','RASADMIN');

  3      sys.xs_admin_cloud_util.grant_system_privilege('ADMIN_ANY_SEC_POLICY','RASADMIN');

  4  end;

  5* /


PL/SQLプロシージャが正常に完了しました。


SQL> 


ロールHR_ROLEを作成し、ユーザーRASADMINに割り当てます。ロールHR_ROLEは後ほど、ユーザーRASADMINが作成したアプリケーション・ロールEMPLOYEEに割り当てます。

create role hr_role;
grant select any table on schema hr to hr_role;
grant hr_role to rasadmin with admin option;

SQL> create role hr_role;


Role HR_ROLEは作成されました。


SQL> grant select any table on schema hr to hr_role;


Grantが正常に実行されました。


SQL> grant hr_role to rasadmin with admin option;


Grantが正常に実行されました。


SQL> 


MCPサーバーの接続ユーザーMCPUSERに権限を追加します。スキーマHRの表を検索する権限を与えます。また、RASセッションを操作する権限ADMINISTER_SESSIONも与えます。
grant select any table on schema hr to mcpuser;
begin
    sys.xs_admin_cloud_util.grant_system_privilege('ADMINISTER_SESSION','MCPUSER');
end;
/

SQL> grant select any table on schema hr to mcpuser;


Grantが正常に実行されました。


SQL> grant create trigger to mcpuser;


Grantが正常に実行されました。


SQL> begin

  2      sys.xs_admin_cloud_util.grant_system_privilege('ADMINISTER_SESSION','MCPUSER');

  3  end;

  4* /


PL/SQLプロシージャが正常に完了しました。


SQL> 

SQL> exit

Oracle Database 23ai Enterprise Edition Release 23.0.0.0.0 - for Oracle Cloud and Engineered Systems

Version 23.9.0.25.08から切断されました

azure % 


以上で、管理ユーザーRASADMINの作成と各種権限の付与が完了しました。


Real Application Securityの構成



作成した管理ユーザーRASADMINにて、Real Application Securityを構成します。

sql rasadmin@salesadb_low

azure % sql rasadmin@salesadb_low



SQLcl: 火 8月 19 10:18:53 2025のリリース25.2 Production


Copyright (c) 1982, 2025, Oracle.  All rights reserved.


パスワード (**********?) **************

接続先:

Oracle Database 23ai Enterprise Edition Release 23.0.0.0.0 - for Oracle Cloud and Engineered Systems

Version 23.9.0.25.08


SQL> 


Entra IDで認証されたユーザーは、システム・コンテキストUSERENVの属性AUTHENTICATED_IDENTITYにユーザーIDが設定されます。このEntra IDのユーザーをスキーマHRの表EMPLOYEESに保存されている従業員に対応させるために、表AUTH_USERSを作成します。
create table auth_users(
    employee_id number not null,
    department_id number not null,
    email varchar2(25),
    authenticated_identity varchar2(128) not null
);
grant select on auth_users to mcpuser;

SQL> create table auth_users(

  2      employee_id number not null,

  3      department_id number not null,

  4      email varchar2(25),

  5      authenticated_identity varchar2(128) not null

  6* );


Table AUTH_USERSは作成されました。


SQL> grant select on auth_users to mcpuser;


Grantが正常に実行されました。


SQL> 


Entra IDで認証されたユーザーがEMPLOYEE_ID=105, DEPARTMENT_ID=60のDavid Williamsとして認識されるように、表AUTH_USERSに以下の1行を挿入します。

insert into auth_users(employee_id, department_id, email, authenticated_identity) values(105,60,'DWILLIAMS','Entra IDのユーザーのID - upnとして渡される値');
commit;


SQL> insert into auth_users(employee_id, department_id, email, authenticated_identity) values(105,60,'DWILLIAMS','yuji______outlook.com_EXT_@________outlook.onmicrosoft.com');


1行挿入しました。


SQL> commit;


コミットが完了しました。


SQL> 


アプリケーション・ロールEMPLOYEEを、動的ロールとして作成します。

今回はReal Application Securityのセッションに、Entra IDで認証したユーザーを外部ユーザーとして割り当てます。認証されたRASセッションで、ここで作成する動的ロールEMPLOYEEを有効化します。
begin
    sys.xs_principal.create_dynamic_role(
        name => 'EMPLOYEE',
        scope => XS_PRINCIPAL.SESSION_SCOPE
    );
end;
/

SQL> begin

  2      sys.xs_principal.create_dynamic_role(

  3          name => 'EMPLOYEE',

  4          scope => XS_PRINCIPAL.SESSION_SCOPE

  5      );

  6  end;

  7* /


PL/SQLプロシージャが正常に完了しました。


SQL> 


アプリケーション・ロールEMPLOYEEに、ロールHR_ROLEを割り当てます。結果として動的ロールEMPLOYEEが有効化されたRASセッションでは、ロールHR_ROLEの持つ権限が与えられます。

grant hr_role to employee;

SQL> grant hr_role to employee;


Grantが正常に実行されました。


SQL> 


ネームスペース・テンプレートとしてHREMPを作成します。仮想プライベート・データベースでのアプリケーション・コンテキストと同じ用途で使用します。

このアプリケーション・コンテキストに表AUTH_USERSから検索された、Entra IDのユーザーに対応した従業員のEMPLOYEE_IDDEPARTMENT_IDを保持します。
declare
    attrlist XS$NS_ATTRIBUTE_LIST;
begin
    attrlist := XS$NS_ATTRIBUTE_LIST();
    attrlist.extend(2);
    attrlist(1) := XS$NS_ATTRIBUTE('employee_id','0');
    attrlist(2) := XS$NS_ATTRIBUTE('department_id','0');
    sys.xs_namespace.create_template(
        name => 'HREMP',
        attr_list => attrlist,
        acl => 'SYS.NS_UNRESTRICTED_ACL'
    );
end;
/

SQL> declare

  2      attrlist XS$NS_ATTRIBUTE_LIST;

  3  begin

  4      attrlist := XS$NS_ATTRIBUTE_LIST();

  5      attrlist.extend(2);

  6      attrlist(1) := XS$NS_ATTRIBUTE('employee_id','0');

  7      attrlist(2) := XS$NS_ATTRIBUTE('department_id','0');

  8      sys.xs_namespace.create_template(

  9          name => 'HREMP',

 10          attr_list => attrlist,

 11          acl => 'SYS.NS_UNRESTRICTED_ACL'

 12      );

 13  end;

 14* /


PL/SQLプロシージャが正常に完了しました。


SQL> 


セキュリティ・クラスとしてemp_privを作成します。

parent_listとしてsys.dmlを指定することにより、標準で定義されている権限のリストselect、update、insert、deleteを引き継ぎます。セキュリティ・クラスemp_privが持つ固有の権限として、view_salを含めます。これは列SALARYCOMMISSION_PCTへのアクセスを制御します。
begin
    sys.xs_security_class.create_security_class(
        name => 'emp_priv',
        parent_list => xs$name_list('sys.dml'),
        priv_list => xs$privilege_list(xs$privilege('view_sal'))
    );
end;
/

SQL> begin

  2      sys.xs_security_class.create_security_class(

  3          name => 'emp_priv',

  4          parent_list => xs$name_list('sys.dml'),

  5          priv_list => xs$privilege_list(xs$privilege('view_sal'))

  6      );

  7  end;

  8* /


PL/SQLプロシージャが正常に完了しました。


SQL> 


サインインしたユーザーと同じ部門にアクセスを限定するACLとして、emp_aclを作成します。
declare
    aces xs$ace_list := xs$ace_list();
begin
    aces.extend(1);
    aces(1) := xs$ace_type(
        privilege_list => xs$name_list('select','insert','update','delete'),
        principal_name => 'employee' -- application role
    );
    sys.xs_acl.create_acl(
        name => 'emp_acl',
        ace_list => aces,
        sec_class => 'emp_priv' -- security class
    );
end;
/

SQL> declare

  2      aces xs$ace_list := xs$ace_list();

  3  begin

  4      aces.extend(1);

  5      aces(1) := xs$ace_type(

  6          privilege_list => xs$name_list('select','insert','update','delete'),

  7          principal_name => 'employee' -- application role

  8      );

  9      sys.xs_acl.create_acl(

 10          name => 'emp_acl',

 11          ace_list => aces,

 12          sec_class => 'emp_priv' -- security class

 13      );

 14  end;

 15* /


PL/SQLプロシージャが正常に完了しました。


SQL> 


サインインしたユーザーがマネージャーである従業員の列SALARYCOMMISSION_PCTにアクセスを限定するACLとして、mgr_aclを作成します。
declare
    aces xs$ace_list := xs$ace_list();
begin
    aces.extend(1);
    aces(1) := xs$ace_type(
        privilege_list => xs$name_list('select','insert','update','delete','view_sal'),
        principal_name => 'employee' -- application role
    );
    sys.xs_acl.create_acl(
        name => 'mgr_acl',
        ace_list => aces,
        sec_class => 'emp_priv'
    );
end;
/

SQL> declare

  2      aces xs$ace_list := xs$ace_list();

  3  begin

  4      aces.extend(1);

  5      aces(1) := xs$ace_type(

  6          privilege_list => xs$name_list('select','insert','update','delete','view_sal'),

  7          principal_name => 'employee' -- application role

  8      );

  9      sys.xs_acl.create_acl(

 10          name => 'mgr_acl',

 11          ace_list => aces,

 12          sec_class => 'emp_priv'

 13      );

 14  end;

 15* /


PL/SQLプロシージャが正常に完了しました。


SQL> 


データ・セキュリティ・ポリシーとして、employee_dsを作成します。
declare
    realms xs$realm_constraint_list := xs$realm_constraint_list();
    cols xs$column_constraint_list := xs$column_constraint_list();
begin
    realms.extend(2);
    realms(1) := xs$realm_constraint_type(
        realm => q'~department_id = xs_sys_context('HREMP','department_id')~',
        acl_list => xs$name_list('emp_acl')
    );
    realms(2) := xs$realm_constraint_type(
        realm => q'~manager_id = xs_sys_context('HREMP','employee_id')~',
        acl_list => xs$name_list('mgr_acl')
    );
    cols.extend(1);
    cols(1) := xs$column_constraint_type(
        column_list => xs$list('SALARY','COMMISSION_PCT'),
        privilege => 'view_sal'
    );
    sys.xs_data_security.create_policy(
        name => 'employee_ds',
        realm_constraint_list => realms,
        column_constraint_list => cols
    );
end;
/

SQL> declare

  2      realms xs$realm_constraint_list := xs$realm_constraint_list();

  3      cols xs$column_constraint_list := xs$column_constraint_list();

  4  begin

  5      realms.extend(2);

  6      realms(1) := xs$realm_constraint_type(

  7          realm => q'~department_id = xs_sys_context('HREMP','department_id')~',

  8          acl_list => xs$name_list('emp_acl')

  9      );

 10      realms(2) := xs$realm_constraint_type(

 11          realm => q'~manager_id = xs_sys_context('HREMP','employee_id')~',

 12          acl_list => xs$name_list('mgr_acl')

 13      );

 14      cols.extend(1);

 15      cols(1) := xs$column_constraint_type(

 16          column_list => xs$list('SALARY','COMMISSION_PCT'),

 17          privilege => 'view_sal'

 18      );

 19      sys.xs_data_security.create_policy(

 20          name => 'employee_ds',

 21          realm_constraint_list => realms,

 22          column_constraint_list => cols

 23      );

 24  end;

 25* /


PL/SQLプロシージャが正常に完了しました。


>


データ・セキュリティ・ポリシーemployee_dsを、表HR.EMPLOYEESに適用します。
begin
    sys.xs_data_security.apply_object_policy(
        policy => 'employee_ds',
        schema => 'hr',
        object => 'employees'
    );
end;
/

SQL> begin

  2      sys.xs_data_security.apply_object_policy(

  3          policy => 'employee_ds',

  4          schema => 'hr',

  5          object => 'employees'

  6      );

  7  end;

  8* /


PL/SQLプロシージャが正常に完了しました。


SQL> 


設定を検証します。XS_DIAG.VAIDATE_WORKSPACE()を実行します。

設定に問題がなければ、All Configurations are correct.と表示されます。
set serveroutput on
begin
    if (sys.xs_diag.validate_workspace()) then
        dbms_output.put_line('All Configurations are correct.');
    else
        dbms_output.put_line('Some configurations are incorrect.');
    end if;
end;
/

SQL> set serveroutput on

SQL> begin

  2      if (sys.xs_diag.validate_workspace()) then

  3          dbms_output.put_line('All Configurations are correct.');

  4      else

  5          dbms_output.put_line('Some configurations are incorrect.');

  6      end if;

  7  end;

  8* /

All Configurations are correct.



PL/SQLプロシージャが正常に完了しました。


SQL> 


データベースに接続した際にReal Application Securityのセッションを初期化するパッケージを、EMP_DEPT_CTX_PKGとして作成します。

色々とデバッグが大変だったので、パッケージにデバッグ・ログを出力するコードを残しています。ログを出力する表はDEBUG_LOGとして作成します。

create table debug_log(m varchar2(4000), d timestamp default systimestamp);
grant all on debug_log to public;

SQL> create table debug_log(m varchar2(4000), d timestamp default systimestamp);


Table DEBUG_LOGは作成されました。


SQL> grant all on debug_log to public;


Grantが正常に実行されました。


SQL> 


条件コンパイルを有効にするには、パッケージをコンパイルする前にALTER SESSION文でPLSQL_CCFLAGSに'debug:true'を設定します。

ALTER SESSION SET PLSQL_CCFLAGS = 'debug:true';

SQL> ALTER SESSION SET PLSQL_CCFLAGS = 'debug:true';


Sessionが変更されました。


SQL> 




SQL> @emp_dept_ctx_pkg.sql


Package EMP_DEPT_CTX_PKGがコンパイルされました



Package Body EMP_DEPT_CTX_PKGがコンパイルされました


SQL> 


このパッケージはMCPサーバーからデータベースに接続するユーザーが呼び出すため、ユーザーMCPUSERに実行権限を与えます。

grant execute on emp_dept_ctx_pkg to mcpuser;

SQL> grant execute on emp_dept_ctx_pkg to mcpuser;


Grantが正常に実行されました。


SQL> exit

Oracle Database 23ai Enterprise Edition Release 23.0.0.0.0 - for Oracle Cloud and Engineered Systems

Version 23.9.0.25.08から切断されました

azure % 


以上でReal Application Securityが構成できました。


動作確認



Real Application Securityのセッションの初期化をログオン・トリガーで行おうとすると、以下のエラーが発生します。

ORA-46100: 定義者の権限プログラム単位の実行中は、XSセッション操作は許可されていません。

パッケージEMP_DEPT_CTX_PKGはAUTHID CURRENT_USERを指定することで実行者権限で動作するようになっています。しかし、それをログオン・トリガーから呼び出すと、ログオン・トリガーが定義者権限で動作するため、上記のエラーが発生します。

セッションの作成時に呼び出されるグローバル・コールバックを作成し、その中からReal Application Securityのプロシージャを呼び出すと、以下のエラーが発生します。

ORA-46207: グローバル・コールバックの実行中は、セッション操作ATTACH_SESSIONは許可されません。

結論としては、仮想プライベート・データベースとは異なり、Real Application Securityのセッションはログイン・トリガーで初期化することはできません。

Real Application Securityの初期化方法はChatGPTに教えてもらったのですが、最初はログオン・トリガーを勧めてきました。ORA-46100が発生すると返したら、次にグローバル・コールバックの使用を勧めてきました。ORA-46207が発生すると返したら、ログオン・トリガーではできない、と返してきました。エラーの内容からみて、これが正解でしょう。

データベースに接続したときにReal Application Securityの初期化が行われるように、login.sqlを作成し、以下の内容を記述します。Entra IDによる認証が行われたときは、Real Application Securityを初期化するプロシージャを実行します。
begin
    if sys_context('USERENV','AUTHENTICATION_METHOD') = 'TOKEN_GLOBAL' then
        rasadmin.emp_dept_ctx_pkg.init;
    end if;
end;
/
login.sqlが参照されるように、環境変数SQLPATHを設定します。

export SQLPATH=$PWD

azure % export SQLPATH=$PWD

azure % 


SALESADB_AZCODE(TOKEN_AUTH=AZURE_DEVICE_CODE)でデータベースに接続して表HR.EMPLOYEESを検索します。

sql /@salesadb_azcode
select employee_id, first_name, last_name, email, salary, commission_pct, manager_id, department_id from hr.employees;


EMPLOYEE_IDが105のDavid Williamsが所属している部署はIT - DEPARTMENT_IDが60 -です。また、David Willamsは誰のマネージャでもありません。

検索結果は以下のようになります。DEPARTMENT_ID60の行だけが検索されています。また、MANAGER_ID105の行は無いので、列SALARYおよびCOMMISSIOIN_PCTが表示されている行はありません。

Real Application Securityのポリシーが適用されていることが確認できます。

azure % sql /@salesadb_azcode



SQLcl: 水 8月 20 12:39:51 2025のリリース25.2 Production


Copyright (c) 1982, 2025, Oracle.  All rights reserved.


To sign in, use a web browser to open the page https://microsoft.com/devicelogin and enter the code O8Q4LG3JG to authenticate.


PL/SQLプロシージャが正常に完了しました。


接続先:

Oracle Database 23ai Enterprise Edition Release 23.0.0.0.0 - for Oracle Cloud and Engineered Systems

Version 23.9.0.25.08


SQL> select employee_id, first_name, last_name, email, salary, commission_pct, manager_id, department_id from hr.employees;


   EMPLOYEE_ID FIRST_NAME    LAST_NAME    EMAIL           SALARY    COMMISSION_PCT    MANAGER_ID    DEPARTMENT_ID 

______________ _____________ ____________ ____________ _________ _________________ _____________ ________________ 

           103 Alexander     James        AJAMES                                             102               60 

           104 Bruce         Miller       BMILLER                                            103               60 

           105 David         Williams     DWILLIAMS                                          103               60 

           106 Valli         Jackson      VJACKSON                                           103               60 

           107 Diana         Nguyen       DNGUYEN                                            103               60 


SQL> exit

Oracle Database 23ai Enterprise Edition Release 23.0.0.0.0 - for Oracle Cloud and Engineered Systems

Version 23.9.0.25.08から切断されました

azure % 


EMPLOYEE_IDが103のAlexander Jamesは、IT部門のマネージャです。マネージャーがサインインしたときは、列SALARYとCOMMISION_PCTが表示されることを確認します。

ユーザーRASADMINで接続し、表AUTH_USERSに設定したEMPLOYEE_ID103、EMAILをAJAMESに変更します。

update auth_users set employee_id = 103, email = 'AJAMES';

azure % sql rasadmin@salesadb_low



SQLcl: 水 8月 20 12:44:20 2025のリリース25.2 Production


Copyright (c) 1982, 2025, Oracle.  All rights reserved.


パスワード (**********?) **************


PL/SQLプロシージャが正常に完了しました。


接続先:

Oracle Database 23ai Enterprise Edition Release 23.0.0.0.0 - for Oracle Cloud and Engineered Systems

Version 23.9.0.25.08


SQL> update auth_users set employee_id = 103, email = 'AJAMES';


1行更新しました。


SQL> commit;


コミットが完了しました。


SQL> exit

Oracle Database 23ai Enterprise Edition Release 23.0.0.0.0 - for Oracle Cloud and Engineered Systems

Version 23.9.0.25.08から切断されました

azure % 


SALESADBへの接続をやり直し、同じ検索を実行します。

MANANGER_IDが103の従業員については、列SALARYの値が表示されています。

azure % sql /@salesadb_azcode 



SQLcl: 水 8月 20 12:46:47 2025のリリース25.2 Production


Copyright (c) 1982, 2025, Oracle.  All rights reserved.


To sign in, use a web browser to open the page https://microsoft.com/devicelogin and enter the code NQRSUWAXP to authenticate.


PL/SQLプロシージャが正常に完了しました。


接続先:

Oracle Database 23ai Enterprise Edition Release 23.0.0.0.0 - for Oracle Cloud and Engineered Systems

Version 23.9.0.25.08


SQL> select employee_id, first_name, last_name, email, salary, commission_pct, manager_id, department_id from hr.employees;


   EMPLOYEE_ID FIRST_NAME    LAST_NAME    EMAIL           SALARY    COMMISSION_PCT    MANAGER_ID    DEPARTMENT_ID 

______________ _____________ ____________ ____________ _________ _________________ _____________ ________________ 

           103 Alexander     James        AJAMES                                             102               60 

           104 Bruce         Miller       BMILLER           6000                             103               60 

           105 David         Williams     DWILLIAMS         4800                             103               60 

           106 Valli         Jackson      VJACKSON          4800                             103               60 

           107 Diana         Nguyen       DNGUYEN           4200                             103               60 


SQL> exit

Oracle Database 23ai Enterprise Edition Release 23.0.0.0.0 - for Oracle Cloud and Engineered Systems

Version 23.9.0.25.08から切断されました

azure % 


SQLclのMCPサーバーはデータベースに接続する際にlogin.sqlは参照しません。そのため、Real Application Securityを有効にするには、プロンプトでrasadmin.emp_dept_ctx_pkg.initの実行を指示する必要があります。

Claude Desktopで確認しました。

Real Application Securityのポリシーを有効にするために、rasadmin.emp_dept_ctx_pkg.initを実行してください。


Real Application Securityを認識していて、かなり驚きました。

ローコード開発ツールのOracle APEXの用途のひとつにOpportunistic Applicationというのがあります。日本語でいうと「一時的・補助的・小規模な業務ニーズにすぐ対応するためのアプリケーション」となりますが、Opportunistic Applicationの用途であれば、データベースに問い合わせるLLMアプリケーションで代替されるように思います。

今回の記事は以上になります。


設定の削除



以下のスクリプトで作成したセキュリティ・クラス、ACL、ポリシー、ネームスペース、動的ロールなどを削除できます。ユーザーRASADMINで実行します。


この他にユーザーRASADMINとRASADMINが所有しているオブジェクトの削除(cascadeオプションをつける)やユーザーMCPUSERに与えた権限の削除を行ないます。ユーザーADMINで実行します。
drop user rasadmin cascade;
drop role hr_role;
begin
    sys.xs_admin_cloud_util.revoke_system_privilege('ADMINISTER_SESSION','MCPUSER');
end;
/