從 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. 如果您使用外部識別資訊提供者 (IdP),請先 使用聯合身分登入 gcloud CLI

  4. 如要初始化 gcloud CLI,請執行下列指令:

    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. 如果您使用外部識別資訊提供者 (IdP),請先 使用聯合身分登入 gcloud CLI

  10. 如要初始化 gcloud CLI,請執行下列指令:

    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 擷取的最新摘要。

    後續步驟