從 Artifact Registry 同步 OCI 構件

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

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

關於 Artifact Registry

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

事前準備

  1. Sign in to your Google Cloud account. If you're new to Google Cloud, create an account to evaluate how our products perform in real-world scenarios. New customers also get $300 in free credits to run, test, and deploy workloads.
  2. Install the Google Cloud CLI.

  3. If you're using an external identity provider (IdP), you must first sign in to the gcloud CLI with your federated identity.

  4. To initialize the gcloud CLI, run the following command:

    gcloud init
  5. Create or select a Google Cloud project.

    • Create a Google Cloud project:

      gcloud projects create PROJECT_ID

      Replace PROJECT_ID with a name for the Google Cloud project you are creating.

    • Select the Google Cloud project that you created:

      gcloud config set project PROJECT_ID

      Replace PROJECT_ID with your Google Cloud project name.

  6. Make sure that billing is enabled for your Google Cloud project.

  7. Enable the GKE Enterprise, Config Sync, Artifact Registry APIs:

    gcloud services enable anthos.googleapis.com  anthosconfigmanagement.googleapis.com  artifactregistry.googleapis.com
  8. Install the Google Cloud CLI.

  9. If you're using an external identity provider (IdP), you must first sign in to the gcloud CLI with your federated identity.

  10. To initialize the gcloud CLI, run the following command:

    gcloud init
  11. Create or select a Google Cloud project.

    • Create a Google Cloud project:

      gcloud projects create PROJECT_ID

      Replace PROJECT_ID with a name for the Google Cloud project you are creating.

    • Select the Google Cloud project that you created:

      gcloud config set project PROJECT_ID

      Replace PROJECT_ID with your Google Cloud project name.

  12. Make sure that billing is enabled for your Google Cloud project.

  13. Enable the GKE Enterprise, Config Sync, Artifact Registry APIs:

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

    費用

    在本文件中,您會使用 Google Cloud的下列計費元件:

    如要根據預測用量估算費用,請使用 Pricing Calculator

    初次使用 Google Cloud 的使用者可能符合免費試用資格。

    建立 Artifact Registry 存放區

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

    1. 建立 Artifact Registry 存放區:

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

    更改下列內容:

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

    下列章節中使用的變數:

    • FLEET_HOST_PROJECT_ID:如果您使用 GKE Workload Identity Federation for GKE,這與 PROJECT_ID 相同。如果您使用 GKE 適用的 Fleet 工作負載身分聯盟,這個 ID 是叢集註冊的 Fleet 專案 ID。
    • GSA_NAME:您要用來連線至 Artifact Registry 的自訂 Google 服務帳戶名稱。
    • KSA_NAME:調解器的 Kubernetes 服務帳戶。
      • 如果是根存放區,且 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_LENGTHREPO_SYNC_NAME 中的字元數。

    授予讀取者權限

    如要使用 Kubernetes 服務帳戶向 Artifact Registry 進行驗證,請完成下列步驟:

    將 Artifact Registry 讀者 (roles/artifactregistry.reader) 身分與存取權管理角色授予具有 GKE 集區 Workload Identity Federation 的 Kubernetes 服務帳戶:

    gcloud artifacts repositories add-iam-policy-binding AR_REPO_NAME \
       --location=AR_REGION \
       --member="serviceAccount:FLEET_HOST_PROJECT_ID.svc.id.goog[config-management-system/KSA_NAME]" \
       --role=roles/artifactregistry.reader \
       --project=PROJECT_ID
    

    將映像檔推送至 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 物件時的完整選項清單,請參閱 RootSyncRepoSync 欄位

    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 來源簽章

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

    設定簽名驗證伺服器

    為確保 OCI 來源的真實性,您需要 HTTP 伺服器來驗證簽章。您可以使用設定同步範例存放區中的範例,或使用自己的 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 Reader 角色 (roles/artifactregistry.reader) 的 IAM 政策繫結:

        gcloud artifacts repositories add-iam-policy-binding REPOSITORY_NAME \
           --location=REPOSITORY_LOCATION \
           --member="serviceAccount:PROJECT_ID.svc.id.goog[signature-verification/signature-verification-sa]" \
           --role=roles/artifactregistry.reader \
           --project=PROJECT_ID
        

        更改下列內容:

        • REPOSITORY_NAME:Artifact Registry 存放區的名稱,用於儲存 OCI 映像檔。
        • REPOSITORY_LOCATION:Artifact Registry 存放區的位置。
    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
      

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

    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_NAMERepoSync 的名稱。
    • REPOSYNC_NAMESPACE:與 RepoSync 相關聯的命名空間名稱。

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

    後續步驟