1. 概要
現代の組織では、さまざまなソースから大量のデータが流入しています。多くの場合、このデータは戦略的に保存して保護するために、隔離して分類する必要があります。このタスクを手動で行うと、すぐにコストがかかり、不可能になります。
この Codelab では、Cloud Storage にアップロードされたデータを自動的に分類し、対応するストレージ バケットに移動する方法について説明します。この処理は、Cloud Pub/Sub、Cloud Functions、Cloud Data Loss Prevention、Cloud Storage を使用して行います。
演習内容
- 隔離と分類のパイプラインの一部として使用する Cloud Storage バケットを作成する。
- ファイルのアップロード時に DLP API を呼び出す単純な Cloud Functions の関数を作成する。
- ファイル処理の完了を通知するために、Pub/Sub トピックとサブスクリプションを作成する。
- サンプル ファイルを隔離バケットにアップロードして Cloud Functions を呼び出す
- DLP API を使用してファイルの検査と分類を行い、ファイルを適切なバケットに移動します。
必要なもの
- 課金が設定されている Google Cloud プロジェクト。お持ちでない場合は、作成する必要があります。
2. 設定方法
この Codelab では、Cloud Shell を介してコマンドラインを使用して、さまざまなクラウド リソースとサービスをプロビジョニングして管理します。次の操作を行うと、Cloud Shell と Cloud Shell エディタが開き、コンパニオン プロジェクト リポジトリのクローンが作成されます。
gcloud config set project [PROJECT_ID] を使用して、正しいプロジェクトを設定します。
API を有効にする
Google Cloud プロジェクトで必要な API を有効にします。
- Cloud Functions API - イベントに応答して実行される軽量のユーザー定義関数を管理します。
- Cloud Data Loss Prevention(DLP)API - テキスト、画像、Google Cloud Platform ストレージ リポジトリ内のプライバシー センシティブなフラグメントの検出、リスク分析、匿名化のための手法が提供されます。
- Cloud Storage - Google Cloud Storage は、お客様のデータを Google のインフラストラクチャに格納して、そのデータにアクセスするための RESTful サービスです。
サービス アカウントの権限
サービス アカウントは、アプリケーションや仮想マシンが承認済みの API 呼び出しを行うために使用する特別なタイプのアカウントです。
App Engine デフォルト サービス アカウント
App Engine のデフォルトのサービス アカウントは、App Engine で実行中のアプリの代理として Cloud プロジェクトでタスクを実行するために使用されます。このサービス アカウントは、デフォルトでプロジェクトに存在し、編集者ロールが割り当てられています。
まず、データ損失防止ジョブの管理に必要な DLP 管理者ロールをサービス アカウントに付与します。
gcloud projects add-iam-policy-binding $GOOGLE_CLOUD_PROJECT \ --member serviceAccount:$GOOGLE_CLOUD_PROJECT@appspot.gserviceaccount.com \ --role roles/dlp.admin
最後に、DLP API サービス エージェントのロールを付与します。これにより、サービス アカウントに BigQuery、ストレージ、データストア、Pub/Sub、Key Management Service の権限が付与されます。
gcloud projects add-iam-policy-binding $GOOGLE_CLOUD_PROJECT \ --member serviceAccount:$GOOGLE_CLOUD_PROJECT@appspot.gserviceaccount.com \ --role roles/dlp.serviceAgent
DLP サービス アカウント
App Engine サービス アカウントに加えて、DLP サービス アカウントも使用します。このサービス アカウントは、DLP API が有効になったときに自動的に作成され、最初はロールが付与されていません。閲覧者のロールを付与しましょう。
gcloud projects add-iam-policy-binding $GOOGLE_CLOUD_PROJECT \ --member serviceAccount:service-`gcloud projects list --filter="PROJECT_ID:$GOOGLE_CLOUD_PROJECT" --format="value(PROJECT_NUMBER)"`@dlp-api.iam.gserviceaccount.com \ --role roles/viewer
3. Cloud Storage バケット
次に、データを保存する 3 つの Cloud Storage バケットを作成する必要があります。
- 隔離バケット: データは最初にここにアップロードされます。
- 機密データ バケット: DLP API によって機密データと判断されたデータがここに移動されます。
- 機密データ以外のバケット: DLP API によって機密データではないと判断されたデータがここに移動されます。
gsutil コマンドを使用すると、3 つのバケットを一度に作成できます。
gsutil mb gs://[YOUR_QUARANTINE_BUCKET] \ gs://[YOUR_SENSITIVE_DATA_BUCKET] \ gs://[YOUR_NON_SENSITIVE_DATA_BUCKET]
作成したバケットの名前をメモしておきます。この名前は後で必要になります。
4. Pub/Sub トピックとサブスクリプション
Cloud Pub/Sub は、アプリケーション間で多対多の非同期メッセージングを提供します。パブリッシャーはメッセージを作成し、トピックと呼ばれるメッセージ フィードにパブリッシュします。サブスクライバーは、サブスクリプションを介してこれらのメッセージを受信します。このサブスクリプションに基づいて、この例では、DLP ジョブの実行後に Cloud Functions がファイルをそれぞれのバケットに移動します。
まず、トピックを作成しましょう。ファイルが検疫ストレージ バケットに追加されるたびに、ここにメッセージがパブリッシュされます。名前は「classify-topic」とします。
gcloud pubsub topics create classify-topic
トピックがメッセージをパブリッシュすると、サブスクリプションに通知されます。「classify-sub」という名前の Pub/Sub サブスクリプションを作成します。
gcloud pubsub subscriptions create classify-sub --topic classify-topic
このサブスクリプションにより、2 つ目の Cloud Functions がトリガーされ、ファイルが検査されて適切な場所に移動される DLP ジョブが開始されます。
5. Cloud Functions
Cloud Functions を使用すると、サーバーやランタイム環境を管理することなく、軽量でイベントベースの非同期単一目的関数をデプロイできます。dlp-cloud-functions-tutorials/gcs-dlp-classification-python/ にある指定の main.py ファイルを使用して、2 つの Cloud Functions をデプロイします。
変数を置換する
関数を作成する前に、main.py ファイル内の変数を置き換える必要があります。
Cloud Shell エディタで、main.py を調整します。28 ~ 34 行目のプロジェクト ID とバケット変数の値を、作成済みの対応するバケットに置き換えます。
main.py
PROJECT_ID = '[PROJECT_ID_HOSTING_STAGING_BUCKET]'
"""The bucket the to-be-scanned files are uploaded to."""
STAGING_BUCKET = '[YOUR_QUARANTINE_BUCKET]'
"""The bucket to move "sensitive" files to."""
SENSITIVE_BUCKET = '[YOUR_SENSITIVE_DATA_BUCKET]'
"""The bucket to move "non sensitive" files to."""
NONSENSITIVE_BUCKET = '[YOUR_NON_SENSITIVE_DATA_BUCKET]'
また、pub/sub トピック変数の値を、前の手順で作成した pub/sub トピックに置き換えます。
""" Pub/Sub topic to notify once the DLP job completes."""
PUB_SUB_TOPIC = 'classify-topic'
関数をデプロイする
Cloud Shell で、main.py ファイルが存在する gcs-dlp-classification-python ディレクトリに移動します。
cd ~/cloudshell_open/dlp-cloud-functions-tutorials/gcs-dlp-classification-python
関数をデプロイしましょう。
まず、create_DLP_job 関数をデプロイします。[YOUR_QUARANTINE_BUCKET] は正しいバケット名に置き換えます。この関数は、新しいファイルが指定された Cloud Storage 検疫バケットにアップロードされるとトリガーされ、アップロードされたファイルごとに DLP ジョブを作成します。
gcloud functions deploy create_DLP_job --runtime python37 \ --trigger-event google.storage.object.finalize \ --trigger-resource [YOUR_QUARANTINE_BUCKET]
次に、resolve_DLP 関数をデプロイし、トピックをトリガーとして指定します。この関数は、上記の関数から後続の DLP ジョブによって開始された Pub/Sub 通知をリッスンします。Pub/Sub 通知を受け取るとすぐに、DLP ジョブから結果を取得し、ファイルを有害なバケットまたは有害でないバケットに移動します。
gcloud functions deploy resolve_DLP --runtime python37 \ --trigger-topic classify-topic
確認
gcloud functions describe コマンドを使用して、両方の Cloud Functions が正常にデプロイされたことを確認します。
gcloud functions describe create_DLP_job
gcloud functions describe resolve_DLP
デプロイが正常に完了すると、ステータスに ACTIVE と表示されます。
6. サンプルデータでテストする
すべてのパーツが配置されたので、サンプル ファイルを使用してテストしてみましょう。Cloud Shell で、現在の作業ディレクトリを sample_data に変更します。
cd ~/cloudshell_open/dlp-cloud-functions-tutorials/sample_data
サンプル ファイルは、さまざまなデータを含む txt ファイルと csv ファイルで構成されています。「sample_s」という接頭辞が付いたファイルには機密データが含まれますが、「sample_n」という接頭辞が付いたファイルには含まれません。たとえば、sample_s20.csv には、米国の社会保障番号のように見えるようにフォーマットされたものが含まれています。
sample_s20.csv
Name,SSN,metric 1,metric 2
Maria Johnson,284-73-5110,5,43
Tyler Parker,284-73-5110,8,17
Maria Johnson,284-73-5110,54,63
Maria Johnson,245-25-8698,53,19
Tyler Parker,475-15-8499,6,67
Maria Johnson,719-12-6560,75,83
Maria Johnson,616-69-3226,91,13
Tzvika Roberts,245-25-8698,94,61
一方、sample_n15.csv のデータは機密データと見なされません。
sample_n15.csv
record id,metric 1,metric 2,metric 3
1,59,93,100
2,53,13,17
3,59,67,53
4,52,93,34
5,14,22,88
6,18,88,3
7,32,49,5
8,93,46,14
設定でファイルがどのように処理されるかを確認するため、テストファイルをすべて検疫にアップロードします。
bucket:
gsutil -m cp * gs://[YOUR_QUARANTINE_BUCKET]
最初は、ファイルはアップロード先の隔離バケットに保存されます。これを確認するには、ファイルをアップロードした直後に、隔離バケットの内容を一覧表示します。
gsutil ls gs://[YOUR_QUARANTINE_BUCKET]
開始した一連のイベントを確認するには、まず Cloud Functions ページに移動します。
create_DLP_job 関数の [アクション] メニューをクリックし、[ログを表示] を選択します。

この関数のログには、各ファイルに対して少なくとも 4 つのエントリが表示されます。これらのエントリは次のことを示しています。
- 関数の実行が開始されました
- 関数が特定のファイルに対してトリガーされた
- ジョブが作成された
- 関数が実行を終了した

各ファイルに対して create_DLP_job 関数が完了すると、対応する DLP ジョブが開始されます。DLP ジョブページに移動して、キュー内の DLP ジョブのリストを表示します。
保留中、実行中、完了のジョブのリストが表示されます。それぞれが、アップロードしたファイルのいずれかに対応しています。

これらのジョブの ID をクリックすると、詳細が表示されます。
Cloud Functions ページに戻って resolve_DLP 関数のログを確認すると、各ファイルに少なくとも 8 つのエントリが表示されます。これは、次のことを示しています。
- 関数の実行が開始されました
- Pub/Sub 通知を受信しました
- 対応する DLP ジョブの名前
- ステータス コード
- 機密データのインスタンス数(存在する場合)
- ファイルの移動先となるバケット
- DLP ジョブがファイルの解析を完了しました
- 関数が実行を終了した

resolve_DLP 関数へのすべての呼び出しが完了したら、検疫バケットの内容をもう一度確認します。
gsutil ls gs://[YOUR_QUARANTINE_BUCKET]
今回は完全に空になっているはずです。ただし、他のバケットに対して上記の同じコマンドを実行すると、ファイルが対応するバケットに完全に分離されていることがわかります。
7. クリーンアップ
DLP API と Cloud Functions を組み合わせてデータを分類する方法を確認したので、作成したすべてのリソースをプロジェクトから削除しましょう。
プロジェクトを削除する
必要に応じて、プロジェクト全体を削除することもできます。GCP Console で、[Cloud Resource Manager] ページに移動します。
プロジェクト リストで、目的のプロジェクトを選択し、[削除] をクリックします。プロジェクト ID を入力するように求められます。入力して [シャットダウン] をクリックします。
別の方法として、gcloud を使用してプロジェクト全体を Cloud Shell から直接削除することもできます。
gcloud projects delete [PROJECT_ID]
さまざまなコンポーネントを 1 つずつ削除する場合は、次のセクションに進んでください。
Cloud Functions
gcloud を使用して両方の Cloud Functions を削除します。
gcloud functions delete -q create_DLP_job && gcloud functions delete -q resolve_DLP
ストレージ バケット
アップロードしたすべてのファイルを削除し、gsutil でバケットを削除します。
gsutil rm -r gs://[YOUR_QUARANTINE_BUCKET] \ gs://[YOUR_SENSITIVE_DATA_BUCKET] \ gs://[YOUR_NON_SENSITIVE_DATA_BUCKET]
Pub/Sub
まず、gcloud を使用して Pub/Sub サブスクリプションを削除します。
gcloud pubsub subscriptions delete classify-sub
最後に、gcloud で Pub/Sub トピックを削除します。
gcloud pubsub topics delete classify-topic
8. 完了
おめでとうございます。これで完了です。DLP API と Cloud Functions を使用してファイルの分類を自動化する方法を学びました。
学習した内容
- 機密データと機密情報でないデータを保存するために Cloud Storage バケットを作成しました。
- クラウド関数をトリガーする Pub/Sub トピックとサブスクリプションを作成しました。
- ファイルに含まれる機密データに基づいてファイルを分類する DLP ジョブを開始するように設計された Cloud Functions を作成しました。
- テストデータをアップロードし、Cloud Functions の Stackdriver ログをチェックして、プロセスが動作していることを確認しました。