0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Glue を使ったPIIのデータマスキング やってみた

Last updated at Posted at 2025-08-31

AWS Glue Studio だけでノーコード PII マスキングをやってみる(Detect Sensitive Data)

TL;DR

  • Glue Studio の Detect Sensitive Data(Detect PII) トランスフォームだけで、スクリプト無しのデータマスキングができる
  • 構成は S3(入力) → Detect PII → S3(出力) の 3 ノードで OK
  • 本記事のサンプル JSON を S3 に置き、チェックリスト通りに設定すればそのまま再現可能

つくるもの

スクリーンショット 2025-08-31 19.12.36.png

  • 検出: Include all available types (256)
  • マスク: ****** に置き換え
  • 出力: JSON

前提

  • AWS アカウント(Glue/Athena/S3 の基本操作ができる権限)
  • Glue Version 4.0 以上(部分マスク等の機能が安定)

1. テストデータ(コピーして pii_sample.json として保存)

※すべてAIで生成したダミーデータ。実在の個人とは無関係です。

[
  {
    "customer_id": "1",
    "full_name": "鈴木 太郎",
    "email": "user61_92346728592a90ce@example.com",
    "phone": "098-6390-6191",
    "birth_date": "1987-05-04",
    "address": "埼玉県川崎市中原区1-7-19",
    "national_id": "674377254175"
  },
  {
    "customer_id": "2",
    "full_name": "高橋 花子",
    "email": "user11_9ad86a4b82b15b50@example.com",
    "phone": "097-7420-2184",
    "birth_date": "1999-06-19",
    "address": "神奈川県札幌市中央区4-12-17",
    "national_id": "926382426486"
  },
  {
    "customer_id": "3",
    "full_name": "佐藤 太郎",
    "email": "user27_4f5085e4592a90ce@example.com",
    "phone": "073-9792-9433",
    "birth_date": "1979-03-16",
    "address": "埼玉県川崎市中原区2-9-2",
    "national_id": "367203173155"
  }
]

2. S3 に配置

  • 入力: s3://<bucket-name>/glue-pii-mask/input/pii_sample.json
  • 出力: s3://<bucket-name>/glue-pii-mask/output/

3. Glue Studio でジョブを作成(ノーコード)

  1. Glue Studio → Create jobVisual ETL
  2. ノード構成を S3/Data Catalog → Detect Sensitive Data → S3 にする
  3. 各ノードを以下の通り設定

Source(Amazon S3)

  • 形式: JSON
  • スキーマ: Data Catalog テーブルを利用するか、プレビューから推論可能

Transform — Detect Sensitive Data(Detect PII)

検出モード

  • Find columns that contain sensitive data(列レベル / 高速・低コスト)
    構造化カラム(email/phone/national_id)向け
  • Find sensitive data in each row(セル内容スキャン / 厳密・コスト高)
    自由記述(address など)向け

今回の実験では、後者を利用しています。

対象エンティティ

  • まずは Include all available types (256)
    → 不足時は Select specific patternsCustom pattern を追加
    例:12 桁の独自 ID → 正規表現 \b\d{12}\b

結果を少し書いてしまいますが、AWSのデフォルト設定では、「住所」や「名前」のマスキングはできませんでした。
必要に応じてカスタムパターンを追加する必要があります。

既定アクション(Global action)

  • Enrich data with detection results
    → 検出結果を含む列(例: 検出したエンティティや位置情報)を元データに追加
  • Redact detected text
    → 一括マスク
  • Partially redact detected text
    → 先頭/末尾を残す
  • Apply cryptographic hash
    → SHA-256

Fine-grained action overrides(列別の上書き例)
今回は指定していませんが、以下のような設定が可能です。

* `full_name`: Partially redact(先頭 1 文字のみ可視)
* `email`: Apply cryptographic hash
* `phone`: Partially redact(末尾 4 桁を残す)
* `address`: Detect PII in each cell に切り替え、Redact で数字のみマスクしたい場合は Custom pattern を併用
* `national_id`: Custom pattern(`\b\d{12}\b`)+ Apply cryptographic hash

同じ列に「マスク+ハッシュ」を同時適用することはできません。別列に出力するか、ジョブを段階分割します。

Target(Amazon S3)

  • 形式: Parquet(推奨。圧縮/クエリ効率◎)または JSON
  • 圧縮形式: GZIP
  • 出力先: s3://<bucket-name>/glue-pii-mask/output/
  • (任意)Partition keys: birth_year など 非 PII

出力形式として CSV は推奨できません

理由は、Detect Sensitive Data Transform の処理結果に DetectedEntities という Map 型フィールドが含まれるためです。
CSV 形式はネストされたデータ型(Map, Array など)をサポートしていないため、出力時に以下のエラーが発生します。

Job 設定

  • Glue version: 5.0
  • Worker type: 小規模なら G.1X
  • Job bookmark: 検証中は Disabled(毎回全件処理)

4. 結果

S3 出力(JSON)は長いので、本文では要点のみ記します(末尾に掲載)。
以下の知見が得られました。

  • 1行目が喪失する
    スクリーンショット 2025-08-31 19.52.26.png

  • デフォルトだけでは「氏名」や「住所」がマスクされないことがある

    • プリセットのエンティティに含まれないケースがあり、カスタムエンティティ(正規表現+コンテキスト語)を追加して対象に含める。
    • あるいは Transform 後に PySpark/ApplyMapping で対象列を強制マスク(既知列なら実務上はこれが堅い)
  • DetectedEntities(Map 型)が巨大化しやすい

    • 監査目的で保持するのでなければ、最終出力前に DropFields 等で削除する。
    • CSV に落とす必要がある場合は DetectedEntitiesto_json() で文字列化する(Map をそのまま CSV 出力は不可)

よくあるつまずき

  • 列レベル検出だけで自由記述の PII を取りこぼす
    addresscommentセル内検出を併用
  • 誤検知/過検知
    → 感度(High/Low)と Fine-grained overrides / Custom pattern で調整
  • 出力がどんどん増える
    → 出力バケットの上書き方針 or 日付パーティションを設計
  • コスト最適化
    → 列レベル検出+サンプリング率(Sample portion)で調整。自由記述だけセル内検出

参考資料(公式)

  • AWS Glue Studio — Detect Sensitive Data(Detect PII)

  • AWS Glue Studio(Detect and process sensitive data)

  • AWS Glue Studio(Visual ETL の基本)

マスキング結果

{
    "customer_id": "2",
    "full_name": "高橋 花子",
    "email": "******",
    "phone": "******",
    "birth_date": "1999-06-19",
    "address": "神奈川県札幌市中央区4-12-17",
    "national_id": "******",
    "DetectedEntities": {
        "email": [
            {
                "entityType": "EMAIL",
                "actionUsed": "REDACT",
                "start": 0,
                "end": 35
            },
            {
                "entityType": "LUXEMBOURG_PASSPORT_NUMBER",
                "actionUsed": "REDACT",
                "start": 24,
                "end": 31
            }
        ],
        "national_id": [
            {
                "entityType": "SRI_LANKA_NATIONAL_IDENTIFICATION_NUMBER",
                "actionUsed": "REDACT",
                "start": 0,
                "end": 12
            },
            {
                "entityType": "FRANCE_NATIONAL_IDENTIFICATION_NUMBER",
                "actionUsed": "REDACT",
                "start": 0,
                "end": 12
            },
            {
                "entityType": "USA_DRIVING_LICENSE",
                "actionUsed": "REDACT",
                "start": 0,
                "end": 12
            },
            {
                "entityType": "BANK_ACCOUNT",
                "actionUsed": "REDACT",
                "start": 0,
                "end": 12
            },
            {
                "entityType": "CANADA_PERSONAL_HEALTH_NUMBER",
                "actionUsed": "REDACT",
                "start": 0,
                "end": 12
            },
            {
                "entityType": "LUXEMBOURG_TAX_IDENTIFICATION_NUMBER",
                "actionUsed": "REDACT",
                "start": 0,
                "end": 12
            },
            {
                "entityType": "JAPAN_DRIVING_LICENSE",
                "actionUsed": "REDACT",
                "start": 0,
                "end": 12
            },
            {
                "entityType": "CYPRUS_DRIVING_LICENSE",
                "actionUsed": "REDACT",
                "start": 0,
                "end": 12
            },
            {
                "entityType": "FRANCE_DRIVING_LICENSE",
                "actionUsed": "REDACT",
                "start": 0,
                "end": 12
            },
            {
                "entityType": "INDIA_AADHAAR_NUMBER",
                "actionUsed": "REDACT",
                "start": 0,
                "end": 12
            },
            {
                "entityType": "LIECHTENSTEIN_TAX_IDENTIFICATION_NUMBER",
                "actionUsed": "REDACT",
                "start": 0,
                "end": 12
            },
            {
                "entityType": "SPAIN_SSN",
                "actionUsed": "REDACT",
                "start": 0,
                "end": 12
            }
        ],
        "phone": [
            {
                "entityType": "UK_PHONE_NUMBER",
                "actionUsed": "REDACT",
                "start": 0,
                "end": 13
            },
            {
                "entityType": "CHINA_PHONE_NUMBER",
                "actionUsed": "REDACT",
                "start": 0,
                "end": 13
            }
        ]
    }
}
{
    "customer_id": "3",
    "full_name": "佐藤 太郎",
    "email": "******",
    "phone": "******",
    "birth_date": "1979-03-16",
    "address": "埼玉県川崎市中原区2-9-2",
    "national_id": "******",
    "DetectedEntities": {
        "email": [
            {
                "entityType": "EMAIL",
                "actionUsed": "REDACT",
                "start": 0,
                "end": 35
            },
            {
                "entityType": "LUXEMBOURG_PASSPORT_NUMBER",
                "actionUsed": "REDACT",
                "start": 24,
                "end": 31
            }
        ],
        "national_id": [
            {
                "entityType": "SRI_LANKA_NATIONAL_IDENTIFICATION_NUMBER",
                "actionUsed": "REDACT",
                "start": 0,
                "end": 12
            },
            {
                "entityType": "FRANCE_NATIONAL_IDENTIFICATION_NUMBER",
                "actionUsed": "REDACT",
                "start": 0,
                "end": 12
            },
            {
                "entityType": "USA_DRIVING_LICENSE",
                "actionUsed": "REDACT",
                "start": 0,
                "end": 12
            },
            {
                "entityType": "BANK_ACCOUNT",
                "actionUsed": "REDACT",
                "start": 0,
                "end": 12
            },
            {
                "entityType": "CANADA_PERSONAL_HEALTH_NUMBER",
                "actionUsed": "REDACT",
                "start": 0,
                "end": 12
            },
            {
                "entityType": "LUXEMBOURG_TAX_IDENTIFICATION_NUMBER",
                "actionUsed": "REDACT",
                "start": 0,
                "end": 12
            },
            {
                "entityType": "JAPAN_DRIVING_LICENSE",
                "actionUsed": "REDACT",
                "start": 0,
                "end": 12
            },
            {
                "entityType": "CYPRUS_DRIVING_LICENSE",
                "actionUsed": "REDACT",
                "start": 0,
                "end": 12
            },
            {
                "entityType": "FRANCE_DRIVING_LICENSE",
                "actionUsed": "REDACT",
                "start": 0,
                "end": 12
            },
            {
                "entityType": "INDIA_AADHAAR_NUMBER",
                "actionUsed": "REDACT",
                "start": 0,
                "end": 12
            },
            {
                "entityType": "LIECHTENSTEIN_TAX_IDENTIFICATION_NUMBER",
                "actionUsed": "REDACT",
                "start": 0,
                "end": 12
            },
            {
                "entityType": "SPAIN_SSN",
                "actionUsed": "REDACT",
                "start": 0,
                "end": 12
            }
        ],
        "phone": [
            {
                "entityType": "UK_PHONE_NUMBER",
                "actionUsed": "REDACT",
                "start": 0,
                "end": 13
            },
            {
                "entityType": "CHINA_PHONE_NUMBER",
                "actionUsed": "REDACT",
                "start": 0,
                "end": 13
            }
        ]
    }
}
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?