Google Cloud CLI(GKE)를 사용하여 시작하기


이 튜토리얼에서는 증명이 필요한 Binary Authorization 정책을 구성하고 테스트하는 방법을 보여줍니다. 이 정책 유형은 이미지 배포를 허용하기 전 컨테이너 이미지에 서명된 증명이 포함되었는지 확인하여 컨테이너 기반 소프트웨어 공급망을 보호합니다.

Binary Authorization은 배포 시에 증명자를 사용하여 증명에서 디지털 서명을 확인합니다. 증명자는 일반적으로 지속적 통합(CI) 파이프라인의 일부로 서명자에 의해 생성됩니다.

이 튜토리얼에서 GKE 클러스터, 증명, 증명자는 모두 단일 프로젝트에 위치합니다. 단일 프로젝트 구성은 주로 서비스를 테스트하거나 실험하는 데 유용합니다. 실제 예시를 더 보려면 다중 프로젝트 구성을 참조하세요.

아래의 단계는 명령줄에서 수행하는 작업을 설명합니다. Google Cloud Console을 사용하여 이러한 단계를 수행하려면 Google Cloud Console 사용 시작하기를 참조하세요.

목표

이 튜토리얼에서는 다음을 수행하는 방법을 알아봅니다.

  • Binary Authorization이 사용 설정된 Google Kubernetes Engine(GKE) 클러스터 만들기
  • Binary Authorization 시행자가 증명의 서명을 확인하는 데 사용하는 증명자 만들기
  • 증명이 필요한 정책 구성
  • 암호화 키 쌍을 만들어 증명을 서명한 후 나중에 확인
  • 컨테이너 이미지 다이제스트에 서명하여 서명 만들기
  • 서명을 사용하여 증명 만들기
  • GKE에 컨테이너 이미지를 배포하여 정책 테스트

비용

이 문서에서는 비용이 청구될 수 있는 다음과 같은 Google Cloud 구성요소를 사용합니다.

프로젝트 사용량을 기준으로 예상 비용을 산출하려면 가격 계산기를 사용하세요. Google Cloud를 처음 사용하는 사용자는 무료 체험판을 사용할 수 있습니다.

시작하기 전에

  1. Google Cloud 계정에 로그인합니다. Google Cloud를 처음 사용하는 경우 계정을 만들고 Google 제품의 실제 성능을 평가해 보세요. 신규 고객에게는 워크로드를 실행, 테스트, 배포하는 데 사용할 수 있는 $300의 무료 크레딧이 제공됩니다.
  2. Google Cloud Console의 프로젝트 선택기 페이지에서 Google Cloud 프로젝트를 선택하거나 만듭니다.

    프로젝트 선택기로 이동

  3. Google Cloud 프로젝트에 결제가 사용 설정되어 있는지 확인합니다.

  4. Google Cloud CLI를 설치합니다.
  5. gcloud CLI를 초기화하려면 다음 명령어를 실행합니다.

    gcloud init
  6. Google Cloud Console의 프로젝트 선택기 페이지에서 Google Cloud 프로젝트를 선택하거나 만듭니다.

    프로젝트 선택기로 이동

  7. Google Cloud 프로젝트에 결제가 사용 설정되어 있는지 확인합니다.

  8. Google Cloud CLI를 설치합니다.
  9. gcloud CLI를 초기화하려면 다음 명령어를 실행합니다.

    gcloud init
  10. GKE와의 상호작용을 위해 kubectl을 설치합니다.

Binary Authorization 사용 설정

기본 프로젝트 설정

첫 번째 단계는 gcloud 명령어에서 사용되는 기본 Google Cloud 프로젝트를 설정하는 것입니다.

PROJECT_ID=PROJECT_ID
gcloud config set project ${PROJECT_ID}

여기서 PROJECT_ID는 프로젝트 이름입니다.

필요한 API 사용 설정

API 사용 설정 대상:

Container Registry

gcloud --project=${PROJECT_ID} \
    services enable\
    container.googleapis.com\
    containerregistry.googleapis.com\
    binaryauthorization.googleapis.com

Artifact Registry

gcloud --project=${PROJECT_ID} \
    services enable\
    container.googleapis.com\
    artifactregistry.googleapis.com\
    binaryauthorization.googleapis.com

Binary Authorization이 사용 설정된 클러스터 만들기

클러스터 만들기

Binary Authorization이 사용 설정된 GKE 클러스터를 만듭니다. 배포된 컨테이너 이미지를 실행할 클러스터입니다. 클러스터를 만들 때 --binauthz-evaluation-mode=PROJECT_SINGLETON_POLICY_ENFORCE 플래그를 gcloud container clusters create 명령어에 전달합니다.

클러스터를 만들려면 다음 단계를 따르세요.

gcloud container clusters create \
    --binauthz-evaluation-mode=PROJECT_SINGLETON_POLICY_ENFORCE \
    --zone us-central1-a \
    test-cluster

여기에서 GKE 영역 us-central1-atest-cluster라는 클러스터를 만듭니다.

kubectl 구성

kubectl 설치를 위해 로컬 kubeconfig 파일도 업데이트해야 합니다. 이 파일은 GKE에서 클러스터에 액세스하는 데 필요한 사용자 인증 정보와 엔드포인트 정보를 제공합니다.

로컬 kubeconfig 파일을 업데이트하려면 다음을 실행하세요.

gcloud container clusters get-credentials \
    --zone us-central1-a \
    test-cluster

기본 정책 보기

Binary Authorization의 정책은 컨테이너 이미지의 배포를 제어하는 규칙 집합입니다. 정책은 프로젝트당 하나만 사용할 수 있습니다. 기본적으로 정책은 모든 컨테이너 이미지를 배포하도록 구성됩니다.

Binary Authorization을 사용하면 YAML 형식으로 정책 파일을 내보내고 가져올 수 있습니다. 이 형식에는 서비스에 저장된 정책의 구조가 반영됩니다. gcloud 명령어를 사용하여 정책을 구성할 때 이 파일을 수정합니다.

기본 정책을 보려면 정책 YAML 파일을 내보내세요.

gcloud container binauthz policy export

기본적으로 파일에 포함되는 내용은 다음과 같습니다.

admissionWhitelistPatterns:
- namePattern: gcr.io/google_containers/*
- namePattern: gcr.io/google-containers/*
- namePattern: k8s.gcr.io/**
- namePattern: gke.gcr.io/**
- namePattern: gcr.io/stackdriver-agents/*
globalPolicyEvaluationMode: ENABLE
defaultAdmissionRule:
  evaluationMode: ALWAYS_ALLOW
  enforcementMode: ENFORCED_BLOCK_AND_AUDIT_LOG
name: projects/${PROJECT_ID}/policy

기본 목록에는 registry.k8s.io로 대체되고 이전 버전과의 호환성을 위해 목록에 보관되는 오픈소스 커뮤니티 소유 레지스트리 k8s.gcr.io가 포함되어 있습니다. 대체 레지스트리 registry.k8s.io는 기본 목록에 포함되지 않습니다. k8s.gcr.io에서 마이그레이션할 때 제어할 레지스트리로 이동하거나 대체 레지스트리 registry.k8s.io를 이 목록에 추가합니다.

여기에서 기본 규칙은 정책의 defaultAdmissionRule 노드에 정의되어 있습니다. evaluationMode는 정책이 모든 이미지 배포 시도를 허용하도록 지정합니다. 이 튜토리얼에서는 증명을 요구하도록 기본 규칙을 업데이트합니다.

정책 구조에 대한 자세한 내용은 정책 YAML 참조를 확인하세요.

증명자 만들기

증명자는 배포 시 Binary Authorization 시행자가 GKE에서 서명된 컨테이너 이미지를 배포하도록 허용할지 여부를 결정하는 확인 권한입니다. 증명자는 공개 키를 포함하며 일반적으로 소프트웨어 공급망 보안을 담당하는 조직 내 직원이 관리합니다.

증명자를 만들려면 다음을 수행해야 합니다.

  • Artifact Analysis에서 메모를 만들어 승인 프로세스에 사용된 신뢰할 수 있는 메타데이터 저장
  • Binary Authorization에서 증명자를 만들고 생성한 메모를 연결합니다.

이 튜토리얼에서는 test-attestor라는 증명자 하나와 test-attestor-note라는 컨테이너 분석 메모를 사용합니다. 실제 시나리오에서는 제한 없이 증명자를 사용할 수 있으며, 각 증명자는 컨테이너 이미지의 승인 프로세스에 참여하는 당사자를 나타냅니다.

Artifact Analysis 메모 만들기

  1. 증명자 및 Artifact Analysis 메모의 이름을 저장할 변수를 설정합니다.

    ATTESTOR_NAME=test-attestor
    NOTE_ID=test-attestor-note
    

    다음과 같이 바꿉니다.

    • test-attestor: 선택한 증명자 이름입니다.
    • attestor-note: 선택한 증명자 메모 이름입니다.
  2. /tmp/note_payload.json에 컨테이너 분석 메모를 설명하는 JSON 파일을 만듭니다.

    cat > /tmp/note_payload.json << EOM
    {
      "name": "projects/${PROJECT_ID}/notes/${NOTE_ID}",
      "attestation": {
        "hint": {
          "human_readable_name": "Attestor Note"
        }
      }
    }
    EOM
    
  3. Artifact Analysis REST API에 HTTP 요청을 보내 메모를 만듭니다.

    curl -X POST \
        -H "Content-Type: application/json" \
        -H "Authorization: Bearer $(gcloud auth print-access-token)"  \
        --data-binary @/tmp/note_payload.json  \
        "https://containeranalysis.googleapis.com/v1/projects/${PROJECT_ID}/notes/?noteId=${NOTE_ID}"
    
  4. 메모가 생성되었는지 확인합니다.

    curl \
    -H "Authorization: Bearer $(gcloud auth print-access-token)" \
    "https://containeranalysis.googleapis.com/v1/projects/${PROJECT_ID}/notes/${NOTE_ID}"
    

증명자 만들기

이제 증명자를 만들 수 있습니다.

  1. Binary Authorization에서 증명자를 만듭니다.

    gcloud container binauthz attestors create ${ATTESTOR_NAME} \
    --attestation-authority-note=${NOTE_ID} \
    --attestation-authority-note-project=${PROJECT_ID}
    
  2. 증명자가 생성되었는지 확인합니다.

    gcloud container binauthz attestors list
    

생성된 증명자는 연결된 PKIX 키 쌍이 없이는 사용할 수 없습니다. PKIX 키 쌍은 아래에서 만듭니다.

키 쌍 생성

Binary Authorization은 암호화 키를 사용하여 서명자의 ID를 안전하게 확인합니다. 이렇게 하면 승인된 컨테이너 이미지만 배포할 수 있습니다. 키 쌍은 비공개 키와 공개 키로 구성됩니다. 서명자는 비공개 키를 사용하여 컨테이너 이미지 다이제스트를 서명합니다. 그러면 증명에 저장되는 서명이 생성됩니다. 공개 키는 증명자에 저장됩니다. 배포 시 Binary Authorization 시행자는 증명자의 공개 키를 사용하여 컨테이너의 배포를 허용하기 전에 증명의 서명을 확인합니다.

이 튜토리얼에서는 암호화 키에 공개 키 인프라(X.509)(PKIX) 형식을 사용합니다. 이 튜토리얼에서는 PKIX 키 쌍을 생성하는 데 타원 곡선 디지털 서명 알고리즘(ECDSA) 사용이 권장됩니다. 서명에 RSA 또는 PGP 키를 사용할 수도 있습니다.

서명 알고리즘에 대한 자세한 내용은 키 용도 및 알고리즘을 참조하세요.

Cloud Key Management Service(Cloud KMS)에서 생성하여 저장된 키는 PKIX와 호환되는 형식입니다. PKIX 키 및 Cloud KMS 사용에 대한 자세한 내용은 gcloud CLI를 사용하여 증명자 만들기를 참조하세요.

PKIX(Cloud KMS)

Cloud KMS에서 키 쌍을 만들려면 다음 안내를 따르세요.

  1. 키 쌍을 만드는 데 필요한 환경 변수를 설정합니다.

    KMS_KEY_PROJECT_ID=${PROJECT_ID}
    KMS_KEYRING_NAME=my-binauthz-keyring
    KMS_KEY_NAME=my-binauthz-kms-key-name
    KMS_KEY_LOCATION=global
    KMS_KEY_PURPOSE=asymmetric-signing
    KMS_KEY_ALGORITHM=ec-sign-p256-sha256
    KMS_PROTECTION_LEVEL=software
    KMS_KEY_VERSION=1
    
  2. 키링을 만들려면 다음 명령어를 실행합니다.

    gcloud kms keyrings create ${KMS_KEYRING_NAME} \
      --location ${KMS_KEY_LOCATION}
    
  3. 키를 만들려면 다음 명령어를 실행합니다.

    gcloud kms keys create ${KMS_KEY_NAME} \
      --location ${KMS_KEY_LOCATION} \
      --keyring ${KMS_KEYRING_NAME}  \
      --purpose ${KMS_KEY_PURPOSE} \
      --default-algorithm ${KMS_KEY_ALGORITHM} \
      --protection-level ${KMS_PROTECTION_LEVEL}
    
  4. 공개 키를 증명자에 추가하려면 다음 명령어를 실행합니다.

    gcloud --project="${PROJECT_ID}" \
        container binauthz attestors public-keys add \
        --attestor="${ATTESTOR_NAME}" \
        --keyversion-project="${KMS_KEY_PROJECT_ID}" \
        --keyversion-location="${KMS_KEY_LOCATION}" \
        --keyversion-keyring="${KMS_KEYRING_NAME}" \
        --keyversion-key="${KMS_KEY_NAME}" \
        --keyversion="${KMS_KEY_VERSION}"
    
  5. 다음과 같이 증명자에서 공개 키 ID를 가져옵니다.

    gcloud container binauthz attestors describe <var>ATTESTOR_NAME</var> 명령어를 사용하면 언제든지 공개 키 ID를 볼 수 있습니다.

    공개 키 ID를 환경 변수에 저장하려면 다음 명령어를 입력하세요.

    PUBLIC_KEY_ID=$(gcloud container binauthz attestors describe ${ATTESTOR_NAME} \
    --format='value(userOwnedGrafeasNote.publicKeys[0].id)' --project ${PROJECT_ID})
    

PKIX(로컬 키)

PKIX 키 쌍을 생성하려면 다음 단계를 따르세요.

  1. 비공개 키를 만듭니다.

    PRIVATE_KEY_FILE="/tmp/ec_private.pem"
    openssl ecparam -genkey -name prime256v1 -noout -out ${PRIVATE_KEY_FILE}
    
  2. 비공개 키에서 공개 키를 추출합니다.

    PUBLIC_KEY_FILE="/tmp/ec_public.pem"
    openssl ec -in ${PRIVATE_KEY_FILE} -pubout -out ${PUBLIC_KEY_FILE}
    
  3. 공개 키를 증명자에 추가합니다.

    이제 Binary Authorization에서 ID 확인에 사용할 수 있도록 내보낸 공개 키를 증명자에 추가합니다.

    gcloud --project="${PROJECT_ID}" \
        beta container binauthz attestors public-keys add \
        --attestor="${ATTESTOR_NAME}" \
        --pkix-public-key-file=${PUBLIC_KEY_FILE} \
        --pkix-public-key-algorithm=ecdsa-p256-sha256
    
  4. 공개 키 ID를 저장합니다.

    공개 키 ID를 저장하려면 위의 public-keys add 결과에서 복사하면 됩니다. 증명자의 공개 키 ID를 증명자에 추가한 후 보려면 gcloud container binauthz attestors describe ${ATTESTOR_NAME}를 사용하세요.

    PUBLIC_KEY_ID=$(gcloud container binauthz attestors describe ${ATTESTOR_NAME} \
      --format='value(userOwnedGrafeasNote.publicKeys[0].id)')
    

정책 구성

이제 정책을 구성할 수 있습니다. 이 단계에서는 정책 YAML 파일을 로컬 시스템으로 내보내고 위에서 정의한 증명자의 증명을 요구하도록 기본 규칙을 수정합니다.

정책을 구성하려면 다음 단계를 따르세요.

  1. Google이 관리하는 시스템 이미지를 허용하고, evaluationModeREQUIRE_ATTESTATION으로 설정하고, 생성된 증명자를 참조하는 requireAttestationsBy라는 노드를 추가하는 새로운 정책 파일을 만듭니다.

    cat > /tmp/policy.yaml << EOM
        globalPolicyEvaluationMode: ENABLE
        defaultAdmissionRule:
          evaluationMode: REQUIRE_ATTESTATION
          enforcementMode: ENFORCED_BLOCK_AND_AUDIT_LOG
          requireAttestationsBy:
            - projects/${PROJECT_ID}/attestors/${ATTESTOR_NAME}
        name: projects/${PROJECT_ID}/policy
    EOM
    
  2. 정책 YAML 파일을 Binary Authorization으로 가져옵니다.

    gcloud container binauthz policy import /tmp/policy.yaml
    

정책 구성에 대한 자세한 내용은 gcloud CLI를 사용하여 정책 구성을 참조하세요.

정책 테스트

클러스터에 샘플 컨테이너 이미지 배포를 시도하여 위에서 구성한 정책을 테스트할 수 있습니다. 필요한 증명이 적용되지 않은 경우 정책에서 배포를 차단합니다.

이 튜토리얼에서는 Container Registry 및 Artifact Registry의 샘플 이미지를 사용할 수 있습니다. Container Registry의 이미지는 gcr.io/google-samples/hello-app:1.0 경로에 있습니다. Artifact Registry의 이미지는 us-docker.pkg.dev/google-samples/containers/gke/hello-app:1.0 경로에 있습니다. 두 경로 모두 'Hello, World!' 샘플 애플리케이션이 포함된 Google에서 생성된 공개 이미지를 포함합니다.

먼저 이미지를 배포해 봅니다.

kubectl run hello-server --image gcr.io/google-samples/hello-app:1.0 --port 8080

이제 Binary Authorization에서 배포를 차단했는지 확인합니다.

kubectl get pods

이 명령어는 이미지가 배포되지 않았음을 나타내는 다음 메시지를 출력합니다.

No resources found.

배포에 대한 세부정보를 확인할 수 있습니다.

kubectl get event --template \
'{{range.items}}{{"\033[0;36m"}}{{.reason}}:{{"\033[0m"}}\{{.message}}{{"\n"}}{{end}}'

다음과 비슷한 응답이 표시됩니다.

FailedCreate: Error creating: pods POD_NAME is forbidden: admission webhook "imagepolicywebhook.image-policy.k8s.io" denied the request: Image IMAGE_NAME denied by Binary Authorization default admission rule. Image IMAGE_NAME denied by attestor ATTESTOR_NAME: No attestations found

이 출력에서 각 항목의 의미는 다음과 같습니다.

  • POD_NAME: 포드의 이름입니다.
  • IMAGE_NAME: 이미지의 이름입니다.
  • ATTESTOR_NAME: 증명자의 이름입니다.

다음 단계를 진행하려면 배포를 삭제해야 합니다.

kubectl delete deployment hello-server

증명 만들기

증명서명자가 만든 디지털 문서로, GKE에서 연결된 컨테이너 이미지를 배포할 수 있는지 여부를 인증합니다. 증명을 만드는 프로세스는 '이미지 서명'이라고도 합니다. 서명자는 사람이거나 컨테이너 이미지를 빌드할 때 실행되는 자동화된 프로세스일 수 있습니다. 서명은 키 쌍의 비공개 키를 사용하여 생성됩니다. 배포 시 Binary Authorization 시행자는 증명의 공개 키를 사용하여 증명의 서명을 확인합니다.

이 튜토리얼에서 증명에는 단순히 이미지 배포를 승인했음이 표시됩니다.

증명을 만들려면 다음 단계를 따르세요.

  1. 이미지의 레지스트리 경로와 다이제스트를 저장할 변수를 설정합니다.

    Container Registry

    IMAGE_PATH="gcr.io/google-samples/hello-app"
    IMAGE_DIGEST="sha256:c62ead5b8c15c231f9e786250b07909daf6c266d0fcddd93fea882eb722c3be4"
    IMAGE_TO_ATTEST=${IMAGE_PATH}@${IMAGE_DIGEST}
    

    Artifact Registry

    IMAGE_PATH="us-docker.pkg.dev/google-samples/containers/gke/hello-app"
    IMAGE_DIGEST="sha256:37e5287945774f27b418ce567cd77f4bbc9ef44a1bcd1a2312369f31f9cce567"
    IMAGE_TO_ATTEST=${IMAGE_PATH}@${IMAGE_DIGEST}
    
  2. 증명을 만들려면 다음을 수행합니다.

    PKIX Cloud KMS

    Cloud KMS 키를 사용하여 증명을 만들려면 다음 명령어를 실행하세요.

    gcloud beta container binauthz attestations sign-and-create \
        --project="${PROJECT_ID}" \
        --artifact-url="${IMAGE_TO_ATTEST}" \
        --attestor="${ATTESTOR_NAME}" \
        --attestor-project="${PROJECT_ID}" \
        --keyversion-project="${KMS_KEY_PROJECT_ID}" \
        --keyversion-location="${KMS_KEY_LOCATION}" \
        --keyversion-keyring="${KMS_KEYRING_NAME}" \
        --keyversion-key="${KMS_KEY_NAME}" \
        --keyversion="${KMS_KEY_VERSION}"
    

    PKIX(로컬 키)

    로컬 키를 사용하여 증명을 만들려면 다음을 수행하세요.

    1. 증명 페이로드를 생성합니다.

      gcloud container binauthz create-signature-payload \
      --artifact-url=${IMAGE_TO_ATTEST} > /tmp/generated_payload.json
      

      페이로드 JSON 파일에 포함되는 내용은 다음과 같습니다.

      {
      "critical": {
        "identity": {
          "docker-reference": "gcr.io/google-samples/hello-app"
        },
        "image": {
          "docker-manifest-digest": "sha256:c62ead5b8c15c231f9e786250b07909daf6c266d0fcddd93fea
      882eb722c3be4"
        },
        "type": "Google cloud binauthz container signature"
      }
      }
      
    2. PKIX 비공개 키로 페이로드에 서명하고 서명 파일을 생성하려면 다음 명령어를 실행합니다.

      openssl dgst -sha256 -sign ${PRIVATE_KEY_FILE} /tmp/generated_payload.json > /tmp/ec_signature
      

      서명 파일은 이 가이드의 앞부분에서 만든 페이로드 JSON 파일의 서명된 버전입니다.

    3. 증명을 만들고 검증합니다.

      gcloud container binauthz attestations create \
        --project="${PROJECT_ID}" \
        --artifact-url="${IMAGE_TO_ATTEST}" \
        --attestor="projects/${PROJECT_ID}/attestors/${ATTESTOR_NAME}" \
        --signature-file=/tmp/ec_signature \
        --public-key-id="${PUBLIC_KEY_ID}" \
        --validate
      

      PUBLIC_KEY_ID를 위의 PKIX 키 쌍 생성에서 찾은 공개 키 ID로 바꿉니다.

      validate 플래그는 정책에 구성된 증명자로 증명을 확인할 수 있는지 검사합니다.

  3. 증명이 생성되었는지 확인합니다.

    gcloud container binauthz attestations list \
        --attestor=$ATTESTOR_NAME --attestor-project=$PROJECT_ID
    

증명 만들기에 대한 자세한 내용은 증명 만들기를 참조하세요.

정책 다시 테스트

다시 샘플 컨테이너 이미지를 클러스터에 배포하여 정책을 테스트합니다. Binary Authorization에서 이미지 경로와 다이제스트를 모두 사용하여 증명을 조회하므로 이번에는 1.0 또는 latest와 같은 태그가 아닌 다이제스트를 사용하여 이미지를 배포해야 합니다. 여기에서는 필요한 증명이 적용되었으므로 Binary Authorization을 통해 이미지를 배포할 수 있습니다.

이미지를 배포하려면 다음 단계를 따르세요.

kubectl run hello-server --image ${IMAGE_TO_ATTEST} --port 8080

이미지가 배포되었는지 확인하려면 다음을 실행하세요.

kubectl get pods

위 명령어가 반환하는 메시지는 다음과 같으며, 배포가 성공했음을 나타냅니다.

NAME                            READY     STATUS    RESTARTS   AGE
hello-server-579859fb5b-h2k8s   1/1       Running   0          1m

삭제

이 튜토리얼에서 사용된 리소스 비용이 Google Cloud 계정에 청구되지 않도록 하려면 리소스가 포함된 프로젝트를 삭제하거나 프로젝트를 유지하고 개별 리소스를 삭제하세요.

GKE에서 만든 클러스터를 삭제합니다.

gcloud container clusters delete \
    --zone=us-central1-a \
    test-cluster

다음 단계