Confidential Space を使用して ML モデルと知的財産を保護する

1. 概要

Confidential Space は、複数の関係者間のコラボレーションのための安全な環境を提供します。この Codelab では、Confidential Space を使用して、機械学習モデルなどの機密性の高い知的財産を保護する方法について説明します。

この Codelab では、Confidential Space を使用して、ある企業が自社の独自 ML モデルを、そのモデルを使用したい別の企業と安全に共有できるようにします。具体的には、Primus 社は、Confidential Space で実行されるワークロードにのみリリースされる機械学習モデルを所有しており、Primus 社は知的財産を完全に管理できます。Secundus 社はワークロード オペレーターとなり、Confidential Space で ML ワークロードを実行します。Secundus 社はこのモデルをロードし、Secundus 社が所有するサンプルデータを使用して推論を実行します。

ここで、Primus 社はワークロード コードを作成するワークロード作成者であり、信頼できないワークロード オペレーターである Secundus 社から知的財産を保護したい共同作業者です。Secundus 社は、ML ワークロードのワークロード オペレーターです。

5a86c47d935da998.jpeg

学習内容

  • 知的財産を管理しながら、ある企業が自社の独自 ML モデルを別の企業と共有できる環境を構成する方法。

必要なもの

Confidential Space の設定に関わるロール

この Codelab では、Primus 社がリソース所有者とワークロード作成者となり、次のことを行います。

  1. ML モデルを使用して必要なクラウド リソースを設定する
  2. ワークロード コードを記述する
  3. ワークロード イメージを公開する
  4. 信頼できないオペレーターから ML モデルを保護するように Workload Identity プール ポリシーを構成する

Secundus 社はオペレーターとなり、次のことを行います。

  1. ワークロードと結果で使用されるサンプル画像を保存するために必要なクラウド リソースを設定する
  2. Primus 社が提供するモデルを使用して、Confidential Space で ML ワークロードを実行する

Confidential Space の仕組み

Confidential Space でワークロードを実行すると、構成されたリソースを使用して次のプロセスが行われます。

  1. ワークロードは、 $PRIMUS_SERVICEACCOUNT の一般的な Google アクセス トークンを Workload Identity プール からリクエストします。ワークロードと環境のクレームを含む Attestation Verifier サービス トークンを提供します。
  2. Attestation Verifier サービス トークンのワークロード測定クレームが WIP の属性条件と一致する場合、 $PRIMUS_SERVICEACCOUNT. のアクセス トークンが返されます。
  3. ワークロードは、$PRIMUS_SERVICEACCOUNT に関連付けられたサービス アカウント アクセス トークンを使用して、$PRIMUS_INPUT_STORAGE_BUCKET バケットに保存されている ML モデルにアクセスします。
  4. ワークロードは、Secundus 社が所有するデータに対してオペレーションを実行します。このワークロードは、Secundus 社のプロジェクトで Secundus 社によって運用および実行されます。
  5. ワークロードは $WORKLOAD_SERVICEACCOUNT サービス アカウントを使用して、そのオペレーションの結果を $SECUNDUS_RESULT_STORAGE_BUCKET バケットに書き込みます。

2. Cloud リソースを設定する

始める前に

git clone https://github.com/GoogleCloudPlatform/confidential-space.git
  • この Codelab のディレクトリを変更します。
cd confidential-space/codelabs/ml_model_protection/scripts
  • 以下に示すように、必要なプロジェクト環境変数が設定されていることを確認します。GCP プロジェクトの設定の詳細については、 この Codelab をご覧ください。プロジェクト ID の取得方法と、プロジェクト名やプロジェクト番号との違いについては、こちらをご覧ください。
export PRIMUS_PROJECT_ID=<GCP project id of Primus>
export SECUNDUS_PROJECT_ID=<GCP project id of Secundus>
gcloud services enable \
    cloudapis.googleapis.com \
    cloudresourcemanager.googleapis.com \
    cloudshell.googleapis.com \
    container.googleapis.com \
    containerregistry.googleapis.com \
    iam.googleapis.com \
    confidentialcomputing.googleapis.com
  • 次のコマンドを使用して、上記で指定したリソース名の変数に値を割り当てます。これらの変数を使用すると、必要に応じてリソース名をカスタマイズできます。また、既存のリソースが作成されている場合は、そのリソースを使用することもできます。(例: export PRIMUS_INPUT_STORAGE_BUCKET='my-input-bucket'
  1. Primus プロジェクトの既存のクラウド リソース名を使用して、次の変数を設定できます。変数が設定されている場合は、Primus プロジェクトの対応する既存のクラウド リソースが使用されます。変数が設定されていない場合、クラウド リソース名はプロジェクト名から生成され、その名前で新しいクラウド リソースが作成されます。リソース名でサポートされている変数は次のとおりです。

$PRIMUS_INPUT_STORAGE_BUCKET

Primus の ML モデルを保存するバケット。

$PRIMUS_WORKLOAD_IDENTITY_POOL

クレームを検証する Primus の Workload Identity プール(WIP)。

$PRIMUS_WIP_PROVIDER

Attestation Verifier サービスによって署名されたトークンに使用する認可条件を含む、Primus の Workload Identity プール プロバイダ。

$PRIMUS_SERVICE_ACCOUNT

$PRIMUS_WORKLOAD_IDENTITY_POOL が保護されたリソース(この Codelab の ML モデル)にアクセスするために使用する Primus サービス アカウント。このステップでは、$PRIMUS_INPUT_STORAGE_BUCKET バケットに保存されている機械学習モデルを読み取る権限があります。

$PRIMUS_ARTIFACT_REPOSITORY

ワークロード Docker イメージが push されるアーティファクト リポジトリ。

  1. Secundus プロジェクトの既存のクラウド リソース名を使用して、次の変数を設定できます。変数が設定されている場合は、Secundus プロジェクトの対応する既存のクラウド リソースが使用されます。変数が設定されていない場合、クラウド リソース名はプロジェクト名から生成され、その名前で新しいクラウド リソースが作成されます。リソース名でサポートされている変数は次のとおりです。

$SECUNDUS_INPUT_STORAGE_BUCKET

Primus が提供するモデルを使用して Secundus が分類するサンプル画像を保存するバケット。

$SECUNDUS_RESULT_STORAGE_BUCKET

ワークロードの結果を保存するバケット。

$WORKLOAD_IMAGE_NAME

ワークロード コンテナ イメージの名前。

$WORKLOAD_IMAGE_TAG

ワークロード コンテナ イメージのタグ。

$WORKLOAD_SERVICE_ACCOUNT

ワークロードを実行する Confidential VM にアクセスする権限を持つサービス アカウント。

  • これらの 2 つのプロジェクトには特定の権限が必要です。GCP コンソールを使用して IAM ロールを付与する方法については、こちらのガイドをご覧ください。
  • $PRIMUS_PROJECT_ID の場合は、ストレージ管理者、Artifact Registry 管理者、サービス アカウント管理者、IAM Workload Identity プール管理者が必要です。
  • $SECUNDUS_PROJECT_ID の場合は、Compute 管理者、ストレージ管理者、サービス アカウント管理者、IAM Workload Identity プール管理者、セキュリティ管理者(省略可)が必要です。
  • 次の スクリプト を実行して、残りの変数名をリソース名のプロジェクト ID に基づく値に設定します。
source config_env.sh

Primus 社のリソースを設定する

このステップでは、Primus に必要なクラウド リソースを設定します。次の スクリプト を実行して、Primus のリソースを設定します。スクリプトの実行時に次のリソースが作成されます。

  • Primus の ML モデルを保存する Cloud Storage バケット($PRIMUS_INPUT_STORAGE_BUCKET)。
  • プロバイダで構成された属性条件に基づいてクレームを検証する Workload Identity プール($PRIMUS_WORKLOAD_IDENTITY_POOL)。
  • 上記の Workload Identity プール($PRIMUS_WORKLOAD_IDENTITY_POOL)に接続されたサービス アカウント($PRIMUS_SERVICEACCOUNT)。Cloud Storage バケットからデータを読み取る IAM アクセス権(objectViewer ロールを使用)と、このサービス アカウントを Workload Identity プールに接続する IAM アクセス権(roles/iam.workloadIdentityUser ロールを使用)。

このクラウド リソースの設定では、TensorFlow モデルを使用します。モデルのアーキテクチャ、重み、トレーニング構成を含むモデル全体を ZIP アーカイブに保存できます。この Codelab では、こちらにある ImageNet データセットでトレーニングされた MobileNet V1 モデルを使用します。

./setup_primus_company_resources.sh

上記のスクリプトでクラウド リソースを設定したら、モデルをダウンロードして、スクリプトで作成した Cloud Storage バケットに公開します。

  1. こちらから事前トレーニング済みのモデルをダウンロードします。
  2. ダウンロードしたら、ダウンロードした tar ファイルの名前を model.tar.gz に変更します。
  3. model.tar.gz ファイルを含むディレクトリから次のコマンドを使用して、 model.tar.gz ファイルを Cloud Storage バケットに公開します。
gsutil cp model.tar.gz gs://${PRIMUS_INPUT_STORAGE_BUCKET}/

Secundus 社のリソースを設定する

このステップでは、Secundus に必要なクラウド リソースを設定します。次の スクリプト を実行して、Secundus のリソースを設定します。このステップでは、次のリソースが作成されます。

  • Secundus が推論を実行するためのサンプル画像を保存する Cloud Storage バケット($SECUNDUS_INPUT_STORAGE_BUCKET)。
  • Secundus による ML ワークロードの実行結果を保存する Cloud Storage バケット($SECUNDUS_RESULT_STORAGE_BUCKET)。

この Codelab では、サンプル画像の一部を こちらで入手できます。

./setup_secundus_company_resources.sh

3. ワークロードを作成する

ワークロード サービス アカウントを作成する

次に、必要なロールと権限を持つワークロードのサービス アカウントを作成します。次の スクリプト を実行して、Secundus プロジェクトにワークロード サービス アカウントを作成します。このサービス アカウントは、ML ワークロードを実行する VM で使用されます。

このワークロード サービス アカウント($WORKLOAD_SERVICEACCOUNT)には次のロールがあります。

  • confidentialcomputing.workloadUser を使用して証明書トークンを取得する。
  • logging.logWriter を使用して Cloud Logging にログを書き込む。
  • objectViewer を使用して $SECUNDUS_INPUT_STORAGE_BUCKET Cloud Storage バケットからデータを読み取る。
  • objectUser を使用して、ワークロードの結果を $SECUNDUS_RESULT_STORAGE_BUCKET Cloud Storage バケットに書き込む。
./create_workload_service_account.sh

ワークロードを作成する

このステップでは、ワークロード Docker イメージを作成します。ワークロードは Primus によって作成されます。この Codelab で使用するワークロードは、Primus のストレージ バケットに保存されている ML モデルにアクセスし、ストレージ バケットに保存されているサンプル画像を使用して推論を実行する ML Python コードです。

Primus のストレージ バケットに保存されている ML モデルには、必要な属性条件を満たすワークロードのみがアクセスできます。これらの属性条件については、ワークロードの承認に関する次のセクションで詳しく説明します。

この Codelab で作成して使用するワークロードの run_inference() メソッドを次に示します。ワークロード コード全体はこちらで確認できます。

def run_inference(image_path, model):
  try:
    # Read and preprocess the image
    image = tf.image.decode_image(tf.io.read_file(image_path), channels=3)
    image = tf.image.resize(image, (128, 128))
    image = tf.image.convert_image_dtype(image, tf.float32)
    image = tf.expand_dims(image, axis=0)

    # Get predictions from the model
    predictions = model(image)
    predicted_class = np.argmax(predictions)

    top_k = 5
    top_indices = np.argsort(predictions[0])[-top_k:][::-1]

    # Convert top_indices to a TensorFlow tensor
    top_indices_tensor = tf.convert_to_tensor(top_indices, dtype=tf.int32)

    # Use TensorFlow tensor for indexing
    top_scores = tf.gather(predictions[0], top_indices_tensor)

    return {
        "predicted_class": int(predicted_class),
        "top_k_predictions": [
            {"class_index": int(idx), "score": float(score)}
            for idx, score in zip(top_indices, top_scores)
        ],
    }
  except Exception as e:
    return {"error": str(e)}

次の スクリプト を実行して、次の手順が実行されるワークロードを作成します。

  • Primus が所有する Artifact Registry($PRIMUS_ARTIFACT_REGISTRY)を作成します。
  • 必要なリソース名でワークロード コードを更新します。
  • ML ワークロードをビルドし、ワークロード コードの Docker イメージをビルドするための Dockerfile を作成します。 この Codelab で使用する Dockerfile を次に示します。
  • Docker イメージをビルドして、Primus が所有する Artifact Registry($PRIMUS_ARTIFACT_REGISTRY)に公開します。
  • $PRIMUS_ARTIFACT_REGISTRY の読み取り権限を $WORKLOAD_SERVICEACCOUNT に付与します。これは、ワークロード コンテナが Artifact Registry からワークロード Docker イメージを pull するために必要です。
./create_workload.sh

また、ワークロードを使用する前にモデルのハッシュまたは署名を確認することで、想定されるバージョンの ML モデルがロードされるようにワークロードをコーディングすることもできます。このような追加のチェックを行うことで、ML モデルの整合性を確保できます。これにより、ワークロードが異なるバージョンの ML モデルを使用することが想定される場合、ワークロード オペレーターはワークロード イメージまたはそのパラメータを更新する必要があります。

4. ワークロードを承認して実行する

ワークロードを承認する

Primus は、次のリソースの属性に基づいて ML モデルにアクセスするワークロードを承認したいと考えています。

  • 内容: 検証済みのコード
  • 場所: 安全な環境
  • ユーザー: 信頼できるオペレーター

Primus は Workload Identity 連携 を使用して、これらの要件に基づくアクセス ポリシーを適用します。Workload Identity 連携を使用すると、属性条件を指定できます。これらの条件により、Workload Identity プール(WIP)で認証できる ID が制限されます。Attestation Verifier サービスを Workload Identity プール プロバイダとして WIP に追加して、測定値を提示し、ポリシーを適用できます。

Workload Identity プールは、クラウド リソースの設定ステップで作成済みです。次に、Primus は新しい OIDC Workload Identity プール プロバイダを作成します。指定された --attribute-condition により、ワークロード コンテナへのアクセスが承認されます。この構成では、次のものが必要になります。

  • 内容: $PRIMUS_ARTIFACT_REPOSITORY リポジトリにアップロードされた最新の $WORKLOAD_IMAGE_NAME
  • 場所: Confidential Space の高信頼実行環境は、完全にサポートされている Confidential Space VM イメージで実行されています。
  • ユーザー: Secundus $WORKLOAD_SERVICE_ACCOUNT サービス アカウント。
export WORKLOAD_IMAGE_DIGEST=$(gcloud artifacts docker images describe ${PRIMUS_PROJECT_REPOSITORY_REGION}-docker.pkg.dev/$PRIMUS_PROJECT_ID/$PRIMUS_ARTIFACT_REPOSITORY/$WORKLOAD_IMAGE_NAME:$WORKLOAD_IMAGE_TAG  --format="value(image_summary.digest)" --project ${PRIMUS_PROJECT_ID})
gcloud config set project $PRIMUS_PROJECT_ID
gcloud iam workload-identity-pools providers create-oidc $PRIMUS_WIP_PROVIDER \
  --location="global" \
  --workload-identity-pool="$PRIMUS_WORKLOAD_IDENTITY_POOL" \
  --issuer-uri="https://confidentialcomputing.googleapis.com/" \
  --allowed-audiences="https://sts.googleapis.com" \
  --attribute-mapping="google.subject='assertion.sub'" \
  --attribute-condition="assertion.swname == 'CONFIDENTIAL_SPACE' &&
'STABLE' in assertion.submods.confidential_space.support_attributes &&
assertion.submods.container.image_digest == '${WORKLOAD_IMAGE_DIGEST}' &&
 assertion.submods.container.image_reference == '${PRIMUS_PROJECT_REPOSITORY_REGION}-docker.pkg.dev/$PRIMUS_PROJECT_ID/$PRIMUS_ARTIFACT_REPOSITORY/$WORKLOAD_IMAGE_NAME:$WORKLOAD_IMAGE_TAG' &&
'$WORKLOAD_SERVICEACCOUNT@$SECUNDUS_PROJECT_ID.iam.gserviceaccount.com' in assertion.google_service_accounts"

ワークロードを実行する

このステップでは、Confidential Space VM でワークロードを実行します。必要な TEE 引数は、 メタデータ フラグを使用して渡されます。ワークロード コンテナの引数は、フラグの "tee-cmd" 部分を使用して渡されます。ワークロードの実行結果は $SECUNDUS_RESULT_STORAGE_BUCKET に公開されます。

gcloud compute instances create ${WORKLOAD_VM} \
 --confidential-compute-type=SEV \
 --shielded-secure-boot \
 --project=${SECUNDUS_PROJECT_ID} \
 --maintenance-policy=MIGRATE \
 --scopes=cloud-platform --zone=${SECUNDUS_PROJECT_ZONE} \
 --image-project=confidential-space-images \
 --image-family=confidential-space \
 --service-account=${WORKLOAD_SERVICEACCOUNT}@${SECUNDUS_PROJECT_ID}.iam.gserviceaccount.com \
 --metadata  ^~^tee-image-reference=${PRIMUS_PROJECT_REPOSITORY_REGION}-docker.pkg.dev/${PRIMUS_PROJECT_ID}/${PRIMUS_ARTIFACT_REPOSITORY}/${WORKLOAD_IMAGE_NAME}:${WORKLOAD_IMAGE_TAG}

結果を表示

ワークロードが正常に完了すると、ML ワークロードの結果が $SECUNDUS_RESULT_STORAGE_BUCKET に公開されます。

gsutil cat gs://$SECUNDUS_RESULT_STORAGE_BUCKET/result

サンプル画像の推論結果の例を次に示します。

Image: sample_image_1.jpeg, Response: {'predicted_class': 531, 'top_k_predictions': [{'class_index': 531, 'score': 12.08437442779541}, {'class_index': 812, 'score': 10.269512176513672}, {'class_index': 557, 'score': 9.202644348144531}, {'class_index': 782, 'score': 9.08737564086914}, {'class_index': 828, 'score': 8.912498474121094}]}

Image: sample_image_2.jpeg, Response: {'predicted_class': 905, 'top_k_predictions': [{'class_index': 905, 'score': 9.53619384765625}, {'class_index': 557, 'score': 7.928380966186523}, {'class_index': 783, 'score': 7.70129919052124}, {'class_index': 531, 'score': 7.611623287200928}, {'class_index': 906, 'score': 7.021416187286377}]}

Image: sample_image_3.jpeg, Response: {'predicted_class': 905, 'top_k_predictions': [{'class_index': 905, 'score': 6.09878396987915}, {'class_index': 447, 'score': 5.992854118347168}, {'class_index': 444, 'score': 5.9582319259643555}, {'class_index': 816, 'score': 5.502010345458984}, {'class_index': 796, 'score': 5.450454235076904}]}

Secundus ストレージ バケット内のサンプル画像ごとに、結果にエントリが表示されます。このエントリには、次の 2 つの重要な情報が含まれます。

  • predicted_class のインデックス: これは、モデルが画像を分類するクラスを表す数値インデックスです。
  • Top_k_predictions: 画像の予測を最大 k 個提供します。可能性の高い順に並べられます。この Codelab では k の値は 5 に設定されていますが、ワークロード コードで調整して、予測数を増減できます。

クラス インデックスを人間が読める形式のクラス名に変換するには、こちらで入手できるラベルのリストを参照してください。たとえば、クラス インデックスが 2 の場合は、ラベルリストのクラスラベル「tench」に対応します。

この Codelab では、TEE で実行されるワークロードにのみリリースされる Primus が所有するモデルについて説明しました。Secundus は TEE で ML ワークロードを実行します。このワークロードは Primus が所有するモデルを使用できますが、Primus はモデルを完全に管理できます。

承認されていないワークロードを実行する

Secundus は、Primus によって承認されていない独自のアーティファクト リポジトリから別のワークロード イメージを pull して、ワークロード イメージを変更します。Primus の Workload Identity プールは、${PRIMUS_PROJECT_REPOSITORY_REGION}-docker.pkg.dev/$PRIMUS_PROJECT_ID/$PRIMUS_ARTIFACT_REPOSITORY/$WORKLOAD_IMAGE_NAME:$WORKLOAD_IMAGE_TAG ワークロード イメージのみを承認しています。

ワークロードを再実行する

Secundus がこの新しいワークロード イメージで元のワークロードを実行しようとすると、失敗します。エラーを表示するには、元の結果ファイルと VM インスタンスを削除してから、ワークロードを再度実行します。

Secundus の Artifact Registry(us-docker.pkg.dev/${SECUNDUS_PROJECT_ID}/custom-image/${WORKLOAD_IMAGE_NAME}:${WORKLOAD_IMAGE_TAG})に新しい Docker イメージが公開され、ワークロード サービス アカウント($WORKLOAD_SERVICEACCOUNT)にこの新しいワークロード イメージを読み取るための Artifact Registry の読み取り権限が付与されていることを確認してください。これは、ワークロードが提示したトークンが Primus の WIP ポリシーによって拒否される前に、ワークロードが終了しないようにするためです。

既存の結果ファイルと VM インスタンスを削除する

  1. プロジェクトを $SECUNDUS_PROJECT_ID プロジェクトに設定します。
gcloud config set project $SECUNDUS_PROJECT_ID
  1. 結果ファイルを削除します。
gsutil rm gs://$SECUNDUS_RESULT_STORAGE_BUCKET/result
  1. Confidential VM インスタンスを削除します。
gcloud compute instances delete ${WORKLOAD_VM} --zone=${SECUNDUS_PROJECT_ZONE}

承認されていないワークロードを実行します。

gcloud compute instances create ${WORKLOAD_VM} \
 --confidential-compute-type=SEV \
 --shielded-secure-boot \
 --maintenance-policy=MIGRATE \
 --scopes=cloud-platform --zone=${SECUNDUS_PROJECT_ZONE} \
 --image-project=confidential-space-images \
 --image-family=confidential-space \
 --service-account=${WORKLOAD_SERVICEACCOUNT}@${SECUNDUS_PROJECT_ID}.iam.gserviceaccount.com \
 --metadata  ^~^tee-image-reference=us-docker.pkg.dev/${SECUNDUS_PROJECT_ID}/custom-image/${WORKLOAD_IMAGE_NAME}:${WORKLOAD_IMAGE_TAG}

エラーを表示

ワークロードの結果ではなく、エラー(The given credential is rejected by the attribute condition)が表示されます。

gsutil cat gs://$SECUNDUS_RESULT_STORAGE_BUCKET/result

5. クリーンアップ

この Codelab で作成したリソースをクリーンアップするために使用できるスクリプトを次に示します。このクリーンアップでは、次のリソースが削除されます。

  • Primus の入力ストレージ バケット($PRIMUS_INPUT_STORAGE_BUCKET))。
  • Primus サービス アカウント($PRIMUS_SERVICEACCOUNT)。
  • Primus のアーティファクト リポジトリ($PRIMUS_ARTIFACT_REPOSITORY)。
  • Primus Workload Identity プール($PRIMUS_WORKLOAD_IDENTITY_POOL)。
  • Secundus のワークロード サービス アカウント($WORKLOAD_SERVICEACCOUNT)。
  • Secundus の入力ストレージ バケット($SECUNDUS_INPUT_STORAGE_BUCKET)
  • ワークロード コンピューティング インスタンス。
  • Secundus の結果ストレージ バケット($SECUNDUS_RESULT_STORAGE_BUCKET)。
$ ./cleanup.sh

探索が完了したら、プロジェクトの削除を検討してください。

  • Cloud Platform Console に移動します。
  • シャットダウンするプロジェクトを選択し、上部の [削除] をクリックします。これにより、プロジェクトの削除がスケジュールされます。

次のステップ

次の Codelab もご覧ください。