如何透過多方運算和 Confidential Space 進行數位資產交易

1. 總覽

在開始之前,雖然不是必要,但建議您先瞭解以下功能和概念,以利於完成本程式碼研究室。

4670cd5427aa39a6.png

課程內容

本實驗室提供參考實作項目,說明如何使用機密空間執行符合多方計算的區塊鏈簽署作業。為說明這些概念,我們將介紹以下情境:公司 Primus 想將數位資產轉移至公司 Secundus。在這個情況下,Primus 公司使用 MPC 相容的模型,也就是說,他們使用的是分散式金鑰共用項,而非個別的私密金鑰。這些金鑰分片由多方持有,在本例中為小莉和志明。這種做法可為 Primus 公司帶來多項優勢,包括簡化使用者體驗、提高作業效率,以及掌控私密金鑰。

為說明這個程序的基本面向,我們將詳細說明技術設定,並逐步引導您完成啟動數位資產從 Company Primus 轉移至 Company Secundus 的核准與簽署程序。請注意,Bob 和 Alice 都是 Primus 公司的員工,因此必須核准交易。

雖然這個參考實作項目會示範簽署作業,但並未涵蓋 MPC 金鑰管理的所有層面。舉例來說,我們不會討論金鑰產生作業。此外,還有其他替代和互補的方法,例如使用非 Google Cloud 服務產生共同簽署,或是讓共同簽署者在自己的環境中建構區塊鏈簽署,這是更去中心化的架構。我們希望這個實驗室能激發您在 Google Cloud 上使用 MPC 的不同做法。

您將使用簡單的工作負載,透過共同簽署者金鑰素材在機密空間中簽署以太坊交易。以太坊交易簽署為例,這是使用者在以太坊區塊鏈上授權交易的程序。如要傳送以太坊交易,您必須使用私密金鑰簽署交易。這可證明你是帳戶擁有者,並授權進行交易。簽署程序如下:

  1. 寄件者會建立交易物件,指定收件者地址、要傳送的 ETH 數量,以及任何其他相關資料。
  2. 使用者會使用發送者的私密金鑰對交易資料進行散列。
  3. 然後使用私密金鑰簽署散列值。
  4. 簽名會附加至交易物件。
  5. 交易會廣播至以太坊網路。

當網路上的節點收到交易時,會驗證簽名,確認簽名者是帳戶擁有者。如果簽章有效,節點就會將交易加入區塊鏈。

首先,您將設定必要的 Cloud 資源。接著,您將在 Confidential Space 中執行工作負載。本程式碼研究室會引導您完成下列高階步驟:

  • 如何設定執行機密空間所需的雲端資源
  • 如何根據下列屬性授權存取受保護的資源:
  • 內容:工作負載容器
  • 位置:機密空間環境 (機密 VM 上的機密空間映像檔)
  • Who:執行工作負載的帳戶
  • 如何在執行機密空間 VM 映像檔的機密 VM 中執行工作負載

必要 API

您必須在指定專案中啟用下列 API,才能完成本指南的步驟。

API 名稱

API 標題

cloudkms.googleapis.com

Cloud KMS

compute.googleapis.com

Compute Engine

confidentialcomputing.googleapis.com

機密運算

iamcredentials.googleapis.com

IAM

artifactregistry.googleapis.com

Artifact Registry

2. 設定雲端資源

事前準備

  • 使用下列指令複製 這個存放區,取得用於本程式碼研究室的必要指令碼。
git clone https://github.com/GoogleCloudPlatform/confidential-space.git
  • 變更本程式碼研究室的目錄。
cd confidential-space/codelabs/digital_asset_transaction_codelab/scripts
  • 請確認您已設定必要的專案環境變數,如下所示。如要進一步瞭解如何設定 GCP 專案,請參閱 這個程式碼研究室。您可以參閱這篇文章,瞭解如何擷取專案 ID,以及專案 ID 與專案名稱和專案編號的差異。。
export PRIMUS_PROJECT_ID=<GCP project id>
gcloud services enable \
   cloudapis.googleapis.com \
    cloudkms.googleapis.com \
    cloudresourcemanager.googleapis.com \
    cloudshell.googleapis.com \
    container.googleapis.com \
    containerregistry.googleapis.com \
    iam.googleapis.com \
    confidentialcomputing.googleapis.com
  • 如要設定資源名稱的變數,您可以使用下列指令。請注意,這會覆寫公司 A 專屬 GCP 專案的資源名稱,例如 export PRIMUS_INPUT_STORAGE_BUCKET='primus-input-bucket'
  • 您可以在公司 A 的 GCP 專案中設定下列變數:

$PRIMUS_INPUT_STORAGE_BUCKET

儲存加密金鑰的值區。

$PRIMUS_RESULT_STORAGE_BUCKET

儲存 MPC 交易結果的資料集。

$PRIMUS_KEY

用於為 Primus Bank 加密 $PRIMUS_INPUT_STORAGE_BUCKET 中儲存的資料的 KMS 金鑰。

$PRIMUS_KEYRING

用於為 Primus Bank 建立加密金鑰 $PRIMUS_KEY 的 KMS 鑰圈。

$PRIMUS_WIP_PROVIDER

Workload Identity Pool 提供者,其中包含用於由 MPC 工作負載服務簽署的權杖的屬性條件。

$PRIMUS_SERVICEACCOUNT

$PRIMUS_WORKLOAD_IDENTITY_POOL 用來存取受保護資源的服務帳戶。這個服務帳戶將具備查看 $PRIMUS_INPUT_STORAGE_BUCKET 值區中儲存的加密金鑰的權限。

$PRIMUS_ARTIFACT_REPOSITORY

用於儲存工作負載容器映像檔的構件存放區。

$WORKLOAD_SERVICEACCOUNT

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

$WORKLOAD_CONTAINER

執行工作負載的 Docker 容器。

$WORKLOAD_IMAGE_NAME

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

$WORKLOAD_IMAGE_TAG

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

  • 執行下列指令碼,將剩餘的變數名稱設為資源名稱的值,並根據專案 ID 進行設定。
source config_env.sh

設定雲端資源

在這個步驟中,您將設定多方運算所需的雲端資源。本研究室會使用以下私密金鑰:0000000000000000000000000000000000000000000000000000000000000001

在正式環境中,您會自行產生私密金鑰。不過,為了完成本實驗室的目標,我們會將這個私密金鑰分割成兩個共用金鑰,並分別加密。在實際工作環境中,金鑰絕不應儲存在明文檔案中。相反地,私密金鑰可在 Google Cloud 以外產生 (或完全略過,改為使用自訂的 MPC 金鑰分片建立作業),然後加密,以免任何人都能存取私密金鑰或金鑰分片。為了進行本實驗室,我們將使用 Gcloud CLI。

執行下列指令碼,設定必要的雲端資源。在這些步驟中,系統會建立下列資源:

  • 用於儲存已加密私密金鑰共用項目的 Cloud Storage 值區 ($PRIMUS_INPUT_STORAGE_BUCKET)。
  • Cloud Storage 值區 ($PRIMUS_RESULT_STORAGE_BUCKET),用於儲存數位資產交易的結果。
  • KMS 中的加密金鑰 ($PRIMUS_KEY) 和金鑰環 ($PRIMUS_KEYRING),用於加密私密金鑰共用項目。
  • 工作負載身分集區 ($PRIMUS_WORKLOAD_IDENTITY_POOL),可根據提供者下所設定的屬性條件驗證要求。
  • 服務帳戶 ($PRIMUS_SERVICEACCOUNT) 已連結至上述工作負載身分集區 ($PRIMUS_WORKLOAD_IDENTITY_POOL),並具備下列身分與存取權管理存取權:
  • roles/cloudkms.cryptoKeyDecrypter 使用 KMS 金鑰解密資料。
  • objectViewer 讀取 Cloud Storage 值區中的資料。
  • roles/iam.workloadIdentityUser,用於將此服務帳戶連結至工作負載身分池。
./setup_resources.sh

3. 建立工作負載

建立工作負載服務帳戶

接下來,您將為工作負載建立服務帳戶,並設定必要的角色和權限。如要這麼做,請執行以下指令碼,為公司 A 建立工作負載服務帳戶。執行工作負載的 VM 會使用這個服務帳戶。

工作負載服務帳戶 ($WORKLOAD_SERVICEACCOUNT) 將具備下列角色:

  • confidentialcomputing.workloadUser 取得認證權杖
  • logging.logWriter 將記錄檔寫入 Cloud Logging。
  • objectViewer 可讀取 $PRIMUS_INPUT_STORAGE_BUCKET Cloud Storage 值區中的資料。
  • objectUser 將工作負載結果寫入 $PRIMUS_RESULT_STORAGE_BUCKET Cloud Storage 值區。
./create_workload_service_account.sh

建立工作負載

這個步驟包括建立工作負載 Docker 映像檔。這個程式碼研究室的工作負載是簡單的 Node.js MPC 應用程式,可使用加密的私密金鑰共用項目簽署數位交易,用於轉移資產。以下是工作負載專案程式碼。工作負載專案包含下列檔案。

package.json:此檔案包含應用於工作負載 MPC 應用程式的套件清單。在本例中,我們使用 @google-cloud/kms、@google-cloud/storage、ethers 和 fast-crc32c 程式庫。這裡是本程式碼研究室要使用的 package.json 檔案。

index.js:這是工作負載應用程式的進入點,可指定工作負載容器啟動時應執行的指令。我們也附上未簽署的交易範例,這類交易通常是由不受信任的應用程式提供,並要求使用者簽署。這個 index.js 檔案也會從 mpc.js 匯入函式,我們會在下一個步驟建立這個檔案。以下是 index.js 檔案的內容,您也可以按這裡查看。

import {signTransaction, submitTransaction, uploadFromMemory} from './mpc.js';

const signAndSubmitTransaction = async () => {
  try {
    // Create the unsigned transaction object
    const unsignedTransaction = {
      nonce: 0,
      gasLimit: 21000,
      gasPrice: '0x09184e72a000',
      to: '0x0000000000000000000000000000000000000000',
      value: '0x00',
      data: '0x',
    };

    // Sign the transaction
    const signedTransaction = await signTransaction(unsignedTransaction);

    // Submit the transaction to Ganache
    const transaction = await submitTransaction(signedTransaction);

    // Write the transaction receipt
    uploadFromMemory(transaction);

    return transaction;
  } catch (e) {
    console.log(e);
    uploadFromMemory(e);
  }
};

await signAndSubmitTransaction();

mpc.js:這是交易簽署的所在位置。它會匯入 kms-decrypt 和 credential-config 的函式,我們會在後續說明。以下是 mpc.js 檔案的內容,您也可以在這裡找到該檔案。

import {Storage} from '@google-cloud/storage';
import {ethers} from 'ethers';

import {credentialConfig} from './credential-config.js';
import {decryptSymmetric} from './kms-decrypt.js';

const providers = ethers.providers;
const Wallet = ethers.Wallet;

// The ID of the GCS bucket holding the encrypted keys
const bucketName = process.env.KEY_BUCKET;

// Name of the encrypted key files.
const encryptedKeyFile1 = 'alice_encrypted_key_share';
const encryptedKeyFile2 = 'bob_encrypted_key_share';

// Create a new storage client with the credentials
const storageWithCreds = new Storage({
  credentials: credentialConfig,
});

// Create a new storage client without the credentials
const storage = new Storage();

const downloadIntoMemory = async (keyFile) => {
  // Downloads the file into a buffer in memory.
  const contents =
      await storageWithCreds.bucket(bucketName).file(keyFile).download();

  return contents;
};

const provider =
    new providers.JsonRpcProvider(`http://${process.env.NODE_URL}:80`);

export const signTransaction = async (unsignedTransaction) => {
  /* Check if Alice and Bob have both approved the transaction
  For this example, we're checking if their encrypted keys are available. */
  const encryptedKey1 =
      await downloadIntoMemory(encryptedKeyFile1).catch(console.error);
  const encryptedKey2 =
      await downloadIntoMemory(encryptedKeyFile2).catch(console.error);

  // For each key share, make a call to KMS to decrypt the key
  const privateKeyshare1 = await decryptSymmetric(encryptedKey1[0]);
  const privateKeyshare2 = await decryptSymmetric(encryptedKey2[0]);

  /* Perform the MPC calculations
  In this example, we're combining the private key shares
  Alternatively, you could import your mpc calculations here */
  const wallet = new Wallet(privateKeyshare1 + privateKeyshare2);

  // Sign the transaction
  const signedTransaction = await wallet.signTransaction(unsignedTransaction);

  return signedTransaction;
};

export const submitTransaction = async (signedTransaction) => {
  // This can now be sent to Ganache
  const hash = await provider.sendTransaction(signedTransaction);
  return hash;
};

export const uploadFromMemory = async (contents) => {
  // Upload the results to the bucket without service account impersonation
  await storage.bucket(process.env.RESULTS_BUCKET)
      .file('transaction_receipt_' + Date.now())
      .save(JSON.stringify(contents));
};

kms-decrypt.js:這個檔案包含使用 KMS 中管理的金鑰解密的程式碼。以下是 kms-decrypt.js 檔案的內容,您也可以按這裡查看。

import {KeyManagementServiceClient} from '@google-cloud/kms';
import crc32c from 'fast-crc32c';

import {credentialConfig} from './credential-config.js';

const projectId = process.env.PRIMUS_PROJECT_ID;
const locationId = process.env.PRIMUS_LOCATION;
const keyRingId = process.env.PRIMUS_ENC_KEYRING;
const keyId = process.env.PRIMUS_ENC_KEY;

// Instantiates a client
const client = new KeyManagementServiceClient({
  credentials: credentialConfig,
});

// Build the key name
const keyName = client.cryptoKeyPath(projectId, locationId, keyRingId, keyId);

export const decryptSymmetric = async (ciphertext) => {
  const ciphertextCrc32c = crc32c.calculate(ciphertext);
  const [decryptResponse] = await client.decrypt({
    name: keyName,
    ciphertext,
    ciphertextCrc32c: {
      value: ciphertextCrc32c,
    },
  });

  // Optional, but recommended: perform integrity verification on
  // decryptResponse. For more details on ensuring E2E in-transit integrity to
  // and from Cloud KMS visit:
  // https://cloud.google.com/kms/docs/data-integrity-guidelines
  if (crc32c.calculate(decryptResponse.plaintext) !==
      Number(decryptResponse.plaintextCrc32c.value)) {
    throw new Error('Decrypt: response corrupted in-transit');
  }

  const plaintext = decryptResponse.plaintext.toString();

  return plaintext;
};

credential-config.js:此檔案會儲存工作負載身分池路徑和服務帳戶冒用功能的詳細資料。這裡是我們在本程式碼研究室中使用的 credential-config.js 檔案。

Dockerfile:最後,我們會建立 Dockerfile,用於建構工作負載 Docker 映像檔。請參閱這裡的說明,瞭解如何定義 Dockerfile。

FROM node:16.18.0

ENV NODE_ENV=production

WORKDIR /app

COPY ["package.json", "package-lock.json*", "./"]

RUN npm install --production

COPY . .

LABEL "tee.launch_policy.allow_cmd_override"="true"
LABEL "tee.launch_policy.allow_env_override"="NODE_URL,RESULTS_BUCKET,KEY_BUCKET,PRIMUS_PROJECT_NUMBER,PRIMUS_PROJECT_ID,PRIMUS_WORKLOAD_IDENTITY_POOL,PRIMUS_WIP_PROVIDER,PRIMUS_SERVICEACCOUNT,PRIMUS_ENC_KEYRING,PRIMUS_ENC_KEY"

CMD [ "node", "index.js" ]

注意:Dockerfile 中的 LABEL "tee.launch_policy.allow_cmd_override"="true" 是映像檔作者設定的啟動政策。這可讓操作員在執行工作負載時覆寫 CMD。根據預設,allow_cmd_override 會設為 false。標籤「tee.launch_policy.allow_env_override」會告知機密空間圖像使用者可使用的環境變數。

執行以下指令碼,建立工作負載,並執行下列步驟:

  • 建立 Artifact Registry($PRIMUS_ARTIFACT_REPOSITORY) 來儲存工作負載 Docker 映像檔。
  • 請更新工作負載程式碼,加入必要的資源名稱。這裡是本程式碼研究室使用的負載程式碼。
  • 建立 Dockerfile,以便建構工作負載程式的 Docker 映像檔。您可以在這裡找到 Dockerfile。
  • 建構 Docker 映像檔,並發布至先前步驟建立的 Artifact Registry ($PRIMUS_ARTIFACT_REPOSITORY)。
  • $WORKLOAD_SERVICEACCOUNT 的讀取權限授予 $PRIMUS_ARTIFACT_REPOSITORY。這項設定是必要的,因為工作負載容器必須從 Artifact Registry 提取工作負載 Docker 映像檔。
./create_workload.sh

建立區塊鏈節點

Ganache 以太坊節點

授權工作負載前,我們需要建立以太坊 Ganache 為基礎的例項。系統會將已簽署的交易提交至這個 Ganache 例項。請記下這個執行個體的 IP 位址。執行下列指令後,您可能需要輸入 y 才能啟用 API。

gcloud compute instances create-with-container ${ETHEREUM_NODE} \
  --zone=${PRIMUS_PROJECT_ZONE} \
  --tags=http-server \
  --project=${PRIMUS_PROJECT_ID} \
  --shielded-secure-boot \
  --shielded-vtpm \
  --shielded-integrity-monitoring \
  --container-image=docker.io/trufflesuite/ganache:v7.7.3 \
--container-arg=--wallet.accounts=\"0x0000000000000000000000000000000000000000000000000000000000000001,0x21E19E0C9BAB2400000\" \
  --container-arg=--port=80

4. 授權及執行工作負載

授權工作負載

在這個步驟中,我們會在 workload identity pool ($PRIMUS_WORKLOAD_IDENTITY_POOL) 下設定 workload identity pool 提供者。我們為 workload identity 設定了屬性條件,如下所示。其中一個條件是驗證工作負載映像檔是否從預期的構件存放區提取。

gcloud config set project $PRIMUS_PROJECT_ID
gcloud iam workload-identity-pools providers create-oidc ${PRIMUS_WIP_PROVIDER} \
 --location="${PRIMUS_PROJECT_LOCATION}" \
 --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_reference == '${PRIMUS_PROJECT_REPOSITORY_REGION}-docker.pkg.dev/$PRIMUS_PROJECT_ID/$PRIMUS_ARTIFACT_REPOSITORY/$WORKLOAD_IMAGE_NAME:$WORKLOAD_IMAGE_TAG' && '$WORKLOAD_SERVICEACCOUNT@$PRIMUS_PROJECT_ID.iam.gserviceaccount.com' in assertion.google_service_accounts"

執行工作負載

本節將說明如何在機密 VM 上執行工作負載。為此,我們會使用中繼資料標記傳遞必要的 TEE 引數。此外,我們會使用「tee-env-*」旗標為工作負載容器設定環境變數。圖片包含下列變數:

  • NODE_URL:處理已簽署交易的以太坊節點網址。
  • RESULTS_BUCKET:儲存 mpc 交易結果的值區。
  • KEY_BUCKET:儲存 mpc 加密金鑰的值區。
  • PRIMUS_PROJECT_NUMBER:用於憑證設定檔的專案編號。
  • PRIMUS_PROJECT_ID:用於憑證設定檔的專案 ID。工作負載執行結果會發布至 $PRIMUS_RESULT_STORAGE_BUCKET
  • PRIMUS_WORKLOAD_IDENTITY_POOL:用於驗證要求的工作負載身分集區。
  • PRIMUS_WIP_POROVIDER:Workload Identity Pool 提供者,其中包含用於驗證工作負載提供的權杖的屬性條件。
  • WORKLOAD_SERVICEACCOUNT:工作負載的服務帳戶。
gcloud compute instances create $WORKLOAD_VM \
 --confidential-compute-type=SEV \
 --shielded-secure-boot \
 --maintenance-policy=TERMINATE \
 --scopes=cloud-platform \
 --zone=${PRIMUS_PROJECT_ZONE} \
 --project=${PRIMUS_PROJECT_ID} \
 --image-project=confidential-space-images \
 --image-family=confidential-space \
 --service-account=$WORKLOAD_SERVICEACCOUNT@$PRIMUS_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~tee-restart-policy=Never~tee-env-NODE_URL=$(gcloud compute instances describe ${ETHEREUM_NODE} --format='get(networkInterfaces[0].networkIP)' --zone=${PRIMUS_PROJECT_ZONE})~tee-env-RESULTS_BUCKET=$PRIMUS_RESULT_STORAGE_BUCKET~tee-env-KEY_BUCKET=$PRIMUS_INPUT_STORAGE_BUCKET~tee-env-PRIMUS_PROJECT_ID=$PRIMUS_PROJECT_ID~tee-env-PRIMUS_PROJECT_NUMBER=$(gcloud projects describe $PRIMUS_PROJECT_ID --format="value(projectNumber)")~tee-env-PRIMUS_WORKLOAD_IDENTITY_POOL=$PRIMUS_WORKLOAD_IDENTITY_POOL~tee-env-PRIMUS_PROJECT_LOCATION=${PRIMUS_PROJECT_LOCATION}~tee-env-PRIMUS_WIP_PROVIDER=$PRIMUS_WIP_PROVIDER~tee-env-PRIMUS_SERVICEACCOUNT=$PRIMUS_SERVICEACCOUNT~tee-env-PRIMUS_KEY=${PRIMUS_KEY}~tee-env-PRIMUS_KEYRING=${PRIMUS_KEYRING}"

查看 Cloud Storage 結果

您可以在 Cloud Storage 中查看交易收據。系統可能需要幾分鐘的時間才能啟動機密空間,並顯示結果。當 VM 處於停止狀態時,您就會知道容器已完成。

  1. 前往「Cloud Storage Browser」(Cloud Storage 瀏覽器) 頁面。
  2. 按一下「$PRIMUS_RESULT_STORAGE_BUCKET」。
  3. 按一下 transaction_receipt 檔案。
  4. 按一下「Download」下載並查看交易回應。

或者,您也可以執行下列指令來查看結果。

gcloud config set project $PRIMUS_PROJECT_ID
gsutil cat gs://$PRIMUS_RESULT_STORAGE_BUCKET/transaction_receipt

注意:如果沒有顯示結果,您可以前往 Compute Engine 雲端控制台頁面中的 $WORKLOAD_VM,然後按一下「Serial port 1 (console)」(序列埠 1 (主控台)) 查看記錄。

檢查 Ganache 區塊鏈交易

您也可以在區塊鏈記錄中查看交易。

  1. 前往 Cloud Compute Engine 頁面。
  2. 按一下 ${ETHEREUM_NODE} VM
  3. 按一下 SSH 開啟瀏覽器中的 SSH 視窗。
  4. 在 SSH 視窗中輸入 sudo docker ps,查看執行中的 Ganache 容器。
  5. 找出 trufflesuite/ganache:v7.7.3 的容器 ID
  6. 輸入 sudo docker logs CONTAINER_ID,並將 CONTAINER_ID 替換為 trufflesuite/ganache:v7.7.3 的 ID。
  7. 查看 Ganache 的記錄,確認記錄中是否列有交易。

5. 清理

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

  • 輸入用於儲存加密金鑰分片的儲存空間值區 ($PRIMUS_INPUT_STORAGE_BUCKET))。
  • 加密金鑰 ($PRIMUS_KEY)。
  • 用於存取受保護資源的服務帳戶 ($PRIMUS_SERVICEACCOUNT)。
  • Workload Identity 集區 ($PRIMUS_WORKLOAD_IDENTITY_POOL)。
  • 工作負載服務帳戶 ($WORKLOAD_SERVICEACCOUNT)。
  • 工作負載運算執行個體 ($WORKLOAD_VM$ETHEREUM_NODE)。
  • 用於儲存交易結果的結果儲存值區。($PRIMUS_RESULT_STORAGE_BUCKET)。
  • 用於儲存工作負載映像檔 ($PRIMUS_ARTIFACT_REPOSITORY) 的構件登錄。
./cleanup.sh

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

  • 前往 Cloud Platform Console
  • 選取要關閉的專案,然後點選頂端的「刪除」。這會排定刪除專案的時間。

後續步驟

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

其他資訊