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

1. 概要

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

この Codelab では、Confidential Space を使用して、ある企業が独自の ML モデルを、そのモデルを使用する別の企業と安全に共有できるようにします。具体的には、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. Workload Identity プールのポリシーを構成して、信頼できないオペレーターから ML モデルを保護する

Secundus Company が運営し、以下の作業に責任を負います。

  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. クラウド リソースの設定

始める前に

  • 以下のコマンドを使用して このリポジトリのクローンを作成し、この Codelab に必要なスクリプトを取得します。
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>
  • プロジェクトに対する課金を有効にします
  • 両方のプロジェクトで 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 が使用する Primus サービス アカウント(この Codelab の ML モデル)。このステップでは、$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 Console を使用して IAM ロールを付与する方法については、こちらのガイドをご覧ください。
  • $PRIMUS_PROJECT_ID には、ストレージ管理者、Artifact Registry 管理者、サービス アカウント管理者、IAM Workload Identity プール管理者が必要です。
  • $SECUNDUS_PROJECT_ID には、Compute 管理者、ストレージ管理者、サービス アカウント管理者、IAM Workload Identity プール管理者、セキュリティ管理者(省略可)が必要です。
  • 次のスクリプトを実行して、残りの変数名を、リソース名のプロジェクト ID に基づく値に設定します。
source config_env.sh

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

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

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

このクラウド リソースの設定の一環として、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 Company のリソースを設定する

このステップの一環として、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 で使用するワークロードは ML の Python コードです。このコードは、Primus のストレージ バケットに保存されている ML モデルにアクセスし、ストレージ バケットに保存されているサンプル画像で推論を実行します。

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 モデルの整合性を確保できることです。これにより、ワークロードで異なるバージョンの ML モデルが使用されることが予想される場合、ワークロード オペレーターはワークロード イメージまたはそのパラメータも更新する必要があります。

4. ワークロードの承認と実行

ワークロードの承認

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

  • 内容: 検証されたコード
  • 場所: 安全な環境
  • Who: 信頼できるオペレーター

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

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=$(docker images digests ${PRIMUS_PROJECT_REPOSITORY_REGION}-docker.pkg.dev/${PRIMUS_PROJECT_ID}/${PRIMUS_ARTIFACT_REPOSITORY}/${WORKLOAD_IMAGE_NAME}:${WORKLOAD_IMAGE_TAG}| awk 'NR>1{ print $3 }')
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 config set project $SECUNDUS_PROJECT_ID
gcloud compute instances create ${WORKLOAD_VM} \
 --confidential-compute-type=SEV \
 --shielded-secure-boot \
 --maintenance-policy=TERMINATE \
 --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 インスタンスを削除してから、ワークロードを再度実行してみてください。

新しい Docker イメージが Secundus の Artifact Registry(us-docker.pkg.dev/${SECUNDUS_PROJECT_ID}/custom-image/${WORKLOAD_IMAGE_NAME}:${WORKLOAD_IMAGE_TAG} として)で公開されていて、ワークロード サービス アカウント($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 VMs インスタンスを削除します。
gcloud compute instances delete ${WORKLOAD_VM}

未承認のワークロードを実行します。

gcloud compute instances create ${WORKLOAD_VM} \
 --confidential-compute-type=SEV \
 --shielded-secure-boot \
 --maintenance-policy=TERMINATE \
 --scopes=cloud-platform --zone=${SECUNDUS_PROJECT_ZONE} \
 --image-project=confidential-space-images \
 --image-family=confidential-space \ 
--service-account=${WORKLOAD_SERVICE_ACCOUNT}@${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 コンソールに移動します。
  • シャットダウンするプロジェクトを選択し、[削除] をクリックしますプロジェクトの削除がスケジュールされます。

次のステップ

以下の類似の Codelab をご確認ください。