已簽署容器映像檔程式碼研究室

1. 總覽

本程式碼研究室是以「機密空間程式碼研究室」為基礎。已簽署的容器映像檔支援,可選擇使用認證公開金鑰來驗證容器,而不在工作負載身分池 (WIP) 政策中指定映像檔摘要。

機密空間中的已簽署容器映像檔支援後,所做變更:

提升可用性:我們導入已簽署的容器映像檔功能,現在可以將工作負載映像檔摘要方法轉變為容器簽署做法,讓協作者/稽核人員能夠授權映像檔。

  • 如果直接使用映像檔摘要,資源擁有者每次授權新的映像檔時,都必須使用映像檔摘要更新政策。使用圖片簽章,政策就會包含公開金鑰指紋,其對應的私密金鑰由協作者/稽核者所有,用於簽署稽核映像檔。
  • 對某些安全性模型而言,相較於更新新的映像檔摘要值清單,參照信任的映像檔簽署金鑰會更加方便。

無安全性迴歸:這項容器簽章方法不會對先前的映像檔摘要方法造成任何安全性迴歸,因為信任界線保持不變。在容器簽名方法中,資源擁有者會在 WIP 政策中指定信任的公開金鑰指紋來授權驗證金鑰,並由認證驗證器服務和 WIP 執行授權檢查。認證驗證器服務會驗證簽章與執行中的工作負載相關聯,而 WIP 政策則會檢查由服務聲明的公開金鑰是否已獲政策授權。

高安全性:使用容器映像檔簽名,可讓映像檔簽署者獲得一定程度的信任。資源擁有者在認證政策中指定信任的簽署者的公開金鑰指紋後,即可授權簽署者針對哪些容器映像檔符合政策進行簽署。認證驗證器服務會驗證簽章與執行中的工作負載相關聯,而政策會檢查建立簽章的公開金鑰是否已由政策授權。因此,映像檔簽署的附加層可進一步確保「機密空間」安全無虞。

這兩種方法的唯一差別在於,後者會使用額外的間接層,其中工作負載映像檔是使用簽署金鑰授權。這不會造成任何新的安全漏洞,因為信任界線保持不變。

課程內容

在本程式碼研究室中,您將學習如何使用容器映像檔簽章來授權存取受保護的資源:

  • 如何使用 Cosign 簽署稽核的容器映像檔
  • 如何將容器映像檔簽名上傳至 OCI 註冊資料庫,以便探索及儲存特徵碼
  • 如何設定執行機密空間所需的雲端資源
  • 如何在支援已簽署容器映像檔的情況下,在機密空間中執行工作負載

本程式碼研究室將說明如何使用機密空間,從遠端認證容器映像檔 (在 Google Compute Engine 上執行的受信任金鑰簽署)。

軟硬體需求

機密空間中與已簽署容器映像檔相關的角色

在本程式碼研究室中,Primus Bank 將是稽核員及資源擁有者,管理員將負責下列事項:

  1. 使用範例資料設定必要資源。
  2. 稽核工作負載程式碼。
  3. 使用 cosign 簽署工作負載映像檔。
  4. 將簽章上傳至存放區。
  5. 設定 WIP 政策以保護客戶資料。

Secundus Bank 將是工作負載作者和操作人員,負責以下事項:

  1. 設定儲存結果所需的資源。
  2. 編寫工作負載程式碼。
  3. 發布工作負載映像檔。
  4. 透過支援已簽署的容器映像檔,在機密空間中執行工作負載。

Secundus Bank 會開發並發布工作負載,以便查詢儲存在 Cloud Storage 值區中且由 Primus Bank 擁有的客戶資料。Primus Bank 會稽核工作負載、簽署容器映像檔並設定 WIP 政策,允許經過核准的工作負載存取資料。這項工作負載執行作業的結果會儲存在 Secundus 銀行擁有的 Cloud Storage 值區中。

與設定機密空間相關的資源

本程式碼研究室會參考一些變數,您應為 GCP 專案設定適當的值。本程式碼研究室中的指令會假設已設定這些變數。(例如,export PRIMUS_INPUT_STORAGE_BUCKET='my-input-bucket' 可用於設定 Primus 銀行的輸入儲存值區名稱)。如果尚未設定資源名稱的變數,則系統會根據 GCP 專案 ID 產生變數。

在 Primus 專案中設定以下項目:

  • $PRIMUS_INPUT_STORAGE_BUCKET:儲存客戶資料檔案的值區。
  • $PRIMUS_WORKLOAD_IDENTITY_POOL:用來驗證著作權聲明的工作負載身分池 (WIP)。
  • $PRIMUS_WIP_PROVIDER:工作負載身分集區提供者,包含認證驗證器服務所簽署權杖的使用授權條件。
  • $PRIMUS_SERVICEACCOUNT$PRIMUS_WORKLOAD_IDENTITY_POOL 用於存取受保護資源的服務帳戶。在這個步驟中,該團隊有權查看儲存在 $PRIMUS_INPUT_STORAGE_BUCKET 值區的客戶資料。
  • $PRIMUS_ENC_KEY:用來加密 $PRIMUS_INPUT_STORAGE_BUCKET 中儲存的資料的 KMS 金鑰。

本程式碼研究室新增的資源:

  • $PRIMUS_COSIGN_REPOSITORY:用於儲存工作負載映像檔簽章的 Artifact Registry。
  • $PRIMUS_SIGNING_KEY:稽核者/資料協作者用來簽署工作負載映像檔的 KMS 金鑰 (本例中為 Primus 銀行)。

在 Secundus 專案中設定以下內容:

  • $SECUNDUS_ARTIFACT_REGISTRY:要推送工作負載 Docker 映像檔的構件登錄檔。
  • $WORKLOAD_IMAGE_NAME:工作負載 Docker 映像檔的名稱。
  • $WORKLOAD_IMAGE_TAG:工作負載 Docker 映像檔的標記。
  • $WORKLOAD_SERVICEACCOUNT:有權存取執行工作負載的機密 VM 的服務帳戶。
  • $SECUNDUS_RESULT_BUCKET:儲存工作負載結果的值區。

其他資源:

  • primus_customer_list.csv 包含客戶資料。我們會將這項資料上傳至 $PRIMUS_INPUT_STORAGE_BUCKET,並建立工作負載來查詢這項資料。

現有工作流程

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

  1. 工作負載會向 WIP 要求 $PRIMUS_SERVICEACCOUNT 的一般 Google 存取權杖。可提供工作負載和環境憑證附加資訊的 Attestation Verifier 服務權杖。
  2. 如果 Attestation Verifier 服務權杖中的工作負載評估要求與 WIP 中的屬性條件相符,就會傳回 $PRIMUS_SERVICEACCOUNT. 的存取權杖
  3. 工作負載會使用與 $PRIMUS_SERVICEACCOUNT 相關聯的服務帳戶存取權杖存取「$PRIMUS_INPUT_STORAGE_BUCKET」值區中的客戶資料。
  4. 工作負載會對該資料執行作業。
  5. 工作負載會使用 $WORKLOAD_SERVICEACCOUNT 服務帳戶,將作業結果寫入 $SECUNDUS_RESULT_STORAGE_BUCKET 值區。

支援已簽署容器的新工作流程

已簽署容器的支援功能將整合至現有的工作流程,如下圖所示。當您在機密空間中執行工作負載,並支援已簽署的容器映像檔時,系統會使用已設定的資源執行下列程序:

  1. Secret Space 能找出與目前執行中工作負載映像檔相關的容器簽名,並傳送至認證驗證器。認證驗證者會驗證簽章,並在認證聲明中納入任何有效的簽名。
  2. 工作負載會向 WIP 要求 $PRIMUS_SERVICEACCOUNT 的一般 Google 存取權杖。可提供工作負載和環境憑證附加資訊的 Attestation Verifier 服務權杖。
  3. 如果 Attestation Verifier 服務權杖中的容器簽章憑證附加資訊與 WIP 中的屬性條件相符,就會傳回 $PRIMUS_SERVICEACCOUNT 的存取權杖。
  4. 工作負載會使用與 $PRIMUS_SERVICEACCOUNT 相關聯的服務帳戶存取權杖存取「$PRIMUS_INPUT_STORAGE_BUCKET」值區中的客戶資料。
  5. 工作負載會對該資料執行作業。
  6. 工作負載會使用 $WORKLOAD_SERVICEACCOUNT,將作業的結果寫入 $SECUNDUS_RESULT_STORAGE_BUCKET 值區。

2. 設定雲端資源

設定機密空間時,首先您必須在 Primus 和 Secundus 銀行的 GCP 專案內建立必要的雲端資源。以下是本程式碼研究室的全新資源:

在 Primus 專案中:

  • 在稽核程式碼之後,用來簽署 Secundus 工作負載的 KMS 簽署金鑰。
  • 用於儲存 Cosign 簽名的 Artifact Registry 存放區。

Secundus 專案中沒有新資源。設定這些資源後,您就能為工作負載建立具有必要角色和權限的服務帳戶。接著會建立工作負載映像檔,稽核員 Primus 銀行會簽署工作負載映像檔。接著,資料協作者 (本程式碼研究室中的主體銀行) 會授權工作負載,工作負載操作員 (在這個案例中為 Secundus Bank) 就會執行工作負載。

設定機密空間時,您必須在 Primus 和 Secundus GCP 專案中建立必要的雲端資源。

事前準備

  • 使用下列指令複製 這個存放區,即可取得本程式碼研究室中使用的必要指令碼。
$ git clone https://github.com/GoogleCloudPlatform/confidential-space
  • 請確認您已按照下列方式設定必要的專案。
$ export PRIMUS_PROJECT_ID=<GCP project id of primus bank>
$ export SECUNDUS_PROJECT_ID=<GCP project id of secundus bank>
  • 使用這個指令設定上述資源名稱的變數。您可以使用這些變數 (例如 export PRIMUS_INPUT_STORAGE_BUCKET='my-input-bucket') 覆寫資源名稱
  • 執行下列指令碼,根據資源名稱的專案 ID 將其餘變數名稱設為值。
$ source config_env.sh
  • 按照這裡的操作說明安裝 Cosign。

設定 Primus 銀行資源

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

  • 用於儲存 Primus 銀行加密客戶資料檔案的 Cloud Storage 值區 ($PRIMUS_INPUT_STORAGE_BUCKET)。
  • KMS 中的加密金鑰 ($PRIMUS_ENC_KEY) 和金鑰環 ($PRIMUS_ENC_KEYRING),用於加密 Primus 銀行的資料檔案。
  • Workload Identity 集區 ($PRIMUS_WORKLOAD_IDENTITY_POOL),可根據供應商設定的屬性驗證憑證附加資訊。
  • 連接至上述工作負載身分集區 ($PRIMUS_WORKLOAD_IDENTITY_POOL) 的服務帳戶 ($PRIMUS_SERVICEACCOUNT),具備下列 IAM 存取權:
  • roles/cloudkms.cryptoKeyDecrypter,才能使用 KMS 金鑰解密資料。
  • objectViewer 可從 Cloud Storage 值區讀取資料。
  • roles/iam.workloadIdentityUser,用於將這個服務帳戶連線至工作負載身分集區。
$ ./setup_primus_bank_resources.sh

設定 Secundus 銀行資源

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

  • 用於儲存 Secundus Bank 工作負載執行結果的 Cloud Storage 值區 ($SECUNDUS_RESULT_STORAGE_BUCKET)。
$ ./setup_secundus_bank_resources.sh

3. 建立並簽署工作負載

建立工作負載服務帳戶

現在,您將為具備必要角色和權限的工作負載建立服務帳戶。執行下列指令碼,在 Secundus 銀行專案中建立工作負載服務帳戶。這個服務帳戶將由執行工作負載的 VM 使用。

  • 這個工作負載服務帳戶 ($WORKLOAD_SERVICEACCOUNT) 會具備下列角色:
  • confidentialcomputing.workloadUser 可取得認證權杖
  • logging.logWriter,以便將記錄檔寫入 Cloud Logging。
  • objectViewer 可從 $PRIMUS_INPUT_STORAGE_BUCKET 雲端儲存空間值區讀取資料。
  • objectAdmin:將工作負載結果寫入 $SECUNDUS_RESULT_STORAGE_BUCKET 雲端儲存空間值區。
$ ./create_workload_serviceaccount.sh

建立工作負載

在這個步驟中,您將建立工作負載 Docker 映像檔。本程式碼研究室中使用的工作負載是以 CLI 為基礎的簡單的 Go 應用程式,可從引數中提供的地理位置計算客戶 (來自 Primus 銀行客戶資料)。執行下列指令碼來建立工作負載,並在其中執行下列步驟:

  • 建立 Secundus 銀行擁有的 Artifact Registry($SECUNDUS_ARTIFACT_REGISTRY)。
  • 使用必要的資源名稱更新工作負載程式碼。這是本程式碼研究室所用的工作負載程式碼,請按這裡
  • 建構 Go 二進位檔並建立 Dockerfile,用來建構工作負載程式碼的 Docker 映像檔。這裡是本程式碼研究室使用的 Dockerfile。
  • 建構 Docker 映像檔並發布至 Secundus Bank 擁有的 Artifact Registry ($SECUNDUS_ARTIFACT_REGISTRY)。
  • $WORKLOAD_SERVICEACCOUNT 授予 $SECUNDUS_ARTIFACT_REGISTRY 的讀取權限。這樣工作負載容器才能從 Artifact Registry 提取工作負載 Docker 映像檔。
$ ./create_workload.sh

簽署工作負載

我們會使用 Cosign 簽署工作負載映像檔。Cosign 預設會將簽名儲存在與簽署映像檔相同的存放區中。如要為簽名指定不同的存放區,您可以設定 COSIGN_REPOSITORY 環境變數。

本文以 Artifact Registry 為例。您也可以根據自己的偏好選擇其他以 OCI 為基礎的註冊資料庫,例如 Docker Hub、AWS CodeArtifact。

  1. 建立 Artifact Registry Docker 存放區。
$ gcloud config set project $PRIMUS_PROJECT_ID

$ gcloud artifacts repositories create $PRIMUS_COSIGN_REPOSITORY \
  --repository-format=docker --location=us
  1. 請在 KMS 下建立金鑰環和金鑰,以便簽署工作負載映像檔。
$ gcloud config set project $PRIMUS_PROJECT_ID

$ gcloud kms keyrings create $PRIMUS_SIGNING_KEYRING \
  --location=global

$ gcloud kms keys create $PRIMUS_SIGNING_KEY \
  --keyring=$PRIMUS_SIGNING_KEYRING \
  --purpose=asymmetric-signing \
  --default-algorithm=ec-sign-p256-sha256
  --location=us
  1. 如果是 Artifact Registry,則必須提供完整的映像檔名稱,例如 $LOCATION/$PROJECT/$REPOSITORY/$IMAGE_NAME。您可以將任何容器映像檔上傳至存放區,以便儲存簽名。
$ export COSIGN_REPOSITORY=us-docker.pkg.dev/${PRIMUS_PROJECT_ID}/${PRIMUS_COSIGN_REPOSITORY}/demo
  1. $PRIMUS_COSIGN_REPOSITORY 存放區的檢視者角色授予 $WORKLOAD_SERVICEACCOUNT 服務帳戶。這可讓 Sensitive Space 找出所有已上傳至 $PRIMUS_COSIGN_REPOSITORY 的容器映像檔簽名。
$ gcloud artifacts repositories add-iam-policy-binding ${PRIMUS_COSIGN_REPOSITORY} \
--project=${PRIMUS_PROJECT_ID} --role='roles/viewer' --location=us \
--member="serviceAccount:${WORKLOAD_SERVICEACCOUNT}@${SECUNDUS_PROJECT_ID}.iam.gserviceaccount.com"

Cosign 是擁有多種簽署功能的強大工具。以我們的用途來說,我們只要求使用 Cosign 簽署金鑰組。這項已簽署的容器映像檔功能不支援 Cosign 無金鑰簽署功能。

使用金鑰組進行簽署時,有兩種做法:

  1. 使用 Cosign 產生的本機金鑰組簽署。
  2. 使用儲存在其他位置 (例如 KMS 中) 的金鑰組簽署。
  1. 如果沒有金鑰組,請在 Cosign 中產生金鑰組。詳情請參閱「使用自行管理的金鑰簽署」一文。
// Set Application Default Credentials.
$ gcloud auth application-default login 

// Generate keys using a KMS provider.
$ cosign generate-key-pair --kms <provider>://<key>

// Generate keys using Cosign.
$ cosign generate-key-pair

在上述指令中,請將 <provider>://<key>合作頻道:gcpkms://projects/$PRIMUS_PROJECT_ID/locations/global/keyRings/$PRIMUS_SIGNING_KEYRING/cryptoKeys/$PRIMUS_SIGNING_KEY/cryptoKeyVersions/$PRIMUS_SIGNING_KEYVERSION

  • &lt;provider&gt;:指的是您目前使用的 KMS 解決方案
  • &lt;key&gt;:代表 KMS 中的金鑰路徑
  1. 擷取用於驗證的公開金鑰。
// For KMS providers.
$ cosign public-key --key <some provider>://<some key> > pub.pem

// For local key pair signing.
$ cosign public-key --key cosign.key > pub.pem
  1. 使用 Cosign 簽署工作負載。對公開金鑰執行未填充 Base64 編碼
$ PUB=$(cat pub.pem | openssl base64)

// Remove spaces and trailing "=" signs.
$ PUB=$(echo $PUB | tr -d '[:space:]' | sed 's/[=]*$//')
  1. 使用 Cosign 簽署工作負載,並附加匯出的公開金鑰和簽名演算法。
$ IMAGE_REFERENCE=us-docker.pkg.dev/$SECUNDUS_PROJECT_ID/$SECUNDUS_ARTIFACT_REPOSITORY/$WORKLOAD_IMAGE_NAME:$WORKLOAD_IMAGE_TAG

// Sign with KMS support.
$ cosign sign --key <some provider>://<some key> $IMAGE_REFERENCE \
-a dev.cosignproject.cosign/sigalg=ECDSA_P256_SHA256 \
-a dev.cosignproject.cosign/pub=$PUB

// Sign with a local key pair.
$ cosign sign --key cosign.key $IMAGE_REFERENCE \
-a dev.cosignproject.cosign/sigalg=ECDSA_P256_SHA256 \
-a dev.cosignproject.cosign/pub=$PUB
  • --key [必要] 指定要使用的簽署金鑰。參照 KMS 供應商管理的金鑰時,請遵循 Sigstore KMS 支援提供的特定 URI 格式。參照 Cosign 產生的金鑰時,請改用 cosign.key。
  • $IMAGE_REFERENCE [必要] 指定要簽署的容器映像檔。IMAGE_REFERENCE 的格式可透過標記或映像檔摘要識別。例如:us-docker.pkg.dev/$SECUNDUS_PROJECT_ID/secundus-workloads/workload-container:latest or us-docker.pkg.dev/$SECUNDUS_PROJECT_ID/secundus-workloads/workload-container[IMAGE-digest]
  • -a [REQUIRED] 指定附加至簽名酬載的註解。機密空間已簽署的容器映像檔時,必須將公開金鑰和簽名演算法附加至簽名酬載。
  • dev.cosignproject.cosign/sigalg「只」接受三個值:
  • RSASSA_PSS_SHA256:具有 PSS 填充搭配 SHA256 摘要的 RSASSA 演算法。
  • RSASSA_PKCS1V15_SHA256:具有 PKCS#1 v1.5 填充搭配 SHA256 摘要的 RSASSA 演算法。
  • ECDSA_P256_SHA256:P-256 曲線上的 ECDSA,具有 SHA256 摘要。這也是 Cosign 產生的金鑰組預設簽章演算法。
  1. 將簽章上傳至 Docker 存放區

Cosign 簽署會將簽名自動上傳至指定的 COSIGN_REPOSITORY。

4. 授權並執行工作負載

授權工作負載

在這個步驟中,我們會在工作負載身分集區 ($PRIMUS_WORKLOAD_IDENTITY_POOL) 中設定工作負載識別資訊提供者。工作負載身分設有屬性條件,如下所示。其中一項條件是依據簽署公開金鑰指紋來驗證工作負載映像檔簽章的指紋。有了這項屬性條件,Secundus Bank 推出新的工作負載映像檔時,Primuss Bank 就會稽核工作負載程式碼,並簽署新的工作負載映像檔,不必使用映像檔摘要更新 WIP 政策。

$ gcloud config set project $PRIMUS_PROJECT_ID

$ PUBLIC_KEY_FINGERPRINT=$(openssl pkey -pubin -in pub.pem -outform DER | openssl sha256 | cut -d' ' -f2)

$ 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
     && '${WORKLOAD_SERVICEACCOUNT}@${SECUNDUS_PROJECT_ID}.iam.gserviceaccount.com' in
     assertion.google_service_accounts
     && ['ECDSA_P256_SHA256:${PUBLIC_KEY_FINGERPRINT}']
       .exists(fingerprint, fingerprint in assertion.submods.container.image_signatures.map(sig,sig.signature_algorithm+':'+sig.key_id))"

執行工作負載

在這個步驟中,我們將透過機密 VM 執行工作負載。必要的 TEE 引數會透過中繼資料標記傳遞。系統會使用「tee-cmd」傳遞工作負載容器的引數部分。工作負載經過編碼,會將結果發布至 $SECUNDUS_RESULT_STORAGE_BUCKET

$ gcloud config set project $SECUNDUS_PROJECT_ID

$ gcloud compute instances create signed-container-vm \
 --confidential-compute-type=SEV \
 --shielded-secure-boot \
 --maintenance-policy=TERMINATE \
 --scopes=cloud-platform --zone=us-west1-b \
 --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}/${SECUNDUS_ARTIFACT_REPOSITORY}/${WORKLOAD_IMAGE_NAME}:${WORKLOAD_IMAGE_TAG}~tee-restart-policy=Never~tee-cmd="[\"count-location\",\"Seattle\",\"gs://${SECUNDUS_RESULT_STORAGE_BUCKET}/seattle-result\"]"~tee-signed-image-repos=us-docker.pkg.dev/${PRIMUS_PROJECT_ID}/${PRIMUS_COSIGN_REPOSITORY}/demo"

查看結果

在 Secundus 專案中,查看工作負載的結果。

$ gcloud config set project $SECUNDUS_PROJECT_ID

$ gsutil cat gs://$SECUNDUS_RESULT_STORAGE_BUCKET/seattle-result

結果應為 3,因為 primus_customer_list.csv 檔案中列出的為西雅圖有多少人!

5. 清除

這裡使用的指令碼可用來清除我們在本程式碼研究室中建立的資源。這項清理作業將刪除下列資源:

  • 輸入 Primus 銀行的輸入儲存值區 ($PRIMUS_INPUT_STORAGE_BUCKET)。
  • Primus 銀行服務帳戶 ($PRIMUS_SERVICEACCOUNT)。
  • 保存映像檔簽名 ($PRIMUS_COSIGN_REPOSITORY) 的 Primus Bank Artifact Registry。
  • Primus Bank 工作負載身分池 ($PRIMUS_WORKLOAD_IDENTITY_POOL)。
  • Secundus Bank 的工作負載服務帳戶 ($WORKLOAD_SERVICEACCOUNT)。
  • 工作負載運算執行個體。
  • Secundus Bank ($SECUNDUS_RESULT_STORAGE_BUCKET) 結果的儲存值區。
  • Secundus Bank 的 Artifact Registry ($SECUNDUS_ARTIFACT_REGISTRY)。
// run the clean up script to delete the resources created as part of this codelab.
$ ./cleanup.sh

如果試用完畢,請考慮刪除專案。

恭喜

恭喜,您已成功完成本程式碼研究室!

您已瞭解如何利用已簽署的容器映像檔功能,提高機密空間的可用性。

後續步驟

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

其他資訊