MySQL 9.7.0 の新しい LTSリリースでは、Enterprise Edition の新機能の一つとして 動的データマスキング(DDM: Dynamic Data Masking) が追加されました。

MySQL Product Management Director のMike Frankによる最近のブログでは、個人識別情報(PII: Personal Identifiable Information)を扱うあらゆる業界において、DDM がなぜ重要なのかが紹介されています。

Mike の記事では DDM の概要が説明されています。本記事では、MySQL Enterprise Edition 9.7 における動的データマスキング機能のインストール方法、有効化、実際の利用方法 を紹介します。

MySQLにおける動的データマスキングの仕組み

概要:

マスキングは、マスク対象の列を読み取るクエリが実行された時に適用されます。一方で、それらの列への書き込み処理には影響を与えません。この機能は object_policy コンポーネントに依存しており、マスキングポリシー定義を保存・取得します。

クエリ処理中に、マスク対象列への参照は、ポリシーで定義された CASE 式に自動的に置き換えられます。返却される値は、現在のユーザーまたは有効なロールに基づいて決定されます。

セットアップとインストール:

前述のとおり、動的データマスキング は Enterprise Editionの object_policy コンポーネントに依存しています。このコンポーネントは mysql スキーマ内にマスキングポリシーを保存し、ポリシーの作成、管理、取得機能を担っています。

以下の実行例で使用する環境は、 Oracle Linux Server 9.7 上にMySQL Enterprise Edition 9.7.0 の RPM パッケージをデフォルト設定でインストールしています。

Step 1

MySQL パッケージに含まれるインストールスクリプトを実行します。このスクリプトにより、mysql スキーマ内に必要なテーブルが作成され、component_object_policy コンポーネントがインストールされます。

RPM インストールでは通常 /usr/share/mysql-9.7/install_component_object_policy.sql に配置されています。

ファイルの内容は以下のコマンドで確認できます:

cat /usr/share/mysql-9.7/install_component_object_policy.sql

.sql ファイルを実行するには、以下のコマンドを実行します:

mysql -uroot -p < /usr/share/mysql-9.7/install_component_object_policy.sql

MySQL プロンプトから SOURCE コマンドで実行することもできます:

SOURCE install_component_object_policy.sql;

このスクリプトは、ポリシーテーブルを作成し、コンポーネントをインストールします。コンポーネントによって管理されるテーブルは、MySQL 内部で利用するデータベースの一つである mysql 内に column_masking_policies という名前で作成されます。このテーブルの構成は、MySQL にログインして次のコマンドを実行することで確認できます。

use mysql;
show tables like 'column_masking%';

このテーブルの詳細は show create table column_masking_policies\G でも確認できます。

カラム名役割
policy_nameCREATE、DROP、SHOW、およびカラム割り当てで使用される一意のポリシー識別子
expressionUTF-8 MB4 で保存されるポリシー式
argumentカラムのプレースホルダーとして使用されるポリシーパラメータ名
extra_info将来のメタデータ拡張用に予約された JSON フィールド
schema_versionアップグレード処理で使用されるコンポーネントテーブルの形式/バージョンマーカー

Step 2

マスキングコンポーネントをインストールします。マスキング関数 は MySQL Enterprise Edition で提供されている機能です。このマスキング関数を用いてデータをマスクするため、動的データマスキングを利用するには、MySQL プロンプトでマスキングコンポーネントをインストールする必要があります。

INSTALL COMPONENT 'file://component_masking’;
INSTALL COMPONENT 'file://component_masking_functions’;

インストールされたことを確認します。

SELECT * FROM mysql.component;

ID 9 と 10 のコンポーネントが、前の2つのステップでインストールされたものです。

コンポーネントID 1の component_validate_password はデフォルトでインストールされています。

Step 3

次にサンプルデータを作成します:

CREATE SCHEMA IF NOT EXISTS demo_ddm;
USE demo_ddm;
DROP TABLE IF EXISTS employee_details;

CREATE TABLE employee_details (
 emp_id INT PRIMARY KEY,
 first_name VARCHAR(32),
 last_name VARCHAR(32),
 ssn VARCHAR(16),
 doj datetime,
 zip_code VARCHAR(10));
INSERT INTO employee_details VALUES
  (1,'James','Smith','900-01-0001','2026-02-04','10001'),
  (2,'Mary','Johnson','900-01-0002','2025-04-07','90210'),
  (3,'Robert','Williams','900-01-0003','2023-05-07','60601'),
  (4,'Patricia','Brown','900-01-0004','2012-05-03','30301');

Step 4

DDM の動作確認のため、MySQL ユーザーとロールを作成します。

実データを参照できる admin ユーザーを作成します。

CREATE USER IF NOT EXISTS 'admin'@'%' IDENTIFIED BY 'Welcome1!';

マスク済みデータのみを参照できる dba_l1 ユーザーを作成します。

CREATE USER IF NOT EXISTS 'dba_l1'@'%' IDENTIFIED BY 'Welcome1!';

両者にSELECT 権限を付与します。

GRANT SELECT ON demo_ddm.employee_details TO 'admin'@'%';
GRANT SELECT ON demo_ddm.employee_details TO 'dba_l1'@'%';

さらにpii_read ロールを作成し、アクセス権を付与します。

CREATE ROLE IF NOT EXISTS 'pii_read'@'%';
GRANT SELECT ON demo_ddm.employee_details TO 'pii_read'@'%';

このロールを admin ユーザーに割り当てます。

GRANT 'pii_read'@'%' TO 'admin'@'%';

Step 5

マスキングポリシーを作成操作に移る前に、マスキングポリシーとは何か、どのように作成するかを確認しましょう。

マスキングポリシーは、ユーザーレベルでも ロールレベルでも作成できます。実行例では ユーザーレベルで作成し、ロール レベルでの作成は後ほど説明します。

ユーザーレベルで マスキングポリシー を作成する DDL 構文は次のとおりです:

CREATE MASKING POLICY IF NOT EXISTS <policy_name>(<policy_param>)
CASE WHEN CURRENT_USER_IN('<role_list/user_list>')
THEN <policy_param>
ELSE <masking_expression_using_policy_param>
END;
要素説明
policy_name再利用可能なポリシー名。空文字、末尾スペースはサポートしておらず、64文字を超えてはいけません。名前の照合は utf8mb3_general_ci のもとで大文字小文字を区別しません。SHOW CREATE MASKING POLICY は元の大文字小文字を保持します。
policy_param対象列の値を表す単一のパラメータ。有効な識別子であり、空文字、末尾スペースはサポートしておらず、64文字を超えてはいけません。大文字小文字を区別しません。
CURRENT_ROLE_IN(…)有効なロールのいずれかが認可リストに一致する場合に true を返すゲートキーパーです。
CURRENT_USER_IN(…)現在のユーザーが認可リストに一致する場合に true を返すゲートキーパーです。
role_list / user_listカンマ区切りの認可 ID です。CREATE MASKING POLICY では、引数は文字列リテラルである必要があります。
THEN / ELSE一方の分岐は元のパラメータを直接返し、もう一方の分岐はマスクされた値を返す必要があります。
IF NOT EXISTS大文字小文字を区別しない一致ポリシーがすでに存在する場合、作成は成功しますが効果はなく、警告が出力されます。既存の定義は保持されます。

マスキングポリシーのサンプルを作成します。

CREATE MASKING POLICY mask_ssn_policy(ssn_col)
CASE WHEN CURRENT_USER_IN('admin')
  THEN ssn_col
  ELSE mask_ssn(ssn_col)
END;

ここでは、mask_ssn_policy というポリシーを定義しています。admin ユーザーがログインした場合は実際の 社会保障番号(SSN: Social Security Number) が表示され、それ以外のユーザーでは 社会保障番号がマスクされた状態で表示されます。

このポリシーを demo_ddm.employee_details テーブルに関連付けます。

ALTER TABLE demo_ddm.employee_details
ALTER COLUMN ssn
SET MASKING POLICY mask_ssn_policy;

ここでは、employee_details テーブルの ssn カラムに、マスキングポリシー mask_ssn_policy を関連付けています。

ログインしているユーザーが admin の場合:

SELECT emp_id, first_name, last_name, ssn, doj, zip_code
FROM demo_ddm.employee_details
ORDER BY emp_id;

ログインしているユーザーが root または dba_l1 の場合:

SELECT emp_id, first_name, last_name, ssn, doj, zip_code
FROM demo_ddm.employee_details
ORDER BY emp_id;

次に、名前カラム用の別のポリシーを作成します。

CREATE MASKING POLICY mask_name_policy(name_col)
CASE WHEN CURRENT_USER_IN('admin')
  THEN name_col
  ELSE mask_outer(name_col, 1,1)
END;

ユーザーが admin の場合、名前はそのまま表示されます。それ以外の場合は、先頭・末尾文字が X に置き換えられます。

ポリシーをテーブルと対象カラムに関連付けます。

ALTER TABLE demo_ddm.employee_details
ALTER COLUMN first_name SET MASKING POLICY mask_name_policy,
ALTER COLUMN last_name SET MASKING POLICY mask_name_policy;

admin ユーザーでログインします。

SELECT emp_id, first_name, last_name, ssn, doj, zip_code
FROM demo_ddm.employee_details
ORDER BY emp_id;

root ユーザーでログインします。

SELECT emp_id, first_name, last_name, ssn, doj, zip_code
FROM demo_ddm.employee_details
ORDER BY emp_id;

次に dba_l1 ユーザーで確認します。

SELECT emp_id, first_name, last_name, ssn, doj, zip_code
FROM demo_ddm.employee_details
ORDER BY emp_id;

rootユーザでログインし、employee_details テーブルから SSN のマスキングを解除します。

ALTER TABLE demo_ddm.employee_details MODIFY COLUMN ssn varchar(16) NOT NULL;

pii_read ロールへのポリシーを作成します。

CREATE MASKING POLICY mask_name_forRole(name_col)
CASE WHEN CURRENT_ROLE_IN('pii_read')
  THEN name_col
  ELSE mask_outer(name_col, 1,1)
END;

ポリシーをテーブルに関連付けます。

ALTER TABLE demo_ddm.employee_details
ALTER COLUMN first_name
SET MASKING POLICY mask_name_forRole;

admin ユーザーは pii_read ロールに関連付けられてますが、まだ有効化されていません。この状態でadmin でログインして、何が表示されるかを確認します。

SELECT emp_id, first_name, last_name, ssn, doj, zip_code
FROM demo_ddm.employee_details
ORDER BY emp_id;

admin ユーザーでログインしていますが、有効化されていないため first_name 列にはマスクされたデータのみが表示されています。

admin ユーザーでROLE を有効化します。

SET ROLE pii_read;

次に 再度 SELECT 文を実行します。

SELECT emp_id, first_name, last_name, ssn, doj, zip_code
FROM demo_ddm.employee_details
ORDER BY emp_id;

ここでは、マスクされていないデータを確認できます。ロールに対して設定すると完全なデータを表示できますが、単にユーザーとして接続しているだけの場合は、マスクされたデータが表示されます。

マスキングコンポーネントのアンインストール

Linux マシンの同じフォルダ /usr/share/mysql-9.7/ にデフォルトで存在する uninstall_component_object_policy.sql スクリプトを実行します。

mysql -uroot -p -h localhost < /usr/share/mysql-9.7/uninstall_component_object_policy.sql

MySQL にログインし、demo_ddm.employee_details テーブルに対して SELECT を実行すると、エラーが発生することを確認します。

SELECT emp_id, first_name, last_name, ssn, doj, zip_code
FROM demo_ddm.employee_details
ORDER BY emp_id;

テーブルから マスキングポリシーを解除します。

ALTER TABLE demo_ddm.employee_details MODIFY COLUMN ssn varchar(16) NOT NULL;
ALTER TABLE demo_ddm.employee_details MODIFY COLUMN first_name VARCHAR(32);
ALTER TABLE demo_ddm.employee_details MODIFY COLUMN last_name VARCHAR(32);

次に SELECT 文を実行します。

SELECT emp_id, first_name, last_name, ssn, doj, zip_code
FROM demo_ddm.employee_details
ORDER BY emp_id;

MySQL にインストールされているコンポーネントを表示し、component_object_policy が削除されていることを確認します。(マスキングコンポーネントを削除する場合は別途アンインストールする必要があります)

select * from mysql.component;

まとめ

この機能はサーバー側で強制されるように設計されているため、MySQL に直接アクセスした場合でも、データの不適切な取り扱いを避けることができます。

クエリ時、かつサーバーレベルで適用されるため、DWH、CRM、AI、レポーティングなど、他の用途のためにデータを抽出する場合にも利用できます。

オリジナルのデータは MySQL 内に保持され、安全に保護されます。その一方で、他の用途にはマスク済みデータを抽出できます。

詳細情報 / OCI HeatWaveで試す