使用機密空間保護機器學習模型和智慧財產

1. 總覽

Confidential Space 提供安全的環境,讓多方安全地進行協作。本程式碼研究室將示範如何使用機密空間保護機密智慧財產,例如機器學習模型。

在本程式碼研究室中,您將使用機密空間,讓一家公司可安全地將自有機器學習模型,分享給想要使用該模型的其他公司。具體來說,Primus 公司有一個機器學習模型,只會發布給在機密空間中執行的工作負載,讓 Primus 能完全掌控自己的智慧財產。公司 Secundus 將擔任工作負載操作員,並在機密空間中執行機器學習工作負載。Secundus 會載入這個模型,並使用 Secundus 擁有的樣本資料執行推論。

在此例中,Primus 是工作負載作者,負責編寫工作負載程式碼,也是希望保護智慧財產不受不信任工作負載操作員 Secundus 影響的協作者。Secundus 是機器學習工作負載的工作負載運算子。

5a86c47d935da998.jpeg

課程內容

  • 如何設定環境,讓一方可以與另一方分享專屬機器學習模型,同時保有智慧財產權。

軟硬體需求

機密聊天室設定中涉及的角色

在本程式碼研究室中,Primus 公司將擔任資源擁有者和工作負載作者,負責執行下列工作:

  1. 使用機器學習模型設定必要的雲端資源
  2. 編寫工作負載程式碼
  3. 發布工作負載映像檔
  4. 設定 Workload Identity Pool 政策,保護機器學習模型免受不受信任的操作員攻擊

Secundus Company 將擔任營運商,負責下列事項:

  1. 設定必要的雲端資源,用於儲存工作負載使用的範例圖片和結果
  2. 使用 Primus 提供的模型,在 Confidential Space 中執行機器學習工作負載

機密空間的運作方式

在機密空間中執行工作負載時,系統會使用已設定的資源執行下列程序:

  1. 工作負載會向 Workload Identity 集區要求 $PRIMUS_SERVICEACCOUNT 的一般 Google 存取權權杖。這項服務會提供具有工作負載和環境宣告的 Attestation Verifier 服務權杖。
  2. 如果 Attestation Verifier 服務權杖中的負載量評估宣稱符合 WIP 中的屬性條件,則會傳回 $PRIMUS_SERVICEACCOUNT. 的存取權杖。
  3. 工作負載會使用與 $PRIMUS_SERVICEACCOUNT 相關聯的服務帳戶存取權杖,存取儲存在 $PRIMUS_INPUT_STORAGE_BUCKET 值區中的機器學習模型。
  4. 工作負載會對 Secundus 擁有的資料執行作業,而該工作負載會由 Secundus 在專案中運作及執行。
  5. 工作負載會使用 $WORKLOAD_SERVICEACCOUNT 服務帳戶,將該作業的結果寫入 $SECUNDUS_RESULT_STORAGE_BUCKET 值區。

2. 設定雲端資源

事前準備

  • 使用下列指令複製 這個存放區,取得本程式碼研究室所需的指令碼。
git clone https://github.com/GoogleCloudPlatform/confidential-space.git
  • 變更本程式碼研究室的目錄。
cd confidential-space/codelabs/ml_model_protection/scripts
  • 請確認您已設定必要的專案環境變數,如下所示。如要進一步瞭解如何設定 GCP 專案,請參閱 這個程式碼研究室。您可以參閱這篇文章,進一步瞭解如何擷取專案 ID,以及專案 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 機器學習模型的儲存桶。

$PRIMUS_WORKLOAD_IDENTITY_POOL

驗證要求的 Primus 工作負載身分集區 (WIP)。

$PRIMUS_WIP_PROVIDER

Primus 的工作負載身分集區提供者,其中包含授權條件,可用於由認證驗證服務簽署的權杖。

$PRIMUS_SERVICE_ACCOUNT

$PRIMUS_WORKLOAD_IDENTITY_POOL 用來存取受保護資源 (本程式碼研究室中的 ML 模型) 的 Primus 服務帳戶。在此步驟中,它有權讀取儲存在 $PRIMUS_INPUT_STORAGE_BUCKET 值區中的機器學習模型。

$PRIMUS_ARTIFACT_REPOSITORY

工作負載 Docker 映像檔將推送至的構件存放區。

  1. 您可以使用 Secundus 專案中現有的雲端資源名稱設定下列變數。如果變數已設定,系統就會使用 Secundus 專案中對應的現有雲端資源。如果未設定變數,系統會根據專案名稱產生雲端資源名稱,並以該名稱建立新的雲端資源。以下是支援的資源名稱變數:

$SECUNDUS_INPUT_STORAGE_BUCKET

儲存 Secundus 想使用 Primus 提供的模型分類的樣本圖片的儲存體。

$SECUNDUS_RESULT_STORAGE_BUCKET

用來儲存工作負載結果的值區。

$WORKLOAD_IMAGE_NAME

工作負載容器映像檔的名稱。

$WORKLOAD_IMAGE_TAG

工作負載容器映像檔的標記。

$WORKLOAD_SERVICE_ACCOUNT

服務帳戶具備執行工作負載的機密 VM 存取權。

  • 您需要為這兩個專案取得特定權限,請參閱這份指南,瞭解如何使用 GCP 主控台授予 IAM 角色:
  • 如要使用 $PRIMUS_PROJECT_ID,您需要具備「儲存空間管理員」、「Artifact Registry 管理員」、「服務帳戶管理員」和「身分與存取權管理 Workload Identity 集區管理員」角色。
  • 對於 $SECUNDUS_PROJECT_ID,您需要 Compute 管理員、儲存空間管理員、服務帳戶管理員、IAM Workload Identity 集區管理員、安全性管理員 (選用)。
  • 執行下列指令碼,將其餘變數名稱設為資源名稱的值,並根據專案 ID 進行設定。
source config_env.sh

設定 Primus 公司資源

在這個步驟中,您將為 Primus 設定必要的雲端資源。執行下列指令碼,為 Primus 設定資源。以下資源會在指令碼執行時建立:

  • Cloud Storage 值區 ($PRIMUS_INPUT_STORAGE_BUCKET),用於儲存 Primus 的機器學習模型。
  • Workload Identity 集區 ($PRIMUS_WORKLOAD_IDENTITY_POOL) 可根據提供者設定的屬性條件驗證要求。
  • 服務帳戶 ($PRIMUS_SERVICEACCOUNT) 已連結至上述工作負載身分集區 ($PRIMUS_WORKLOAD_IDENTITY_POOL),並具備以下權限:從雲端儲存空間讀取資料 (使用 objectViewer 角色),以及將此服務帳戶連結至工作負載身分集區 (使用 roles/iam.workloadIdentityUser 角色)。

在這個雲端資源設定中,我們會使用 TensorFlow 模型。我們可以將包含模型架構、權重和訓練設定的整個模型儲存至 ZIP 封存檔。在本程式碼研究室中,我們會使用在 這裡的 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 設定資源。在這些步驟中,系統會建立下列資源:

  • Cloud Storage 值區 ($SECUNDUS_INPUT_STORAGE_BUCKET),用於儲存 Secundus 執行推論時所需的樣本圖片。
  • Cloud Storage 值區 ($SECUNDUS_RESULT_STORAGE_BUCKET),用於儲存 Secundus 執行機器學習工作負載的結果。

您可以在這裡取得本程式碼研究室的部分圖片範例。

./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 編寫。本程式碼研究室使用的負載是機器學習 Python 程式碼,可存取儲存在 Primus 儲存值區中的 ML 模型,並使用儲存在儲存值區中的範例圖片執行推論。

儲存在 Primus 儲存空間值區中的機器學習模型,只有符合必要屬性條件的情況下,才能由工作負載存取。下一節將進一步說明這些屬性條件,說明如何授權工作負載。

以下是本程式碼研究室中將建立及使用的負載的 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)。
  • 更新工作負載程式碼,加入必要的資源名稱。
  • 建構機器學習工作負載,並建立 Dockerfile,以便建構工作負載程式的 Docker 映像檔。這裡是本程式碼研究室使用的 Dockerfile。
  • 建構並發布 Docker 映像檔至 Primus 擁有的 Artifact Registry ($PRIMUS_ARTIFACT_REGISTRY)。
  • $WORKLOAD_SERVICEACCOUNT 的讀取權限授予 $PRIMUS_ARTIFACT_REGISTRY。這項設定是工作負載容器從 Artifact Registry 提取工作負載 Docker 映像檔所需。
./create_workload.sh

此外,您也可以編寫工作負載,在使用機器學習模型前先檢查模型的雜湊或簽章,確保系統載入的版本正確無誤。這類額外檢查的優點在於確保機器學習模型的完整性。因此,當工作負載預期使用不同版本的機器學習模型時,工作負載操作員也需要更新工作負載映像檔或其參數。

4. 授權及執行工作負載

授權工作負載

Primus 希望授權工作負載根據下列資源的屬性存取機器學習模型:

  • What:已驗證的程式碼
  • 地點:安全的環境
  • Who:可信任的運算子

Primus 會使用 Workload Identity 聯盟,根據這些需求強制執行存取權政策。您可以透過 Workload Identity 聯盟指定屬性條件。這些條件會限制哪些身分可以透過工作負載身分集區 (WIP) 進行驗證。您可以將認證驗證服務新增至 WIP,做為工作負載身分集區供應商,以呈現評估結果並強制執行政策。

在雲端資源設定步驟中,我們已先建立 Workload Identity 集區。Primus 會建立新的 OIDC 工作負載身分集區提供者。指定的 --attribute-condition 會授予工作負載容器的存取權。它需要:

  • 內容:最新的 $WORKLOAD_IMAGE_NAME 已上傳至 $PRIMUS_ARTIFACT_REPOSITORY 存放區。
  • 適用範圍:在完全支援的機密空間 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"

執行工作負載

在這個步驟中,我們會在機密空間 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 儲存空間值區中每個樣本圖片的項目。這個項目會包含兩項重要資訊:

  • predicted_class 的索引:這是代表模型預測圖片所屬類別的數字索引。
  • Top_k_predictions:這項屬性會提供最多 k 個圖片預測結果,並依可能性高低排序。本程式碼研究室中將 k 的值設為 5,但您可以在工作負載程式碼中調整該值,以取得更多或更少的預測結果。

如要將類別索引轉換為人類可讀的類別名稱,請參閱這裡提供的標籤清單。舉例來說,如果您看到的類別索引為 2,則對應的類別標籤為標籤清單中的「tench」。

在本程式碼研究室中,我們示範了 Primus 擁有的模型,該模型只會發布至在 TEE 中執行的工作負載。Secundus 會在 TEE 中執行機器學習工作負載,而這個工作負載可以使用 Primus 擁有的模型,同時 Primus 保留對模型的完整控制權。

執行未授權的工作負載

Secundus 會從自己的構件存放區 (未經 Primus 授權) 提取不同的工作負載映像檔,藉此變更工作負載映像檔。Primus 的工作負載身分集區僅授權 ${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 Reader 讀取這項新工作負載映像檔的權限。這可確保在 Primus 的 WIP 政策拒絕工作負載提供的權杖之前,工作負載不會結束。

刪除現有結果檔案和 VM 執行個體

  1. 將專案設為 $SECUNDUS_PROJECT_ID 專案。
gcloud config set project $SECUNDUS_PROJECT_ID
  1. 刪除結果檔案。
gsutil rm gs://$SECUNDUS_RESULT_STORAGE_BUCKET/result
  1. 刪除機密 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. 清除

這裡提供的程式碼可用於清除我們在本程式碼研究室中建立的資源。在本次清理作業中,系統會刪除下列資源:

  • Primus 的輸入儲存值區 ($PRIMUS_INPUT_STORAGE_BUCKET))。
  • Primus 服務帳戶 ($PRIMUS_SERVICEACCOUNT)。
  • Primus 的構件存放區 ($PRIMUS_ARTIFACT_REPOSITORY)。
  • Primus workload identity pool ($PRIMUS_WORKLOAD_IDENTITY_POOL)。
  • Secundus 的工作負載服務帳戶 ($WORKLOAD_SERVICEACCOUNT)。
  • 輸入 Secundus 的儲存值區 ($SECUNDUS_INPUT_STORAGE_BUCKET))。
  • 工作負載運算執行個體。
  • Secundus 的結果儲存空間值區 ($SECUNDUS_RESULT_STORAGE_BUCKET)。
$ ./cleanup.sh

如果您已完成探索,請考慮刪除專案。

  • 前往 Cloud Platform Console
  • 選取要關閉的專案,然後按一下頂端的「刪除」:這會排定專案的刪除作業

後續步驟

查看一些類似的程式碼研究室…