Artifact Registry에서 OCI 아티팩트 동기화

이 페이지에서는 craneoras를 사용하여 이미지를 만들고 Artifact Registry의 저장소에 게시하는 방법을 보여줍니다.

Artifact Registry를 사용하여 OCI 이미지에서 동기화하도록 구성 동기화를 구성할 수 있습니다. 이 기능을 사용하려면 RootSync 및 RepoSync API를 사용 설정해야 합니다.

Artifact Registry 정보

Artifact Registry는 컨테이너 이미지 및 비컨테이너 아티팩트를 모두 지원하는 완전 관리형 서비스입니다. Google Cloud에서 컨테이너 이미지 스토리지 및 관리를 위해 Artifact Registry를 사용하는 것이 좋습니다. Artifact Registry로 아티팩트를 푸시하는 데 사용할 수 있는 많은 도구가 있습니다. 예를 들어 Docker 이미지를 푸시하거나 Helm 차트를 푸시하거나 go-containerregistry 라이브러리를 사용하여 Container Registry에서 작업할 수 있습니다. 자신에게 가장 적합한 도구를 선택하세요.

시작하기 전에

  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. 외부 ID 공급업체(IdP)를 사용하는 경우 먼저 제휴 ID로 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. Verify 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. 외부 ID 공급업체(IdP)를 사용하는 경우 먼저 제휴 ID로 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. Verify 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. 구성 동기화 요구사항을 충족하고 최신 버전의 구성 동기화를 사용하는 클러스터를 만들거나 이에 대한 액세스 권한을 얻습니다.
  15. nomos CLI를 설치하거나 최신 버전으로 업그레이드합니다.
  16. (선택사항) Cosign을 사용하여 OCI 이미지 서명을 확인하려면 다음을 설치합니다.
    • Cosign: OCI 이미지에 서명합니다.
    • OpenSSL: 웹훅 서버의 사용자 인증 정보를 생성합니다.
    • Docker: 허용 웹훅 서버 이미지를 빌드하고 푸시합니다.

    비용

    이 문서에서는 비용이 청구될 수 있는 Google Cloud구성요소( )를 사용합니다.

    프로젝트 사용량을 기준으로 예상 비용을 산출하려면 가격 계산기를 사용합니다.

    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용 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에 인증하려면 다음 단계를 완료합니다.

    GKE용 워크로드 아이덴티티 제휴 풀이 있는 Kubernetes 서비스 계정에 Artifact Registry 리더(roles/artifactregistry.reader) IAM 역할을 부여합니다.

    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
        

    이미지에서 동기화하도록 구성 동기화 구성

    이 섹션에서는 RootSync 객체를 만들고 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_NAMERootSync 객체의 이름으로 바꿉니다. 이름은 클러스터에서 고유해야 하며 26자(영문 기준) 이하여야 합니다. RootSync 객체를 구성할 때 사용할 수 있는 전체 옵션 목록은 RootSyncRepoSync 필드를 참조하세요.

    2. RootSync 객체를 적용합니다.

      kubectl apply -f ROOT_SYNC_NAME.yaml
      
    3. 구성 동기화가 이미지에서 동기화되는지 확인합니다.

      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 소스 서명 확인

    구성 동기화 버전 1.20.0부터 구성 동기화는 구성이 클러스터에 적용되기 전에 OCI 소스 이미지의 진위성을 확인합니다. 이 메서드는 ValidatingWebhookConfiguration 객체와 검증 웹훅 서버를 사용하여 RootSyncRepoSync 객체의 업데이트 요청을 가로챕니다. 구성 동기화는 새 이미지 다이제스트를 가져온 후 RootSyncRepoSync 객체의 configsync.gke.io/image-to-sync 주석을 업데이트합니다. 검증 웹훅 서버는 이전 주석과 새 주석 간의 값을 비교하고 변경사항이 감지되면 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을 서명 인증 서버 이미지의 URL로 바꿉니다.

    서비스에 인증

    서명 인증 서버를 설정하려면 Artifact Registry, Cosign 클라이언트, 웹훅 서버에 인증해야 합니다.

    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)의 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: OCI 이미지를 저장하는 Artifact Registry 저장소의 이름입니다.
        • REPOSITORY_LOCATION: Artifact Registry 저장소의 위치입니다.
    3. Cosign 클라이언트에 인증하려면 다음 단계를 완료하세요.

      1. Cosign 키 쌍을 생성합니다. 이 명령어는 공개 키와 비공개 키를 생성합니다.

        cosign generate-key-pair
        
      2. 만든 네임스페이스의 Kubernetes 보안 비밀에 공개 키를 저장합니다.

        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 보안 비밀에 저장합니다.

        kubectl create secret tls webhook-tls --cert=tls.crt --key=tls.key -n signature-verification
        
      3. tls.cert의 base64로 인코딩된 콘텐츠를 가져옵니다. 이는 다음 섹션에서 만드는 검증 웹훅 구성에 필요합니다.

        cat tls.crt | base64 -w 0.
        

    허용 웹훅 배포

    다음 샘플을 사용하여 서명 인증 서버와 검증 웹훅 구성의 배포를 만들 수 있습니다.

    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을 서명 인증 서버 이미지의 전체 URL로 바꿉니다.

    2. 클러스터에 배포를 적용합니다.

      kubectl apply -f signature-verification-deployment.yaml -n signature-verification
      
    3. 다음 파일을 저장하여 검증 웹훅 구성을 만듭니다.

      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_BUNDLEtls.cert의 base64로 인코딩된 콘텐츠로 바꿉니다.

    4. 클러스터에 검증 검사 웹훅 구성을 적용합니다.

      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. 구성 동기화 로그를 확인합니다.

      nomos status
      

      서명 인증과 관련된 구성 동기화의 오류는 다음과 같습니다.

      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_NAMERootSync의 이름으로 바꿉니다.

    RepoSync

     kubectl get reposync REPOSYNC_NAME -n REPOSYNC_NAMESPACE -oyaml
    

    다음을 바꿉니다.

    • REPOSYNC_NAME: RepoSync의 이름입니다.
    • REPOSYNC_NAMESPACE: RepoSync와 연결된 네임스페이스의 이름입니다.

    RootSync 또는 RepoSync 객체에 configsync.gke.io/image-to-sync 주석이 추가된 것을 확인할 수 있습니다. 주석에는 소스 OCI 이미지의 URL과 구성 동기화에서 가져온 최신 다이제스트가 포함됩니다.

    다음 단계