データ プライバシー戦略

データのプライバシーとは、個人を特定できる情報(PII)などのデータを、アクセスすべきでないユーザーから保護することです。このページでは、Cloud SQL で PII を保護するために使用できるデータ プライバシーへのアプローチについていくつか説明します。

Cloud SQL を使用すると、PII を安全に保存できます。PII は、厳重なプライバシー保護のもとで処理されるようにし、不注意でアクセスされるのを確実に防ぐ必要があります。たとえば、クレジット カード情報や医療データをデータベースに保存している場合、Cloud SQL を使用して権限のないユーザーから PII を非表示にし、マスクできます。

次の戦略を使用して、Cloud SQL で PII を保護しましょう。

列レベルのセキュリティ

列レベルのセキュリティを使用すると、データベースのテーブルの特定の列のコンテンツを見ることができるユーザーを制限できます。列レベルの権限は、INSERTUPDATESELECTREFERENCES ステートメントに適用されます。

たとえば、小売業者のウェブサイトで、Jack と Alice という 2 人のユーザーの PII を管理するとを考えてみましょう。

--User: "admin"

CREATE SCHEMA secure_schema;

CREATE TABLE secure_schema.user_details(id bigint, name text, age smallint, email_id text, password text);

--For this example, passwords are stored in plain text for demonstration
--purposes only. In production, never store passwords in plain text.

INSERT INTO secure_schema.user_details VALUES(1,'jack',34,'jack@example.com','testpass');
INSERT INTO secure_schema.user_details VALUES(2,'alice',37,'alice@example.com','testpass');

GRANT USAGE ON SCHEMA secure_schema TO analyst_ro;

--Grant read permissions on specific columns only.

GRANT SELECT (id, name, age) ON secure_schema.user_details TO analyst_ro;

--User: "analyst_ro"

SELECT * FROM secure_schema.user_details;
ERROR:  permission denied for table user_details

SELECT name, age, password FROM secure_schema.user_details;
ERROR:  permission denied for table user_details

SELECT id, name,age FROM secure_schema.user_details;
 id | name  | age
----+-------+----
  1 | jack  |  34
  2 | alice |  37

SELECT ステートメントに制限付き列を含めるか、「SELECT *」と入力すると、エラー メッセージが表示されます。Cloud SQL は、これらの列にある Jack と Alice の PII を保護します。

また、1 つの GRANT ステートメントを使用して、異なる権限を組み合わせることもできます。

GRANT SELECT (id,name,age), UPDATE (name) ON secure_schema.user_details TO analyst_ro;

ビューベースのアプローチ

テーブルにビューを作成し、他のユーザーから隠したい列を除外またはマスキングして、テーブルではなくビューへのアクセス権を付与することで、列レベルのセキュリティを実現することもできます。

次の例では、小売店のウェブサイトでビューベースのアプローチを使用して、Jack と Alice の PII を保護する方法を示しています。

--User: "admin"

CREATE SCHEMA analyst_ro;
CREATE VIEW analyst_ro.user_details AS SELECT id, name, age FROM secure_schema.user_details;
GRANT USAGE ON SCHEMA analyst_ro TO analyst_ro;
GRANT SELECT ON analyst_ro.user_details TO analyst_ro;

--User: "analyst_ro"

SELECT id,name,age FROM user_details;
 id | name  | age
----+-------+----
  1 | jack  |  34
  2 | alice |  37

SELECT * FROM user_details;
 id | name  | age
----+-------+----
  1 | jack  |  34
  2 | alice |  37

この例では、ビューの名前がテーブルと同じになるように、ビュー用に別のスキーマを作成しています。ビューベースのアプローチでは、SELECT * を使用できます。

また、ビューを作成してデータベース テーブルの列をマスクすることで、マスクされた PII が権限のないユーザーに表示されないようにすることもできます。

CREATE VIEW analyst_ro.user_details AS SELECT id, name, age, 'redacted@example.com' as email_id,'*****'::text as password FROM secure_schema.user_details;

SELECT * FROM user_details;
 id | name  | age |     email_id         | password
----+-------+-----+----------------------+---------
  1 | jack  |  34 | redacted@example.com | *****
  2 | alice |  37 | redacted@example.com | *****

行レベルのセキュリティ

列レベルのセキュリティとビューベースのアプローチにより、データベース テーブルの列にある PII を特定のユーザーから隠すことができます。しかし、場合によっては、このデータにフィルタを適用したり、テーブルの特定の行へのアクセスを許可したいときがあります。このテーブルには、ユーザーの条件に基づいて、特定のユーザーだけがアクセスできる PII が含まれています。これは行レベルのセキュリティと呼ばれます。

行レベルのセキュリティは、ユーザーが自身の PII に対してのみ読み取りアクセス権と書き込みアクセス権を持っているマルチテナント アプリケーションで役に立ちます。Cloud SQL では、テーブルに行レベルのセキュリティ ポリシーを設定でき、ユーザーがクエリを作成して表示できる行や、ユーザーがデータ変更コマンドを実行して挿入、更新、削除できる行を、ユーザーごとに制限できます。

小売のウェブサイトの例では、Jack と Alice に行レベルのセキュリティを実装して、それぞれの PII を表示することはできますが、変更や削除はできません。

--User: "admin"
--Create and enable a policy for row-level security

CREATE POLICY user_details_rls_pol ON secure_schema.user_details FOR ALL TO PUBLIC USING (name=current_user);
ALTER TABLE secure_schema.user_details ENABLE ROW LEVEL SECURITY;

SELECT * FROM secure_schema.user_details;
 id | name  | age |     email_id      | password
----+-------+-----+-------------------+---------
  1 | jack  |  34 | jack@example.com  | testpass
  2 | alice |  37 | alice@example.com | testpass

--User: "jack"

SELECT * FROM secure_schema.user_details;
 id | name | age |    email_id      | password
----+------+-----+------------------+---------
  1 | jack |  34 | jack@example.com | testpass

--User: "alice"

SELECT * FROM secure_schema.user_details;
 id | name  | age |    email_id       | password
----+-------+-----+-------------------+---------
  2 | alice |  37 | alice@example.com | testpass

BYPASSRLS 属性を持つロールに割り当てられているユーザーは、テーブルにアクセスするときに行レベルのセキュリティをバイパスできます。テーブルのオーナーも、行レベルのセキュリティをバイパスできます。テーブルのオーナーに行レベルのセキュリティを適用したい場合は、ALTER TABLE ... FORCE ROW LEVEL SECURITY コマンドを使用します。

データベース テーブルの行に行レベルのセキュリティを適用したくない場合もあります。たとえば、pg_dump を使用してテーブルのバックアップを作成する場合、バックアップから行が省略されることは望ましくありません。これを回避するには、バックアップを作成するユーザーの row_security 構成パラメータを OFF に設定します。行レベルのセキュリティに基づいてフィルタリングされた行がある場合は、エラー メッセージが表示されます。

データのマスキングと匿名化

ビューベースのアプローチでデータをマスクするだけでなく、postgresql_anonymizer 拡張機能を使用してデータをマスクすることもできます。この拡張機能は、PostgreSQL データベースから PII や商業上のセンシティブ データをマスキングまたは置換します。

ビューベースのアプローチではなく拡張機能を使用すると、次のようなメリットがあります。

  • 置換、ランダム化、フェイク、仮名化、部分スクランブル、シャッフル、ノイズ追加、一般化など、さまざまなマスキング機能があります。

  • 機能テストやデータ処理に使用できる、意味のあるマスクされたデータを生成できます。

  • PostgreSQL のデータ定義言語(DDL)を使用してマスキング ルールを宣言し、テーブル定義内で匿名化戦略を指定できます。

postgresql_anonymizer 拡張機能のインストールと構成

この拡張機能を Cloud SQL インスタンスで使用する手順は次のとおりです。

  1. インスタンスを編集して、cloudsql.enable_anon flagon に設定します。フラグの設定方法と拡張機能でサポートされるフラグの詳細については、データベース フラグを構成するをご覧ください。

  2. 次のコマンドを実行して、データベースに拡張機能を作成します。

    --Connect to the PostgreSQL database
    
    CREATE EXTENSION IF NOT EXISTS anon CASCADE;
    SELECT anon.init();
    

拡張機能をインストールして構成したら、インスタンス上で動的マスク静的マスク匿名ダンプの匿名化戦略を実装します。

動的マスク

動的マスクを使用して、特定のユーザーのマスキング ルールを定義します。これらのユーザーには PII は表示されません。代わりに、マスクされたデータが表示されます。他のすべてのユーザーには、マスクされていないデータが表示されます。これは、PII を変更せずに、特定のユーザーだけに PII を非表示にする場合に、本番環境で便利です。

小売店のウェブサイトの例では、管理者は Jack と Alice のマスクされていないメールアドレスとパスワードを表示できるものの、アナリストはマスクされたデータのみしか表示できないように、動的マスクを実装できます。

--Activate the dynamic masking engine

SELECT anon.start_dynamic_masking();

--Declare the masking user and masking rules
--analyst_ro is the masked user with select privileges on the
--user_details table

SECURITY LABEL FOR anon ON ROLE analyst_ro IS 'MASKED';

SECURITY LABEL FOR anon ON COLUMN secure_schema.user_details.email_id IS 'MASKED WITH FUNCTION anon.fake_email()';
SECURITY LABEL FOR anon ON COLUMN secure_schema.user_details.password  IS 'MASKED WITH FUNCTION anon.hash(password)';

--User: "admin" (can see all unmasked data)

SELECT * FROM secure_schema.user_details;
 id | name  | age |    email_id       | password
----+-------+-----+------------  -----+---------
  1 | jack  |  34 | jack@example.com  | testpass
  2 | alice |  37 | alice@example.com | testpass

--User:"analyst_ro" (note that the "email_id" and "password" columns are
--replaced with masked data,)
--Data in the password column is truncated for better formatting.

SELECT * FROM secure_schema.user_details;
 id | name  | age |       email_id         | password
----+-------+-----+-----------------  -----+----------------
  1 | jack  |  34 | alisontodd@example.com | 13d249f2cb4127b
  2 | alice |  37 | amanda35@example.com   | 13d249f2cb4127b

静的マスク

静的マスクを使用して、マスキング ルールで定義された基準に従ってテーブル内の PII を削除し、その情報をマスクされたデータに置き換えます。ユーザーはマスクされていないデータを取得できません。これは、PII を変更する必要があり、その情報を誰にも知られたくない場合に、テスト環境で便利です。

小売店のウェブサイトの例では、静的マスクを実装することにより、Jack と Alice のマスクされていないメールアドレスとパスワードがどのユーザーにも表示されないようにできます。代わりに、マスクされたデータのみが表示されます。

--User: "admin"

SELECT * FROM secure_schema.user_details;
 id | name  | age |    email_id       | password
----+-------+-----+--------------  ---+---------
  1 | jack  |  34 | jack@example.com  | testpass
  2 | alice |  37 | alice@example.com | testpass

--Apply earlier defined masking rules to the table permanently.
--Now all users see masked data only.

SELECT anon.anonymize_table('secure_schema.user_details');
 anonymize_table
-----------------
 t

--User: "analyst_ro"
--Data in the password column is truncated for better formatting.

select * from secure_schema.user_details;
 id | name  | age |           email_id              |  password
----+-------+-----+-------------------------  ------+---------------
  1 | jack  |  34 | christophercampbell@example.com | 13d249f2cb412c
  2 | alice |  37 | annebenitez@example.com         | 13d249f2cb4127

匿名ダンプ

匿名ダンプを使用して、マスクされたデータを SQL ファイルにエクスポートします。小売店のウェブサイトの例では、user_details テーブルに含まれるマスクされたデータのダンプファイルを作成できます。

--Launch pg_dump_anon with the masked user to apply earlier defined --masking rules

pg_dump_anon -h HOSTIP -p 5432 -d DATABASE_NAME -U analyst_ro --table=secure_schema.user_details --file=user_details_anonysms.sql

データの暗号化

PII をマスキングすることは可能ですが、情報は書式なしテキストとしてデータベースに保存されます。管理者はこの情報を表示できます。

pgcrypto 拡張機能を使用すると、PII を暗号化してから保存できます。これにより、有効な暗号鍵を持つユーザーのみが情報を復号し、書式なしテキストとして表示できます。

pgcrypto 拡張機能には、いくつかのハッシュ関数と暗号化関数があります。

ハッシュ

ハッシュは一方向の暗号関数であり、PII の暗号化のみを行います。これは、パスワードをハッシュ形式で保存し、ユーザーが入力したパスワードとハッシュ化されたパスワードを照合する場合に便利です。ハッシュ化されたパスワードが書式なしテキストで復号されることはありません。

小売店のウェブサイトの例では、pgcrypto 拡張機能を使用して Jack のパスワードをハッシュ化してから user_details テーブルに保存できます。

--Hash passwords before storing them in the user_details table.

TRUNCATE TABLE secure_schema.user_details;
INSERT INTO secure_schema.user_details VALUES(1,'jack',34,'jack@example.com',crypt('testpassword', gen_salt('bf')));

--Match the hashed data with user entered password

SELECT id, name FROM secure_schema.user_details WHERE email_id = 'jack@example.com' AND password = crypt('testpassword', password);
 id | name
----+-----
  1 | jack

暗号化

暗号化暗号関数を使用して、鍵で PII を暗号化します。その後ユーザーは、情報を書式なしテキストに復号する際にこの鍵が必要になります。これは、クレジット カード情報や銀行口座情報を保存する場合、アプリケーションで PII を読み取れる形式で取得したいときに便利です。

小売店のウェブサイトの例では、Jack のパスワードとメールアドレスは暗号化されています。暗号鍵を持っているユーザーは、この情報を復号して書式なしテキストとして表示できます。それ以外のユーザーには、エラー メッセージが表示されます。

--"user_acc_key" is the encryption key

TRUNCATE TABLE secure_schema.user_details;
INSERT INTO secure_schema.user_details VALUES(1,'jack',34,pgp_sym_encrypt('jack@example.com','user_acc_key'),pgp_sym_encrypt('testpassword','user_acc_key'));

--User: "admin" (queries without an encryption key)
--Data in the email_id and password columns are truncated for better
--formatting.

SELECT * FROM secure_schema.user_details;
 id | name  | age |    email_id     | password
----+-------+-----+-----------------+-------------------
  1 | jack |  34 | \xc30d0407030209 | \xc30d040703028962

--User: "app_user" (queries with a valid encryption key)

SELECT name,pgp_sym_decrypt(email_id::bytea,'user_acc_key'),pgp_sym_decrypt(password::bytea,'user_acc_key') FROM secure_schema.user_details;
 name | pgp_sym_decrypt   | pgp_sym_decrypt
------+-------------------+----------------
 jack | jack@example.com  | testpassword

--If a user uses the wrong encryption key, then the following error message appears:

SELECT name,pgp_sym_decrypt(email_id::bytea,'user_bad_key'),
pgp_sym_decrypt(password::bytea,'user_bad_key') FROM secure_schema.user_details;
ERROR:  Wrong key or corrupt data

次のステップ

PII を不正なアクセスから保護するために使用できる、次の追加設定についてご確認ください。