Amazon Aurora PostgreSQLの動的データマスキング登場:今こそ整理するRLSとCLSの違い

記事タイトルとURLをコピーする

こんにちは。
アプリケーションサービス、DevOps担当の兼安です。

AWS re:Invent 2025でAmazon Aurora PostgreSQL(以降、Aurora PostgreSQLと書きます)の動的データマスキングが発表されました。
今回はこれを機会に、行レベルセキュリティ(Row-Level Security, RLS)とカラム(列)レベルセキュリティ(Column-Level Security, CLS)の違いについて整理してみたいと思います。

本記事のターゲット

本記事は、データベースのユーザー・ロール・スキーマ設計・テーブル設計に関することを書いています。
解説を織り交ぜながら書いていますが、単純なSQLクエリだけの話にはとどまらないので、Amazon Aurora PostgreSQLの基礎知識と、ある程度データベース設計の経験がある方をターゲットにしています。

動的データマスキングとデータベースのユーザーとロール

Aurora PostgreSQLの動的データマスキングは、Aurora PostgreSQLのロールに基づいて、特定のカラムのデータをマスキングすることができる機能です。

aws.amazon.com

ビューを使ったマスキングの難点

特定のカラムのデータマスキングは、ビューを使って実現することも可能ですが、権限の種類が増えるとビューが増えてしまい、管理が煩雑になるというデメリットがあります。
また、実テーブルへの権限制御を正しく設定しないと、ビューを飛び越して情報を参照されるというリスクもあります。

flowchart TB
    subgraph users[ユーザー]
        U1[一般ユーザー]
        U2[マネージャー]
        U3[監査担当]
    end

    subgraph database[データベース]
        Table[(実テーブル<br/>customer_info<br/>全データ)]
        View1[一般ユーザー向けビュー]
        View2[マネージャー向けビュー]
        View3[監査担当向けビュー]
    end

    View1 -.->|マスキングあり| Table
    View2 -.->|そのまま表示| Table
    View3 -.->|一部マスキングあり| Table    
    
    U1 -.-> View1
    U2 -.-> View2
    U3 -.-> View3
    
    style Table fill:#e1f5ff
    style View1 fill:#fff4e6
    style View2 fill:#fff4e6
    style View3 fill:#fff4e6

動的データマスキングのメリット

これに対して動的データマスキングは、テーブルに直接マスキングルールを設定できるため、管理が容易になるというメリットがあります。

flowchart TB
    subgraph users[ユーザー]
        U1[一般ユーザー<br/>ロール: general]
        U2[マネージャー<br/>ロール: manager]
        U3[監査担当<br/>ロール: auditor]
    end
    
    subgraph database[データベース層]
        DB[(実テーブル<br/>customer_info<br/>CLS有効化済)]
    end
    
    U1 -.->|マスキングあり| DB
    U2 -.->|そのまま表示| DB
    U3 -.->|マスキングあり| DB
    
    style DB fill:#e1f5ff
    style U1 fill:#fff4e6
    style U2 fill:#ffe6e6
    style U3 fill:#fff4e6

動的データマスキングにおけるロールとは

さて、この動的データマスキング機能ですが、ロールというのはPostgreSQLのデータベースにおけるロールです。
AWSのIAMロールではないので注意が必要です。

PostgreSQLというより、リレーショナルデータベース全般に言えることですが、データベースにはユーザーとロールという概念があります。
データベースのユーザーとロールの関係は、AWS IAMユーザーとIAMロールの関係に似ていますが、混同しないように気をつけてください。

行レベルセキュリティとカラムレベルセキュリティ

Aurora PostgreSQLの動的データマスキングは、カラム(列)レベルセキュリティ(Column-Level Security, CLS)の一種です。
これと似た概念に、行レベルセキュリティ(Row-Level Security, RLS)があります。

以下の表のような顧客情報テーブルがあるとします。
この顧客情報テーブルはマルチテナントであり、tenant_idカラムでテナントを区別しています。

tenant_id customer_id name email credit_card_number registration_date last_login_date status
1 1001 ○○○ user1001@example.com AAAA-BBBB-CCCC-DDDD 2024-01-15 2024-12-05 active
2 2001 △△△ user2001@example.com EEEE-FFFF-GGGG-HHHH 2024-02-20 2024-12-04 active
1 1002 □□□ user1002@example.com IIII-JJJJ-KKKK-LLLL 2024-03-10 2024-11-30 active
3 3001 ◇◇◇ user3001@example.com MMMM-NNNN-OOOO-PPPP 2024-04-05 2024-12-03 active
1 1003 ◎◎◎ user1003@example.com QQQQ-RRRR-SSSS-TTTT 2024-05-12 2024-12-01 inactive
2 2002 ●●● user2002@example.com UUUU-VVVV-WWWW-XXXX 2024-06-18 2024-11-28 active
3 3002 ▲▲▲ user3002@example.com YYYY-ZZZZ-AAAA-BBBB 2024-07-22 2024-12-02 active
1 1004 ■■■ user1004@example.com CCCC-DDDD-EEEE-FFFF 2024-08-30 2024-12-06 active

このテーブルにおいて、行レベルセキュリティとカラムレベルセキュリティの違いは以下の通りです。

セキュリティの種類 説明
行レベルセキュリティ (RLS) 特定の行(レコード)へのアクセスを制御する。 テナントAのユーザーは、tenant_idが1の行のみアクセス可能。
テナントBのユーザーは、tenant_idが2の行のみアクセス可能。
カラムレベルセキュリティ (CLS) 特定のカラム(列)へのアクセスを制御する。 一般ユーザーは、emailとcredit_card_numberのデータをマスキングして表示。
マネージャーユーザーは、そのまま表示可能。

行レベルセキュリティとカラムレベルセキュリティの用途

行レベルセキュリティとカラムレベルセキュリティは、用途が異なります。
行レベルセキュリティは、例えばマルチテナント環境において、テナントごとにデータの分離を行うのに適しています。
以下のように、コンピューティングは各テナントごとに分かれているが、データベースは共通である場合に、他のテナントのデータにアクセスできないようにするのに役立ちます。

flowchart TB
    subgraph clients[クライアント]
        T1[テナント A]
        T2[テナント B]
        T3[テナント C]
    end
    
    subgraph compute[コンピューティング層]
        C1[アプリケーション A<br/>tenant_id=1]
        C2[アプリケーション B<br/>tenant_id=2]
        C3[アプリケーション C<br/>tenant_id=3]
    end
    
    subgraph database[データベース層]
        DB[(実テーブル<br/>customer_info<br/>RLS有効化済)]
    end
    
    T1 --> C1
    T2 --> C2
    T3 --> C3
    
    C1 -.->|tenant_id=1の行のみ<br/>アクセス可能| DB
    C2 -.->|tenant_id=2の行のみ<br/>アクセス可能| DB
    C3 -.->|tenant_id=3の行のみ<br/>アクセス可能| DB
    
    style DB fill:#e1f5ff
    style C1 fill:#fff4e6
    style C2 fill:#fff4e6
    style C3 fill:#fff4e6

カラムレベルセキュリティは、異なる権限を持つユーザーが存在する場合に、特定のカラムのデータを保護するのに適しています。
以下のように、一般ユーザーと管理者が同じデータベースにアクセスする場合に、ロールに応じて見えるデータを制御するのに役立ちます。
従って、どちらかというとセキュリティを強化するのに役立ちます。
(以下の図では、意図的にコンピューティング層を省略しています。 コンピューティング層ありの例は次回以降に書きます。 )

flowchart TB
    subgraph users[ユーザー]
        U1[一般ユーザー<br/>ロール: general]
        U2[マネージャー<br/>ロール: manager]
        U3[監査担当<br/>ロール: auditor]
    end
    
    subgraph database[データベース層]
        DB[(実テーブル<br/>customer_info<br/>CLS有効化済)]
    end
    
    U1 -.->|マスキングあり| DB
    U2 -.->|そのまま表示| DB
    U3 -.->|マスキングあり| DB
    
    style DB fill:#e1f5ff
    style U1 fill:#fff4e6
    style U2 fill:#ffe6e6
    style U3 fill:#fff4e6

Aurora PostgreSQLの動的データマスキングを試してみる

以上を踏まえて、Aurora PostgreSQLの動的データマスキングを動かしてどのように動作するか試してみたいと思います。
手順は以下のAWSの公式ブログ記事を参考にします。

aws.amazon.com

1. DBクラスターの作成

Aurora PostgreSQL(バージョン16.10以上または17.6以上)のDBクラスターを作成します。

2. PostgreSQLのロールとユーザーの作成

次に、SQLでPostgreSQLのロールとユーザーを作成します。
ここから出てくるrds_superuser権限を持つユーザーは、Aurora PostgreSQLクラスター作成時に指定したマスターユーザーを指定すれば大丈夫です。

-- rds_superuser権限を持つユーザーで接続
psql -h <Aurora PostgreSQLのエンドポイント> -U <マスターユーザー名>

-- ロールの作成
CREATE ROLE general_role NOLOGIN;
CREATE ROLE manager_role NOLOGIN;

-- 一般ユーザーの作成
CREATE ROLE general_user LOGIN PASSWORD '<任意のパスワード>';
GRANT general_role TO general_user;

-- 管理者ユーザーの作成
CREATE ROLE manager_user LOGIN PASSWORD '<任意のパスワード>';
GRANT manager_role TO manager_user;

3. スキーマ権限の付与

そのままrds_superuser権限を持つユーザーでデータベースを作成し、各ロールにスキーマ権限を付与します。

-- データベースの作成
CREATE DATABASE customer_db;

-- データベースに接続
\c customer_db

-- スキーマ権限の付与
GRANT USAGE ON SCHEMA public TO general_role;
GRANT USAGE ON SCHEMA public TO manager_role;

4. テーブル作成とデータ投入

テーブルを作成。
テーブル作成後、データを投入します。

-- 顧客情報テーブルの作成
CREATE TABLE customer_info (
    tenant_id INTEGER NOT NULL,
    customer_id INTEGER NOT NULL,
    name TEXT NOT NULL,
    email TEXT NOT NULL,
    credit_card_number TEXT NOT NULL,
    registration_date DATE NOT NULL,
    last_login_date DATE NOT NULL,
    status TEXT NOT NULL,
    PRIMARY KEY (tenant_id, customer_id)
);

-- 一般ロールと管理者ロールにテーブルのSELECT権限を付与
GRANT SELECT ON TABLE public.customer_info TO general_role;
GRANT SELECT ON TABLE public.customer_info TO manager_role;

-- サンプルデータの投入
INSERT INTO customer_info (tenant_id, customer_id, name, email, credit_card_number, registration_date, last_login_date, status) VALUES
(1, 1001, '○○○', 'user1001@example.com', 'AAAA-BBBB-CCCC-DDDD', '2024-01-15', '2024-12-05', 'active'),
(2, 2001, '△△△', 'user2001@example.com', 'EEEE-FFFF-GGGG-HHHH', '2024-02-20', '2024-12-04', 'active'),
(1, 1002, '□□□', 'user1002@example.com', 'IIII-JJJJ-KKKK-LLLL', '2024-03-10', '2024-11-30', 'active'),
(3, 3001, '◇◇◇', 'user3001@example.com', 'MMMM-NNNN-OOOO-PPPP', '2024-04-05', '2024-12-03', 'active'),
(1, 1003, '◎◎◎', 'user1003@example.com', 'QQQQ-RRRR-SSSS-TTTT', '2024-05-12', '2024-12-01', 'inactive'),
(2, 2002, '●●●', 'user2002@example.com', 'UUUU-VVVV-WWWW-XXXX', '2024-06-18', '2024-11-28', 'active'),
(3, 3002, '▲▲▲', 'user3002@example.com', 'YYYY-ZZZZ-AAAA-BBBB', '2024-07-22', '2024-12-02', 'active'),
(1, 1004, '■■■', 'user1004@example.com', 'CCCC-DDDD-EEEE-FFFF', '2024-08-30', '2024-12-06', 'active');

5. pg_columnmaskの有効化

pg_columnmask拡張機能を有効化します。
ここはrds_superuser権限を持つユーザーで接続が必須です。

-- rds_superuser権限を持つユーザーで接続
psql -h <Aurora PostgreSQLのエンドポイント> -U <マスターユーザー名> -d customer_db

-- pg_columnmask拡張機能の有効化
CREATE EXTENSION pg_columnmask;

6. マスキング設定の適用

そのままrds_superuser権限を持つユーザーでpg_columnmaskの機能を使って、特定のカラムにマスキングルールを設定します。
今回は、一般ユーザー(general_roleロール)に対してemailカラムとcredit_card_numberカラムのマスキングを設定します。

-- 一般ユーザー向けのマスキングポリシー作成
CALL pgcolumnmask.create_masking_policy(
    'mask_sensitive_data_for_general',
    'public.customer_info',
    JSON_BUILD_OBJECT(
        'email', 'pgcolumnmask.mask_email(email)',
        'credit_card_number', 'pgcolumnmask.mask_text(credit_card_number)'
    )::JSONB,
    ARRAY['general_role'],
    50
);

以上で設定は完了です。

7. 動作確認

管理者ユーザーと一般ユーザーでログインし、顧客情報テーブルを参照してみます。
まずは、管理者ユーザーでクエリ。

-- manager_userで接続
psql -h <Aurora PostgreSQLのエンドポイント> -U manager_user -d customer_db

-- 顧客情報テーブルを参照
SELECT * FROM customer_info LIMIT 3;
customer_db=> SELECT * FROM customer_info LIMIT 3;
 tenant_id | customer_id | name |        email         | credit_card_number  | registration_date | last_login_date | status 
-----------+-------------+------+----------------------+---------------------+-------------------+-----------------+--------
         1 |        1001 | ○○○  | user1001@example.com | AAAA-BBBB-CCCC-DDDD | 2024-01-15        | 2024-12-05      | active
         2 |        2001 | △△△  | user2001@example.com | EEEE-FFFF-GGGG-HHHH | 2024-02-20        | 2024-12-04      | active
         1 |        1002 | □□□  | user1002@example.com | IIII-JJJJ-KKKK-LLLL | 2024-03-10        | 2024-11-30      | active
(3 rows)

次に、一般ユーザーでクエリ。

-- general_userで接続
psql -h <Aurora PostgreSQLのエンドポイント> -U general_user -d customer_db

-- 顧客情報テーブルを参照
SELECT * FROM customer_info LIMIT 3;
customer_db=> SELECT * FROM customer_info LIMIT 3;
 tenant_id | customer_id | name |        email         | credit_card_number  | registration_date | last_login_date | status 
-----------+-------------+------+----------------------+---------------------+-------------------+-----------------+--------
         1 |        1001 | ○○○  | XXXXXXXX@XXXXXXX.com | XXXXXXXXXXXXXXXXXXX | 2024-01-15        | 2024-12-05      | active
         2 |        2001 | △△△  | XXXXXXXX@XXXXXXX.com | XXXXXXXXXXXXXXXXXXX | 2024-02-20        | 2024-12-04      | active
         1 |        1002 | □□□  | XXXXXXXX@XXXXXXX.com | XXXXXXXXXXXXXXXXXXX | 2024-03-10        | 2024-11-30      | active
(3 rows)

適切にマスキングされていることが確認できました。
このようにカラムレベルセキュリティである動的データマスキングを使うことで、異なる権限を持つユーザーに対して、特定のカラムのデータを保護することができます。
これにより、セキュリティの強化やコンプライアンス要件の遵守に役立ちます。

次回予告

今回は、行レベルセキュリティとカラムレベルセキュリティの違いと用途について考えてみました。
次回はこの動的データマスキングとコンピューティング層を組み合わせたアーキテクチャについて記事を書きます。

補足

実はAurora PostgreSQLの動的データマスキングを試してみるセクションの4.のテーブル作成とデータ投入、および6.のマスキングポリシーの設定は、rds_superuser権限を持つユーザーで実行する必要はありません。
データベース作成時にデータベースの所有者となるユーザーを作成すれば、そのユーザーで実行可能です。
今回は、手順を簡単にするためにrds_superuser権限を持つユーザーで実行しました。

2.のユーザーとロールの作成手順と、5.pg_columnmask拡張機能の有効化は、明確にrds_superuser権限を持つユーザーで実行する必要があります。

兼安 聡(執筆記事の一覧)

アプリケーションサービス部 DS3課所属
2025 Japan AWS Top Engineers (AI/ML Data Engineer)
2025 Japan AWS All Certifications Engineers
2025 AWS Community Builders
Certified ScrumMaster
PMP
広島在住です。今日も明日も修行中です。
X(旧Twitter)