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

1. 概要

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

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

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

5a86c47d935da998.jpeg

学習内容

  • 一方の当事者が知的財産権を失うことなく、独自の ML モデルをもう一方の当事者と共有できる環境を構成する方法。

必要なもの

Confidential Space の設定に関連するロール

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

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

Secundus 社が事業者となり、以下の責任を負います。

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

Confidential Space の仕組み

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

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

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

始める前に

  • 次のコマンドを使用して このリポジトリのクローンを作成し、この Codelab で使用する必要なスクリプトを取得します。
git clone https://github.com/GoogleCloudPlatform/confidential-space.git
  • この Codelab のディレクトリを変更します。
cd confidential-space/codelabs/ml_model_protection/scripts
  • 以下に示すように、必要なプロジェクト環境変数が設定されていることを確認します。GCP プロジェクトの設定の詳細については、 こちらの Codelab をご覧ください。プロジェクト ID の取得方法と、プロジェクト ID とプロジェクト名、プロジェクト番号の違いについては、こちらをご覧ください。
export PRIMUS_PROJECT_ID=<GCP project id of Primus>
export SECUNDUS_PROJECT_ID=<GCP project id of Secundus>
  • プロジェクトの課金を有効にします
  • 両方のプロジェクトで Confidential Computing API と次の API を有効にします。
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 プロジェクトの対応する既存のクラウド リソースが使用されます。変数が設定されていない場合、クラウド リソース名は project-name から生成され、その名前で新しいクラウド リソースが作成されます。リソース名でサポートされている変数は次のとおりです。

$PRIMUS_INPUT_STORAGE_BUCKET

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

$PRIMUS_WORKLOAD_IDENTITY_POOL

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

$PRIMUS_WIP_PROVIDER

Primus の Workload Identity プール プロバイダ。構成には、構成証明検証サービスによって署名されたトークンに使用する認可条件が含まれています。

$PRIMUS_SERVICE_ACCOUNT

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

$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 バケットからデータを読み取る(objectViewer ロールを使用)と、このサービス アカウントを Workload Identity プールに接続する(roles/iam.workloadIdentityUser ロールを使用)ための IAM アクセス権があります。

このクラウド リソースの設定の一環として、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)に公開します。
  • $WORKLOAD_SERVICEACCOUNT$PRIMUS_ARTIFACT_REGISTRY の読み取り権限を付与します。これは、ワークロード コンテナが Artifact Registry からワークロード Docker イメージを pull するために必要です。
./create_workload.sh

また、ワークロードをコード化して、モデルを使用する前にモデルのハッシュまたは署名をチェックすることで、想定どおりのバージョンの ML モデルが読み込まれるようにすることもできます。このような追加チェックの利点は、機械学習モデルの完全性が保証されることです。これにより、ワークロードが異なるバージョンの ML モデルを使用することが予想される場合は、ワークロード オペレーターがワークロード イメージまたはそのパラメータを更新する必要もあります。

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

ワークロードを承認する

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

  • 内容: 確認済みのコード
  • Where: 安全な環境
  • Who: 信頼できるオペレーター

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

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

  • 内容: $PRIMUS_ARTIFACT_REPOSITORY リポジトリにアップロードされた最新の $WORKLOAD_IMAGE_NAME
  • 使用条件: Confidential Space 高信頼実行環境が、完全にサポートされている Confidential Space VM イメージで実行されている。
  • Who: 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 では、Primus が所有するモデルが TEE で実行されているワークロードにのみリリースされることを示しました。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 をご覧ください。