gdpr-compliant について
開発者、アーキテクト、DevOpsチーム、技術リード向けのGDPRエンジニアリング資料です。プライバシー原則をデータ処理、API、ログ、保持期間、セキュリティ、レビュー項目に落とし込んでいます。
主な機能
- 01プライバシー・バイ・デザインの指針
- 02データ最小化と保持の実践
- 03API、ログ、エラー処理の規則
- 04暗号化、パスワード、シークレットの指針
- 05GDPR対応のPRレビューチェックリスト
活用シーン
- 01個人データを扱う機能のレビュー
- 02保存データの保持と消去の設計
- 03APIやログのプライバシーリスク確認
- 04GDPRレビューに向けた技術変更の準備
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ github/ awesome-copilot --skill gdpr-compliantインストール後、Claude Code で/gdpr-compliantを入力して読み込まれたか確認します。
同梱ファイルreferences/data-rights.mdreferences/Security.md
詳細
GDPR エンジニアリングスキル
エンジニア、アーキテクト、DevOps、テックリード向けの実践的な GDPR リファレンスです。 CNIL の開発者向けガイダンスおよび GDPR 第 5 条、第 25 条、第 32 条、第 33 条、第 35 条に基づいています。
基本原則: 収集を減らす。保存を減らす。公開を減らす。保持期間を短くする。
詳しくは、references/ 内のリファレンスファイルをご覧ください。
references/data-rights.md— ユーザーの権利に関するエンドポイント、DSR ワークフロー、RoPAreferences/security.md— 暗号化、ハッシュ化、シークレット、匿名化references/operations.md— クラウド、CI/CD、インシデント対応、アーキテクチャパターン
1. GDPR の基本原則(第 5 条)
| 原則 | エンジニアリング上の義務 |
|---|---|
| 適法性、公平性、透明性 | すべての処理活動について、法的根拠を RoPA に記録します |
| 目的の限定 | 新たな法的根拠がない限り、目的 A のために収集したデータを目的 B に再利用してはなりません |
| データの最小化 | 現時点で文書化された業務上の必要性がある項目だけを収集します |
| 正確性 | 更新用エンドポイントを提供し、訂正内容を下流のストアにも反映します |
| 保存期間の制限 | TTL はスキーマの設計時に定義します。後回しにしてはなりません |
| 完全性と機密性 | 保存時および転送時に暗号化し、アクセスを制限して監査します |
| 説明責任 | コンプライアンスの証拠を維持し、いつでも DPA の検査に備えて RoPA を用意します |
2. プライバシー・バイ・デザインとデフォルト設定
必須
- 個人データを保持するすべてのテーブルに、作成時に
CreatedAtとRetentionExpiresAtを追加します。 - 任意のデータ収集はすべてデフォルトでオフにします。ユーザーがオプトインする形式とし、デフォルトでオンの設定からオプトアウトさせてはなりません。
- 高リスクの処理(生体認証、健康データ、大規模なプロファイリング、体系的な監視)を構築する前に、DPIA を実施します。
- 処理活動を新たに導入する機能を追加するたびに、RoPA を更新します。
- データがサブプロセッサに渡る前に、各サブプロセッサと DPA を締結します。
禁止
- 文書化された法的根拠なしに、新たなデータ収集機能をリリースしてはなりません。
- 明示的な同意なしに、分析、トラッキング、テレメトリーをデフォルトで有効にしてはなりません。
- RoPA に記載されていないシステムに個人データを保存してはなりません。
3. データの最小化
必須
- すべての DTO/モデルの項目を具体的な業務上の必要性に対応付けます。文書化されていない項目は削除します。
- 作成、読み取り、更新には別々の DTO を使用し、同じオブジェクトを使い回してはなりません。
- 呼び出し元が参照を許可されている情報のみを返します。レスポンスのプロジェクションを使用します。
- 機密性の高い値は境界でマスキングします。カード番号は
****1234を返し、完全な値を返してはなりません。 - デフォルトの一覧表示/検索用プロジェクションから、機密項目(生年月日、国民識別番号、健康情報)を除外します。
禁止
- 個人データが含まれる可能性がある場合、リクエスト/レスポンスの本文全体をログに記録してはなりません。
- 個人データを URL のパス部分やクエリパラメーターに含めてはなりません(CDN ログやブラウザー履歴に残るため)。
- 明示的な法的根拠なしに、
dateOfBirth、国民識別番号、健康データを収集してはなりません。
4. 目的の限定
必須
- 各処理活動の目的を、コードコメントと RoPA に記載します。
- データを二次的な目的に再利用する前に、新たな法的根拠を取得するか、目的の適合性を分析します。
禁止
- サービス提供のために収集した個人データを、明示的な同意なしに広告ネットワークと共有してはなりません。
- 別個の法的根拠とユーザーへの通知なしに、サポートチケットの内容を ML モデルのトレーニングに使用してはなりません。
5. ストレージの制限と保持期間
MUST
- 個人データを保持するすべてのテーブルには、保持期間を定めるMUSTがあります。
- スケジュールされたジョブ(Hangfire、cron)で保持期間を自動的に適用します。手動で処理してはなりません。
- 保持期間が過ぎたデータは匿名化するか削除します。期限切れのデータを本番環境に気付かれないまま残してはなりません。
推奨されるデフォルト値
| データの種類 | 最大保持期間 |
|---|---|
| 認証/監査ログ | 12~24 か月 |
| セッション/リフレッシュトークン | 30~90 日 |
| メール/通知ログ | 6 か月 |
| 非アクティブなユーザーアカウント | 最終ログインから 12 か月後 → 通知 → 削除 |
| 支払い記録 | 税法で定められた期間(7~10 年)に従い、最小限に保持 |
| 分析イベント | 13 か月 |
SHOULD
RetentionExpiresAt列を追加し、挿入時に値を計算します。- ソフトデリート(
DeletedAt)を使用し、消去リクエストの猶予期間(30 日)の経過後にスケジュールされたハードデリートを行います。
MUST NOT
- 「後で役に立つかもしれない」という理由で、個人データを無期限に保持してはなりません。
6. API 設計ルール
MUST
- URL パスやクエリパラメーターに個人データを含めてはなりません。
GET /users/{userId}
- 個人データを返す、または受け付けるすべてのエンドポイントで認証を行います。
- 操作を行うユーザーの ID は JWT から取得します。リクエストボディから取得してはなりません。
- すべてのリソースについて所有者であることを検証します。
if (resource.OwnerId != currentUserId) return 403。 - UUID または不透明な識別子を使用し、公開リソース ID に連番の整数を使用してはなりません。
SHOULD
- 機密性の高いエンドポイント(ログイン、データエクスポート、パスワードリセット)にレート制限を設定します。
Referrer-Policy: no-referrerと明示的なCORS許可リストを設定します。
MUST NOT
- API レスポンスにスタックトレース、内部パス、データベースエラーを返してはなりません。
- 認証が必要な API で
Access-Control-Allow-Origin: *を使用してはなりません。
7. ログのルール
MUST
- アプリケーションログ内の IP アドレスを匿名化し、末尾 1 オクテット(IPv4)または末尾 80 ビット(IPv6)をマスクします。
192.168.1.xxx
- パスワード、トークン、セッション ID、認証情報、カード番号、国民識別番号、健康データをログに記録してはなりません。
- PII が含まれる可能性のあるリクエスト/レスポンスの本文全体をログに記録してはなりません。
- ログの保持期間を適用し、定められた期間の経過後に自動的に削除します。
SHOULD
- データではなくイベントを記録します。「
User {UserId} updated email」ではなく、「Email changed from [email protected] to [email protected]」のように記録します。 - メールアドレスではなく、内部識別子として
userIdを使用した構造化ログ(JSON)を使用します。 - 監査ログ(機密データへのアクセス、管理者の操作)をアプリケーションログと分離し、保持期間と ACL を別々に設定します。
8. エラー処理
MUST
- 一般的なエラーメッセージを返し、スタックトレース、内部パス、DB エラーを公開してはなりません。
"Column 'email' violates unique constraint on table 'users'""A user with this email address already exists."
- すべてのエラーレスポンスに Problem Details(RFC 7807) を使用します。
- 相関 ID を付けてサーバー側にエラーの詳細を記録し、クライアントには相関 ID のみを返します。
MUST NOT
- エラーレスポンスにファイルパス、クラス名、行番号を含めてはなりません。
- エラーメッセージに個人データを含めてはなりません(例:「User [email protected] not found」)。
9. 暗号化(概要 — 詳細は references/security.md を参照)
| 対象範囲 | 最低基準 |
|---|---|
| 一般的な個人データ | AES-256 のディスク/ボリューム暗号化 |
| 機密データ(健康、金融、生体認証) | KMS による AES-256 の列レベル暗号化+エンベロープ暗号化 |
| 転送中 | TLS 1.2 以降(1.3 を推奨)。HSTS を適用 |
| 鍵 | HSM を基盤とする KMS。DEK を毎年ローテーション |
TLS 1.0/1.1、NULL 暗号スイート、ハードコードされた暗号化キーを許可してはなりません(MUST NOT)。
10. パスワードのハッシュ化
MUST
- Argon2id(推奨)または bcrypt(コスト ≥ 12)を使用します。MD5、SHA-1、SHA-256 は使用してはなりません。
- パスワードごとに一意のソルトを使用します。ハッシュのみを保存します。
MUST NOT
- いかなる形式でもパスワードをログに記録してはなりません。URL でパスワードを送信してはなりません。リセットトークンを平文で保存してはなりません。
11. シークレット管理
必須
- すべてのシークレットを KMS に保存します:Azure Key Vault、AWS Secrets Manager、GCP Secret Manager、または HashiCorp Vault。
- シークレットのコミットを防ぐため、pre-commit フック(
gitleaks、detect-secrets)を使用します。 - 開発者の退職時、年次スケジュール、または侵害が疑われる場合にシークレットをローテーションします。
.gitignore に必ず含めるもの: .env、.env.*、*.pem、*.key、*.pfx、*.p12、secrets/
禁止
- シークレットをソースコードにコミットすること。シークレットを平文の環境変数のデフォルト値として保存すること。
12. 匿名化と仮名化(概要 — references/security.md を参照)
- 匿名化 =不可逆 → GDPR の適用対象外です。消去後に保持する記録に使用します。
- 仮名化 =鍵を使って可逆 → リスクは低減しますが、引き続き個人データです。
- ユーザーを消去する場合、保持が必要な記録(財務、監査)は削除するのではなく匿名化します。
- 仮名化キーは KMS に保存し、仮名化されたデータと同じデータベースには決して保存しないでください。
禁止 再識別がリンケージ攻撃によって可能なデータを「匿名化済み」と呼ぶこと。
13. フェイクデータを使ったテスト
必須
- 開発、ステージング、または CI 環境で、本番の個人データを使用してはなりません。
- まず PII を除去せずに、本番 DB のバックアップを非本番環境に復元してはなりません。
- 合成データ生成ツールを使用します:
Bogus(.NET)、Faker(JS/Python/Ruby)。 - すべてのテスト用メールアドレスには
@example.comを使用します。
14. アンチパターン
| アンチパターン | 正しい方法 |
|---|---|
| URL 内の PII | 公開識別子には不透明な UUID を使用 |
| リクエスト本文全体のログ記録 | 構造化されたイベントメタデータのみを記録 |
| 「永久保存」スキーマ | 設計時に TTL を定義 |
| 開発/テスト環境での本番データ使用 | 合成データ+スクラビングパイプライン |
| チーム間での認証情報の共有 | 個別アカウント+RBAC |
| ハードコードされたシークレット | KMS+シークレットマネージャー |
認証 API での Access-Control-Allow-Origin: * | 明示的な CORS 許可リスト |
| プロフィールデータと同じ場所への同意情報の保存 | 専用の同意情報ストア |
| GET クエリパラメーター内の PII | POST 本文または認証済みセッション |
| 公開 URL での連番整数 ID | UUID |
| 準識別子を含む「匿名化済み」データ | k-匿名性を適用し、リンケージ耐性をテスト |
| EEA 外のバックアップリージョンの混在 | バックアップジョブでリージョンを明示的に制限 |
15. PR レビューチェックリスト
データモデル
- 新しい PII 列にはすべて、文書化された目的と保持期間があります。
- 機微情報(健康、財務、国民 ID)には列レベルの暗号化を使用します。
- 公開向け識別子として連番整数の PK を使用していません。
API
- URL パスやクエリパラメーターに PII がありません。
- 個人データを返すすべてのエンドポイントで認証が必要です。
- 所有権チェックがあり、ユーザーが別のユーザーのリソースにアクセスできないようになっています。
- 機微なエンドポイントにレート制限が適用されています。
ログ記録
- パスワード、トークン、認証情報を記録していません。
- IP アドレスを匿名化しています(最後のオクテットをマスク)。
- PII が含まれる可能性のあるリクエスト/レスポンス本文全体を記録していません。
インフラストラクチャ
- 公開ストレージバケットやパブリック IP のデータベースがありません。
- 新しいクラウドリソースに
DataClassificationタグを付けています。 - 新しいストレージリソースで保存時の暗号化が有効になっています。
- データ保存用の新しい地理的リージョンは EEA に準拠しているか、SCC の対象です。
シークレットと CI/CD
- ソースコードやコミット済み設定ファイルにシークレットがありません。
- 新しいシークレットを KMS とシークレットインベントリ文書に追加しています。
- CI/CD のシークレットはパイプラインログでマスクされています。
保持と消去
- 保持の適用ジョブまたはポリシーが、新しいデータストアまたはフィールドを対象にしています。
- 消去パイプラインを更新し、新しいデータストアを対象にしています。
ユーザーの権利とガバナンス
- データエクスポートエンドポイントに、新しい個人データ項目が含まれていること。
- 新しい処理活動が導入された場合、RoPA が更新されていること。
- 新しいサブプロセッサーについて、DPA が締結され、RoPA に記載されていること。
- 変更に高リスクの処理が伴う場合、DPIA が実施されていること。
**黄金律:**収集を減らす。保存を減らす。公開を減らす。保持を減らす。
収集しない個人データは、失うことも、侵害されることも、 責任を問われることもありません。
CNIL の開発者向け GDPR ガイダンス、GDPR 第 5 条、第 25 条、第 32 条、第 33 条、第 35 条、 ENISA、OWASP、および NIST のエンジニアリングのベストプラクティスに基づいています。