以下の内容はhttps://developer.feedforce.jp/entry/2026/03/26/104846より取得しました。


pg_columnmask を実際にプロダクトで利用してデータベースの閲覧権限を管理してみた

Omni Hub チームの shunten31 です.

はじめに

Omni Hub チームでは、チームメンバー全員が本番データベースの中身を Redash から参照できる環境を整えるにあたり、PII カラムをマスキングする仕組みが必要でした. 最終的に pg_columnmask のマスキングポリシーをアプリケーションの migration ファイルと一緒に管理する方針に落ち着きました. この記事では、当初試みた view を使ったアプローチの課題と、pg_columnmask を migration と組み合わせた実装方法を紹介します.

当初の試み

Omni Hub チームでは、Redash を通じてメンバー全員が本番データベースの中身が見られるようにするにあたり、個人情報に該当するカラム(以下 PII カラム) がマスキングされる仕組みを導入する必要がありました.

当初は、PostgreSQL の view を利用して、PII カラムをマスキングする view を作成し、Redash 用 PostgreSQL user に mask された view の権限だけ与えることで、解決しようとしていました.

すなわち、PII カラムである customer_id を持つ customers テーブルを例として取ると、customers_maskedという view を下記のように作成し、Redash 用 user から、 customers の閲覧権限を剥奪して customers_masked の権限を与える、 という方針です.

CREATE
OR REPLACE VIEW customers_masked AS
SELECT
    encode(
        digest(customer_id :: text, 'sha256'),
        'hex'
    ) AS customer_id,
    tenant_id
FROM
    customers;

しかし、これは下記の問題がありました.

  • 元テーブル customers のカラムを削除した場合、view の使用上、view を一度削除して再作成する必要がある.
  • 個人情報の閲覧権限のある別のユーザー権限で Redash を利用する際、 クエリが使い回せない (クエリ中の customers_maskedcustomers に書き換える必要がある)

pg_columnmask のことを知る

pg_columnmask については、 下記の記事で紹介しています.

developer.feedforce.jp

読まれていない方のために説明を引用すると、次のとおりです.

AWS Aurora PostgreSQL に対して 昨年末に導入された新機能で、 データベースの動的データマスキングを適用することができる拡張機能です. 特徴として、 下記のような点が挙げられます.

動的データマスキングのため、 マスクされた別の Table や View 等を作成する必要がない ユーザーごとにマスキングポリシーを変更できる 同一カラムに複数のマスキングポリシーを定義し、 重み (weight) を定義することで、 条件によって実際に適用されるマスクを決定できる

pg_columnmask を使えば、同一テーブルの読み取りに対して、ユーザーごとに事前に設定したマスキングポリシーが適用されます. また、マスキングポリシーは更新が可能であり、 view を利用したアプローチで問題になっていた2点が解消されます.

pg_columnmask の運用

マスキングポリシーの記述場所

このような経緯で pg_columnmask の導入を決めました。しかし、マスキングポリシーの維持についての方針は決まっていませんでした. 選択肢としては、以下が考えられました.

  1. 手動で、直接インスタンスでコマンドを叩いて設定
  2. 別のスクリプトや migration ファイルで管理
  3. アプリケーションの migration ファイルで一緒に管理

1 は、本番データベースに接続したうえでのオペレーションになるので、リスクが高いと判断しました. 2 も有効な手だてと考えましたが、前に公開したブログ で調査した通り、データベーススキーマの変更の前にマスキングポリシーの更新が必要なケースがあるので、スキーマの更新手順が複雑化する恐れがありました.

3 の方針であれば、本番データベースへの接続も不要で、データベースのスキーマ更新とマスキングポリシーの更新を同一の migration ファイルで実施できます. よって、マスキングポリシーはアプリケーションの migration ファイルで一緒に管理することにしました.

Aurora だけに対するマスキングポリシーの適用

今回利用する pg_columnmask は、AWS Aurora PostgreSQL においてのみ利用可能であり、ローカル開発環境として利用している PostgreSQL の Docker コンテナなどでは利用できません. よって、ローカル開発環境や、 将来別のデータベースを利用する場合は、 マスキングポリシーを更新するステートメントは migration 適用時に実行したくありません.

案1: aurora_version() による条件分岐

Aurora PostgreSQL には、 aurora_version() 関数が存在します. これを利用して、 下記のような IF 文を migration に記載して、マスキングポリシーの更新ステートメントを条件的に実施することができます.

DO $$
DECLARE
  v_is_aurora BOOLEAN := FALSE;
BEGIN
  -- aurora_version() が存在するかどうかで判別
  SELECT EXISTS (
    SELECT 1
    FROM pg_proc
    WHERE proname = 'aurora_version'
  ) INTO v_is_aurora;

  IF v_is_aurora THEN
    -- Aurora のときだけ実行するスキーマ変更
    ALTER TABLE your_table ADD COLUMN IF NOT EXISTS new_col TEXT;
    RAISE NOTICE 'Aurora detected. Schema change applied.';
  ELSE
    RAISE NOTICE 'Not Aurora. Skipped.';
  END IF;
END;
$$;

しかし、この方法の問題点として、下記のケースに対応できない点があります.

  • Aurora PostgreSQL であっても pg_columnmask を利用したくないケースがあるかもしれない
  • 将来 pg_columnmask が公開されて、Aurora でなくても 利用できるようになるかもしれない

採用した方法: pg_columnmask を利用するかどうかの独自関数を定義

上記の問題を解消するため、 pg_columnmask を利用するかどうかを明示的に指定できるようにする方針にしました.

migration ファイルを通じて、is_pg_columnmask_enabled() 関数を定義します. ここでは、デフォルト値を FALSE として定義します.

CREATE OR REPLACE FUNCTION is_pg_columnmask_enabled()
RETURNS BOOLEAN
LANGUAGE SQL
AS $$
  SELECT FALSE;
$$;

次に、pg_columnmask を利用したいデータベースに直接接続して、以下のステートメントを実行し、値を TRUE に書き換えます.

CREATE EXTENSION IF NOT EXISTS pg_columnmask;
CREATE OR REPLACE FUNCTION is_pg_columnmask_enabled()
RETURNS BOOLEAN
LANGUAGE SQL
AS $$
  SELECT TRUE;
$$;

その後は、マスキングポリシーの追加、更新を行う際には、下記の要領で記載します.

DO $$
BEGIN
  IF is_pg_columnmask_enabled() THEN
    EXECUTE $cm$
      CALL pgcolumnmask.create_masking_policy(
       ...  --- マスキングポリシーの更新を記載
      );
    $cm$;
  END IF;
END;
$$;

このように運用することで、 データベーススキーマの更新を行う migration と一緒にマスキングポリシーの更新を行うことができ、更新忘れを防ぐことができます. やはり、仕組みの導入時に一度データベースに直接アクセスする必要が生じてしまいますが、それ以降は migration と同じ安全なデプロイフローで適用できるため、運用が楽であると感じています.

終わりに

pg_columnmask を用いたデータマスキングを運用しはじめてしばらく経ちましたが、特に問題なく開発できています. この運用方法が少しでも参考になれば幸いです.




以上の内容はhttps://developer.feedforce.jp/entry/2026/03/26/104846より取得しました。
このページはhttp://font.textar.tv/のウェブフォントを使用してます

不具合報告/要望等はこちらへお願いします。
モバイルやる夫Viewer Ver0.14