※ 本記事は2017年1月26日に公開されたものです。

最小権限の原則を実現するためには、全てのユーザーの表にアクセス可能になるSELECT ANY TABLE権限などのANYシステム権限の付与に注意が必要なこは何回か紹介してきました。

しかし、特定のデータベーススキーマのデータを管理するために、スキーマ内の全ての表に対して権限を与えたいこともあります。それが複数のスキーマだったり、アプリ改修で表が増えたりすると、権限の付与が大変で、結局利便性のためにSELECT ANY TABLE権限を利用してしまうケースもあるかもしれません。

では、大量の表に対して一度に権限を付与することはできないでしょうか?
方法のひとつとして以下のようなPL/SQLプログラムの利用が考えられます。
ここでは、PUKUというスキーマの全ての表のSELECT権限をPUKU_ROというロールに付与するSQL文を自動生成する例です。
(注:このSQL/SQLプログラムはデータベース管理者で実行することを想定しています。行が画面からはみ出してしまっている場合にはお手数ですが、テキストエディタなどにコピペしてください。)

set serveroutput on
declare
  objectOwner varchar2(64) := 'PUKU';
  grantee varchar2(64) := 'PUKU_RO';
begin
  for cur in ( select table_name from dba_tables where owner=objectOwner ) loop
    dbms_output.put_line('grant select on ' || objectOwner || '.' || cur.table_name || ' to ' || grantee || ';');
  end loop;
end;
/

実行すると以下のGRANT文が生成されます。

SQL> set serveroutput on
SQL> declare
  2    objectOwner varchar2(64) := 'PUKU';
  3    grantee varchar2(64) := 'PUKU_RO';
  4  begin
  5    for cur in ( select table_name from dba_tables where owner=objectOwner ) loop
  6      dbms_output.put_line('grant select on ' || objectOwner || '.' || cur.table_name || ' to ' || grantee || ';');
  7    end loop;
  8  end;
  9  /
grant select on PUKU.TEST to PUKU_RO;
grant select on PUKU.CUSTOMER to PUKU_RO;
grant select on PUKU.ORDER to PUKU_RO;
grant select on PUKU.M_BOM to PUKU_RO;
grant select on PUKU.M_ZIPCODE to PUKU_RO;
grant select on PUKU.M_COMPANYCODE to PUKU_RO;
PL/SQLプロシージャが正常に完了しました。 

さらにEXECUTE IMMEDIATE文を利用すると、一気にGRANT文の実行までおこなうこともできます。

declare
  objectOwner varchar2(64) := 'PUKU';
  grantee varchar2(64) := 'PUKU_RO';
begin
  for cur in ( select table_name from dba_tables where owner=objectOwner ) loop
    execute immediate 'grant select on ' || objectOwner || '.' || cur.table_name || ' to ' || grantee;
  end loop;
end;
/ 

既に権限が付与されている表に対して再度同じ権限を付与するGRANT文を発行しても、SQL文は正常に終了しますので、このPL/SQLプログラムは何度でも実行することができます。対象スキーマの表構成を変更した後にこのPL/SQLプログラムを実行すれば、簡単に権限付与することができます。

このPL/SQLプログラムは、DBA_TABLESデータディクショナリビューにアクセスしていますので、データベース管理者で実行する必要があります。DBA_TABLESデータディクショナリビューでは、すべてのスキーマの表の情報がリストされますので、検索条件を「OWNER = ‘スキーマ名’」から「OWNER IN (‘スキーマ1’, ‘スキーマ2’)]というように変更することで複数スキーマの全ての表へのオブジェクト権限を一度に付与することもできます。また、DBA_TABLESデータディクショナリビューの代わりに、USER_TABLESデータディクショナリビューを利用すれば、データベース管理者ではなくオブジェクトの所有者アカウントを利用してPL/SQLプログラムを実行できます。

さらに検索条件に「TABLE_NAME LIKE ‘M\_%’」(表名が「M_」から開始する)という条件を追加することで、スキーマ内の特定の表(今回はマスター表)のみの権限を付与するように書き換えることもできます。

set serveroutput on
declare
  grantee varchar2(64) := 'PUKU_RO';
begin
  for cur in ( select table_name from user_tables where table_name like 'M\_%' ) loop
    dbms_output.put_line('grant select on ' || cur.table_name || ' to ' || grantee || ';');
  end loop;
end;
/

 実行結果は以下の通りです。

SQL> show user
ユーザーは"PUKU"です。
SQL> set serveroutput on
SQL> declare
  2    grantee varchar2(64) := 'PUKU_RO';
  3  begin
  4    for cur in ( select table_name from user_tables where table_name like 'M\_%' ) loop
  5      dbms_output.put_line('grant select on ' || cur.table_name || ' to ' || grantee || ';');
  6    end loop;
  7  end;
  8  /
grant select on M_BOM to PUKU_RO;
grant select on M_ZIPCODE to PUKU_RO;
grant select on M_COMPANYCODE to PUKU_RO;
PL/SQLプロシージャが正常に完了しました。 

表の名前付けを規則性を持ったルール化していると、このように権限付与でも管理性が向上します。
また、どのユーザーやロールにどの権限が付与されているかのリストを確認するときにも、不要な権限が付与されているのに気付きやすくなります。

今回は強力なANYシステム権限を利用せずに必要な表へのアクセス権限をまとめたロールを簡単に作成する方法を紹介しました。もちろん今回紹介したものだけで、必ずしもANYシステム権限を使わないですむようになるわけではありませんが、いろいろ工夫をして最小権限の原則の実現を実現させてください。

「もくじ」にもどる