從 Artifact Registry 同步處理 OCI 構件

本頁說明如何使用 crane 和 oras 建立映像檔,並發布至 Artifact Registry 的存放區。

您可以設定 Config Sync,透過 Artifact Registry 同步處理 OCI 映像檔。如要使用這項功能,請務必啟用 RootSync 和 RepoSync API。

關於 Artifact Registry

Artifact Registry 是一項全代管服務,支援容器映像檔和非容器構件。建議您使用 Artifact Registry,在 Cloud de Confiance by S3NS上儲存及管理容器映像檔。您可以使用許多工具將構件推送至 Artifact Registry。舉例來說,您可以推送 Docker 映像檔,或使用 go-containerregistry 程式庫處理 Container Registry。選擇最適合你的工具。

事前準備

  1. 安裝 Google Cloud CLI。

  2. 設定 gcloud CLI,使用您的聯合身分。

    詳情請參閱「 使用聯合身分登入 gcloud CLI」。

  3. 執行下列指令,初始化 gcloud CLI:

    gcloud init
  4. 建立或選取 Cloud de Confiance 專案。

    選取或建立專案所需的角色

    • 選取專案:選取專案時,不需要具備特定 IAM 角色,只要您在專案中獲派角色,即可選取該專案。
    • 建立專案:如要建立專案,您需要專案建立者角色 (roles/resourcemanager.projectCreator),其中包含 resourcemanager.projects.create 權限。瞭解如何授予角色。
    • 建立 Cloud de Confiance 專案:

      gcloud projects create PROJECT_ID

      將 PROJECT_ID 替換為要建立的專案名稱。 Cloud de Confiance

    • 選取您建立的 Cloud de Confiance 專案:

      gcloud config set project PROJECT_ID

      將 PROJECT_ID 替換為 Cloud de Confiance 專案名稱。

  5. 確認 Cloud de Confiance 專案已啟用計費功能。

  6. 如果尚未啟用 GKE、Config Sync 和 Artifact Registry API,請啟用:

    啟用 API 時所需的角色

    如要啟用 API,您必須具備 serviceusage.services.enable 權限。如果您建立了專案,可能已透過「擁有者」角色 (roles/owner) 取得這項權限。否則,您可以透過「服務使用管理員」角色 (roles/serviceusage.serviceUsageAdmin) 取得這項權限。瞭解如何授予角色。

    gcloud services enable container.googleapis.com  anthosconfigmanagement.googleapis.com  artifactregistry.googleapis.com
  7. 建立或存取符合 Config Sync 需求的叢集,並使用最新版 Config Sync。
  8. 安裝 nomos CLI 或升級至最新版本。
  9. (選用) 如要使用 Cosign 驗證 OCI 映像檔簽章,請安裝下列項目:
    • 使用 Cosign 簽署 OCI 映像檔。
    • 使用 OpenSSL 為 webhook 伺服器產生憑證。
    • Docker,用於建構及推送 Admission Webhook 伺服器映像檔。

費用

在本文件中,您將使用下列 Cloud de Confiance by S3NS計費元件:

建立 Artifact Registry 存放區

在本節中,您將建立 Artifact Registry 存放區。如要進一步瞭解如何建立 Artifact Registry 存放區,請參閱「建立存放區」。

建立 Artifact Registry 存放區:

gcloud artifacts repositories create AR_REPO_NAME \
   --repository-format=docker \
   --location=AR_REGION \
   --description="Config Sync repo" \
   --project=PROJECT_ID

更改下列內容:

  • PROJECT_ID:機構的專案 ID。
  • AR_REPO_NAME:存放區 ID。
  • AR_REGION:存放區的區域或多區域位置。

下列章節中使用的變數:

  • FLEET_HOST_PROJECT_NUMBER:如果您使用 GKE Workload Identity Federation for GKE,這與 PROJECT_ID 的專案編號相同。如果您使用機群適用的 Workload Identity Federation for GKE,這是叢集註冊的機群專案編號。
  • FLEET_HOST_PROJECT_ID:如果您使用 GKE Workload Identity Federation for GKE,這與 PROJECT_ID 相同。如果您使用機群 Workload Identity Federation for GKE,這是叢集註冊的機群專案 ID。
  • KUBERNETES_SERVICEACCOUNT:調解器的 Kubernetes ServiceAccount:
    • 如果是根存放區,且 RootSync 名稱為 root-sync,請新增 root-reconciler。否則,請新增 root-reconciler-ROOT_SYNC_NAME。
    • 如果是命名空間存放區,如果 RepoSync 名稱是 repo-sync,請新增 ns-reconciler-NAMESPACE。否則,請加入 ns-reconciler-NAMESPACE-REPO_SYNC_NAME-REPO_SYNC_NAME_LENGTH,其中 REPO_SYNC_NAME_LENGTH 是 REPO_SYNC_NAME 中的字元數。

授予讀取的權限

將 Artifact Registry 讀取者角色 (roles/artifactregistry.reader) 授予存放區的 Kubernetes 服務帳戶:

gcloud artifacts repositories add-iam-policy-binding AR_REPO_NAME \
   --location=AR_REGION \
   --member="principal://iam.googleapis.com/projects/FLEET_HOST_PROJECT_NUMBER/locations/global/workloadIdentityPools/FLEET_HOST_PROJECT_ID.s3ns.svc.id.goog/subject/ns/config-management-system/sa/KUBERNETES_SERVICEACCOUNT" \
   --role=roles/artifactregistry.reader \
   --project=PROJECT_ID \
   --condition=None

將映像檔推送至 Artifact Registry 存放區

在本節中,您將建立 OCI 映像檔並推送至 Artifact Registry。

  1. 建立 Namespace 資訊清單檔案:

    cat <<EOF> test-namespace.yaml
    apiVersion: v1
    kind: Namespace
    metadata:
      name: test
    EOF
    
  2. 登入 Artifact Registry:

    gcloud auth configure-docker AR_REGION-docker.pkg.dev
    
  3. 封裝映像檔並推送至 Artifact Registry:

    crane

    本節中的指令會使用 crane 與遠端映像檔和登錄檔互動。

    1. 封裝檔案:

      tar -cf test-namespace.tar test-namespace.yaml
      
    2. 安裝 crane 工具。

    3. 將映像檔推送至 Artifact Registry:

      crane append -f test-namespace.tar -t AR_REGION-docker.pkg.dev/PROJECT_ID/AR_REPO_NAME/test-namespace:v1
      

    oras

    本節中的指令會使用 oras 與遠端映像檔和登錄檔互動。

    1. 封裝檔案:

      tar -czf test-namespace.tar.gz test-namespace.yaml
      
    2. 安裝 oras 工具。

    3. 將映像檔推送至 Artifact Registry:

      oras push AR_REGION-docker.pkg.dev/PROJECT_ID/AR_REPO_NAME/test-namespace:v1 test-namespace.tar.gz
      

設定 Config Sync,從映像檔同步處理

在本節中,您將建立 RootSync 物件,並設定 Config Sync 從 OCI 映像檔同步處理。

  1. 建立具有專屬名稱的 RootSync 物件:

    cat <<EOF>> ROOT_SYNC_NAME.yaml
    apiVersion: configsync.gke.io/v1beta1
    kind: RootSync
    metadata:
      name: ROOT_SYNC_NAME
      namespace: config-management-system
    spec:
      sourceFormat: unstructured
      sourceType: oci
      oci:
        image: AR_REGION-docker.pkg.dev/PROJECT_ID/AR_REPO_NAME/test-namespace:v1
        dir: .
        auth: k8sserviceaccount
    EOF
    

    將 ROOT_SYNC_NAME 替換為 RootSync 物件的名稱。 名稱在叢集中不得重複,且長度不得超過 26 個字元。 如要查看設定 RootSync 物件時的完整選項清單,請參閱 RootSync 和 RepoSync 欄位。

  2. 套用 RootSync 物件:

    kubectl apply -f ROOT_SYNC_NAME.yaml
    
  3. 從圖片中確認 Config Sync 是否正在同步:

    nomos status --contexts=$(kubectl config current-context)
    

    您會看到類似以下範例的輸出內容:

    Connecting to clusters...
    
    *publish-config-registry
       --------------------
       <root>:root-sync-test   AR_REGION-docker.pkg.dev/PROJECT_ID/AR_REPO_NAME/test-namespace:v1   
       SYNCED                  05e6a6b77de7a62286387cfea833d45290105fe84383224938d7b3ab151a55a1
       Managed resources:
          NAMESPACE   NAME             STATUS    SOURCEHASH
                      namespace/test   Current   05e6a6b
    

    您已成功將映像檔同步至叢集。

(選用) 驗證 OCI 來源簽章

您可以在設定套用至叢集前,驗證 OCI 來源映像檔的真實性。這個方法會使用 ValidatingWebhookConfiguration 物件和驗證 Webhook 伺服器,攔截 RootSync 和 RepoSync 物件的更新要求。Config Sync 成功擷取新的映像檔摘要後,會更新 RootSync 和 RepoSync 物件的 configsync.gke.io/image-to-sync 註解。驗證 Webhook 伺服器會比較舊註解和新註解之間的值,並在偵測到變更時,使用 Cosign 等驗證工具執行驗證。

設定簽名驗證伺服器

為確保 OCI 來源的真實性,您需要 HTTP 伺服器來驗證簽章。 您可以使用Config Sync 範例存放區中的範例,也可以使用自己的 Docker 映像檔。

  1. 如要使用提供的範例,請完成下列步驟:

    1. 複製範例存放區:

      git clone https://github.com/GoogleCloudPlatform/anthos-config-management-samples/
      
    2. 變更為包含簽名驗證伺服器範例的目錄:

      cd anthos-config-management-samples/tree/main/pre-sync/oci-image-verification
      
  2. 如要為簽章驗證伺服器建立 Docker 映像檔,並將其推送至映像檔登錄檔,請執行下列指令:

    docker build -t SIGNATURE_VERIFICATION_SERVER_IMAGE_URL:latest . && docker push SIGNATURE_VERIFICATION_SERVER_IMAGE_URL:latest
    

    將 SIGNATURE_VERIFICATION_SERVER_IMAGE_URL 替換為簽章驗證伺服器映像檔的網址。

驗證服務

如要設定簽章驗證伺服器,您必須向 Artifact Registry、Cosign 用戶端和 Webhook 伺服器進行驗證。

  1. 建立命名空間:

    kubectl create ns signature-verification
    
  2. 如要使用 Kubernetes ServiceAccount 向 Artifact Registry 進行驗證,請完成下列步驟:

    1. 在您建立的命名空間中建立 Kubernetes ServiceAccount:

      kubectl create sa signature-verification-sa -n signature-verification
      
    2. 將 Artifact Registry 讀取者角色 (roles/artifactregistry.reader) 授予存放區的 Kubernetes 服務帳戶:

      gcloud artifacts repositories add-iam-policy-binding REPOSITORY_NAME \
         --location=REPOSITORY_LOCATION \
         --member="principal://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/PROJECT_ID.s3ns.svc.id.goog/subject/ns/signature-verification/sa/signature-verification-sa" \
         --role=roles/artifactregistry.reader \
         --project=PROJECT_ID \
         --condition=None
      

      更改下列內容:

      • REPOSITORY_NAME:Artifact Registry 存放區的名稱,用於儲存 OCI 映像檔。
      • REPOSITORY_LOCATION:Artifact Registry 存放區的位置。
      • PROJECT_NUMBER:您的專案編號。
      • PROJECT_ID:您的專案 ID。
  3. 如要向 Cosign 用戶端進行驗證,請完成下列步驟:

    1. 產生一組 Cosign 金鑰。這個指令會產生公開金鑰和私密金鑰:

      cosign generate-key-pair
      
    2. 將公開金鑰儲存在您建立的命名空間中的 Kubernetes Secret:

      kubectl create secret generic cosign-key --from-file=cosign.pub -n signature-verification
      
  4. 如要驗證簽章驗證伺服器,請完成下列步驟:

    1. 如要加密簽章驗證伺服器內的通訊內容,請使用 OpenSSL 產生 TLS 憑證和私密金鑰:

      openssl req -nodes -x509 -sha256 -newkey rsa:4096 \
      -keyout tls.key \
      -out tls.crt \
      -days 356 \
      -subj "/CN=signature-verification-service.signature-verification.svc"  \
      -addext "subjectAltName = DNS:signature-verification-service,DNS:signature-verification-service.signature-verification.svc,DNS:signature-verification-service.signature-verification"
      
    2. 將產生的憑證儲存在 Kubernetes Secret 中:

      kubectl create secret tls webhook-tls --cert=tls.crt --key=tls.key -n signature-verification
      
    3. 取得 tls.cert 的 Base64 編碼內容。這是下一節中建立的驗證用 Webhook 設定的必要條件:

      cat tls.crt | base64 -w 0.
      

部署許可 Webhook

您可以使用下列範例,為簽章驗證伺服器建立部署作業,以及驗證 Webhook 設定。

  1. 儲存下列檔案,為簽章驗證伺服器建立部署作業:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: signature-verification-server
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: signature-verification-server
      template:
        metadata:
          labels:
            app: signature-verification-server
        spec:
          serviceAccountName: signature-verification-sa
          containers:
          - name: signature-verification-server
            command:
            - /signature-verification-server
            image: SIGNATURE_VERIFICATION_SERVER_IMAGE_URL
            imagePullPolicy: Always
            ports:
            - containerPort: 10250
            volumeMounts:
            - name: tls-certs
              mountPath: "/tls"
            - name: cosign-key
              mountPath: "/cosign-key"
          volumes:
          - name: cosign-key
            secret:
              secretName: cosign-key
          - name: tls-certs
            secret:
              secretName: webhook-tls
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: signature-verification-service
    spec:
      ports:
      - port: 10250
        targetPort: 10250
      selector:
        app: signature-verification-server

    將 SIGNATURE_VERIFICATION_SERVER_IMAGE_URL 替換為簽章驗證伺服器映像檔的完整網址。

  2. 將 Deployment 套用至叢集:

    kubectl apply -f signature-verification-deployment.yaml -n signature-verification
    
  3. 儲存下列檔案,建立驗證 Webhook 設定:

    apiVersion: admissionregistration.k8s.io/v1
    kind: ValidatingWebhookConfiguration
    metadata:
      name: image-verification-webhook
    webhooks:
    - name: imageverification.webhook.com
      clientConfig:
        service:
          name: signature-verification-service
          namespace: signature-verification
          path: "/validate"
          port: 10250
        caBundle: CA_BUNDLE
      rules:
      - apiGroups:
        - configsync.gke.io
        apiVersions:
        - v1beta1
        - v1alpha1
        operations:
        - UPDATE
        resources:
        - 'rootsyncs'
        - 'reposyncs'
        scope: '*'
      admissionReviewVersions: ["v1", "v1beta1"]
      sideEffects: None

    將 CA_BUNDLE 替換為 tls.cert 中採用 Base64 編碼的內容。

  4. 將驗證 webhook 設定套用至叢集:

    kubectl apply -f signature-verification-validatingwebhookconfiguration.yaml
    

檢查記錄檔中的圖片驗證錯誤

設定圖片驗證伺服器後,任何嘗試從未簽署的 OCI 圖片同步的作業都會失敗。

如要檢查簽章驗證錯誤,請執行下列指令,查看簽章驗證伺服器的記錄:

  1. 檢查 kubectl 記錄:

    kubectl logs deployment  signature-verification-server -n  signature-verification
    

    kubectl 傳回的簽名驗證相關錯誤如下:

    main.go:69: error during command execution: no signatures found
    
  2. 查看 Config Sync 記錄:

    nomos status
    

    Config Sync 傳回的簽章驗證相關錯誤如下:

    Error:   KNV2002: admission webhook "imageverification.webhook.com" denied the request: Image validation failed: cosign verification failed: exit status 10, output: Error: no signatures found
    

如果沒有收到任何錯誤訊息,請檢查 RootSync 或 RepoSync 設定,確認簽署的映像檔是正在同步處理的物件:

RootSync

 kubectl get rootsync ROOTSYNC_NAME -n config-management-system -oyaml

將 ROOTSYNC_NAME 替換為您的 RootSync 名稱。

RepoSync

 kubectl get reposync REPOSYNC_NAME -n REPOSYNC_NAMESPACE -oyaml

更改下列內容:

  • REPOSYNC_NAME:RepoSync 的名稱。
  • REPOSYNC_NAMESPACE:與 RepoSync 相關聯的命名空間名稱。

您應該會看到註解 configsync.gke.io/image-to-sync 新增至 RootSync 或 RepoSync 物件。註解包含來源 OCI 映像檔的網址,以及 Config Sync 擷取的最新摘要。

後續步驟