從 Artifact Registry 同步處理 OCI 構件

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

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

關於 Artifact Registry

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

事前準備

  1. 登入 Google Cloud 帳戶。如果您是 Google Cloud新手,歡迎 建立帳戶,親自評估產品在實際工作環境中的成效。新客戶還能獲得價值 $300 美元的免費抵免額,可用於執行、測試及部署工作負載。
  2. 安裝 Google Cloud CLI。

  3. 若您採用的是外部識別資訊提供者 (IdP),請先使用聯合身分登入 gcloud CLI

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

    gcloud init
  5. 建立或選取 Google Cloud 專案

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

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

      gcloud projects create PROJECT_ID

      PROJECT_ID 替換為您要建立的 Google Cloud 專案名稱。

    • 選取您建立的 Google Cloud 專案:

      gcloud config set project PROJECT_ID

      PROJECT_ID 替換為 Google Cloud 專案名稱。

  6. 確認專案已啟用計費功能 Google Cloud

  7. 啟用 GKE、Config Sync 和 Artifact Registry API:

    啟用 API 時所需的角色

    如要啟用 API,您需要具備服務使用情形管理員 IAM 角色 (roles/serviceusage.serviceUsageAdmin),其中包含 serviceusage.services.enable 權限。瞭解如何授予角色

    gcloud services enable container.googleapis.com  anthosconfigmanagement.googleapis.com  artifactregistry.googleapis.com
  8. 安裝 Google Cloud CLI。

  9. 若您採用的是外部識別資訊提供者 (IdP),請先使用聯合身分登入 gcloud CLI

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

    gcloud init
  11. 建立或選取 Google Cloud 專案

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

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

      gcloud projects create PROJECT_ID

      PROJECT_ID 替換為您要建立的 Google Cloud 專案名稱。

    • 選取您建立的 Google Cloud 專案:

      gcloud config set project PROJECT_ID

      PROJECT_ID 替換為 Google Cloud 專案名稱。

  12. 確認專案已啟用計費功能 Google Cloud

  13. 啟用 GKE、Config Sync 和 Artifact Registry API:

    啟用 API 時所需的角色

    如要啟用 API,您需要具備服務使用情形管理員 IAM 角色 (roles/serviceusage.serviceUsageAdmin),其中包含 serviceusage.services.enable 權限。瞭解如何授予角色

    gcloud services enable container.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 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 工作負載身分聯盟,這是叢集註冊的 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_PROJECsvc.id.googT_ID.[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 來源簽章

您可以在設定套用至叢集前,驗證 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:PROJECsvc.id.googT_ID.[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: [&quot;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 擷取的最新摘要。

後續步驟