「同じ1つのテーブルを、経理には全部見せ、営業には給与を伏字にして自部門の行だけ、社外パートナーには最小限だけ」——データ基盤の現場でほぼ必ず出てくる要件です。テーブルを分割してビューを量産する運用はすぐ破綻します。Snowflakeはこれを、列レベルの Dynamic Data Masking と行レベルの Row Access Policy という宣言的なポリシーで解きます。実データは1つのまま、クエリ時に見る人のロールへ合わせて結果が変わる。本記事では両者の仕組み、タグベースでの自動適用、AWS側との連携、そしてEMWが検証段階で先に踏み抜いて本番では防いだ落とし穴までを、現場目線で整理します。
01なぜ「役割で見せ分ける」のか
Snowflakeのアクセス制御はロール(RBAC)でテーブルやビュー単位に権限を配るのが基本です。しかし実務では「同じ売上テーブルを、経理は全列・全行、営業は自部門の行だけでメールと給与は伏字」といった、列単位・行単位の細かい制御が求められます。要件ごとにテーブルを複製したり限定ビューを量産したりする運用は、列が増えるたびに漏れが生まれ破綻します。Snowflakeは、これを2つの宣言的なポリシーで解決します。列レベルの Dynamic Data Masking と、行レベルの Row Access Policy です。どちらもクエリ実行時に評価されるため、保存されている実データは1セットのまま、参照する人のロールや条件に応じて返る結果だけが変わります。なお列レベル/行レベルのセキュリティは Enterprise Edition 以上の機能です。
02Dynamic Data Masking:列を守る
マスキングポリシーはスキーマレベルのオブジェクトです。CREATE MASKING POLICY で「入力する列の型」と「条件に応じて返す値」を定義し、ALTER TABLE … MODIFY COLUMN … SET MASKING POLICY で対象列に適用します。クエリ実行時、その列が現れるすべての場所でポリシーが評価され、ロールや条件に応じて平文・部分マスク・完全マスクのいずれかが返ります。ポイントは再利用性です。ポリシーを一度書けば数千の列に使い回せ、マスクの中身を変えても列への再適用は不要です。条件分岐には CURRENT_ROLE や IS_ROLE_IN_SESSION などのコンテキスト関数を使い、たとえば「特定ロールなら平文、それ以外は伏字」を1行の CASE 式で表現できます。条件付きマスキングでは、別の列(例:同意フラグ)の値を見て開示可否を切り替えることもできます。
CURRENT_ROLE はセッションで有効なプライマリロール1つだけを見ます。ロール階層で継承した権限まで含めて判定したいなら IS_ROLE_IN_SESSION を使うのが正解です。ここを取り違えると「解除されるべき人が伏字のまま」「意図せず露出」の両方が起き得ます。03Row Access Policy:行を絞る
行アクセスポリシーは「どの行を返すか」をブール式で定義します。CREATE ROW ACCESS POLICY で列値を引数として受け取り、式が TRUE と評価された行だけが結果に含まれます。テーブルにもビューにもネストして適用でき、地域・部門・テナントIDなどでの絞り込みに使います。実務での定番は「マッピングテーブル方式」です。ユーザーやロールと、見てよいスコープ(部門コードや地域)の対応表をあらかじめ用意し、ポリシー式の中でそれを参照します。重要なのは、ポリシー式がクエリ実行者ではなくポリシーオーナーのロールで評価される点です。おかげで、実行者にマッピングテーブルへの直接の SELECT 権限を与えなくても行フィルタが機能します——マッピング表そのものを隠しながら制御できるわけです。
04タグベースのマスキングでスケールさせる
列ごとに手作業でポリシーを貼る運用は、新しい列が増えるたびに貼り忘れが発生します。タグベースのマスキングは、object tagging と masking policy を組み合わせ、ALTER TAG … SET MASKING POLICY でタグ側にポリシーを一度だけ紐づける方式です。以後、そのタグが付いた列は——ポリシーの入力型と列の型が一致していれば——自動的に保護されます。タグはデータベース・スキーマ・テーブルの各レベルに付与でき、下位オブジェクトへ伝播するため、「新しく作られた列も勝手に守られる」状態を作れます。sensitive data classification(自動分類)と組み合わせれば、PII列の検出 → タグ付与 → 自動マスクという一連の流れを設計できます。
05AWS側との連携
SnowflakeはAWS上で動くため、周辺のAWSサービスと組み合わせると守りが厚くなります。外部ステージのS3データは SSE-KMS/カスタマー管理キーで暗号化し、Storage Integration と IAM ロールで最小権限アクセスに寄せます。ロード/アンロードの経路は AWS PrivateLink でインターネットを経由させない構成にできます。さらに強い要件——「Snowflakeにロードする前からトークン化しておき、権限のあるロールだけがクエリ時に復号(detokenize)する」——には External Tokenization を使います。これはマスキングポリシー本体から外部関数を呼ぶ方式で、Snowflakeがリモートサービスへ直接ではなく、Amazon API Gateway(プロキシ)経由で AWS Lambda(リモートサービス)を呼び出し、トークン化プロバイダのポリシーに従って結果を返します。SnowflakeからAPI GatewayへのHTTPリクエストは AWS SigV4 で署名され、鍵は KMS、権限は IAM で分離します。External Tokenization も Enterprise Edition 以上です。
06検証で先に踏み抜いた落とし穴
これらのポリシーは強力な一方、条件式の書き方ひとつで「見えてはいけないものが見える」「見えるべきものが伏字」という事故につながります。EMWはこの手の落とし穴を必ずPoC・検証環境で先に踏み抜き、本番では未然に防ぐ運用を徹底しています。実際に検証段階で発見・是正した代表例を挙げます。第一に、マスキング条件を CURRENT_ROLE だけで書いたところ、機能ロールを階層で継承しているユーザーが期待どおりに解除されないケースを検証中に観測しました。本番投入前に IS_ROLE_IN_SESSION ベースへ書き換え、ロール階層を意識した条件に是正しています。第二に、Row Access Policy のマッピングテーブルを巨大テーブルへ毎行結合する式にしたところ、検証で想定外にクエリが重くなると判明。マッピングを絞り込み、クラスタリングやキャッシュ前提の設計に見直しました。第三に、タグの伝播範囲を読み違えると、スキーマにタグを付けた瞬間に想定外の列まで一斉にマスクされ得ることも検証で確認し、適用範囲を段階的に広げる手順へ切り替えました。低コストの小規模導入から最大規模の基盤まで、複数業種で同じ姿勢を通し、本番環境での重大障害0を継続しています。
07運用とガバナンスのまとめ
ポリシーは分散させず集中管理するのが鉄則です。CREATE/APPLY 権限を専用のポリシー管理ロールに集約し、テーブルオーナーが勝手に外せない構造にします。適用状況は ACCOUNT_USAGE の POLICY_REFERENCES や MASKING_POLICIES などのビューで棚卸しし、「どの列・どの行にどのポリシーが効いているか」を定期的に可視化します。そして、誰がいつ機微な列にアクセスしたかは Access History で監査します。列マスキング+行アクセス+タグ+自動分類+監査をセットで回すことで、「誰が・どの条件で・何を見られるのか」を説明可能な状態に保てます。ガバナンスとは、ビジネスルールを強制力のある制御と証跡へ翻訳することであり、Snowflakeのポリシー群はその中核を担います。
参考情報(一次情報)
- Understanding Dynamic Data Masking | Snowflake Documentation
- Understanding row access policies | Snowflake Documentation
- Tag-based masking policies | Snowflake Documentation
- Understanding External Tokenization | Snowflake Documentation
- IS_ROLE_IN_SESSION | Snowflake Documentation
- Protect Your Sensitive Data Better with Tag-Based Masking | Snowflake Blog
EMWはAWS×Snowflakeで、マスキング/行アクセス/タグ設計から監査・PrivateLink連携まで検証込みで支援します。データの見せ分け設計はお気軽にご相談ください。
相談する