비공개 CA 인증서로 비공개 레지스트리에 액세스


이 페이지에서는 Google Kubernetes Engine(GKE)에서 실행되는 워크로드가 레지스트리 인증서를 발급한 인증 기관(CA)의 공개 키를 사용하여 비공개 이미지 레지스트리에 액세스하도록 허용하는 방법을 보여줍니다.

작동 방식

비공개 레지스트리의 인증서를 발급하는 데 사용되는 CA의 공개 키를 Secret Manager에 저장하고 인증서 유효성 검사에 이 공개 키를 사용하는 레지스트리 정규화된 도메인 이름(FQDN)을 구성합니다. GKE는 노드 부트스트랩 중에 자동으로 키를 가져오고 컨테이너 런타임 레지스트리 구성을 업데이트합니다. 비공개 레지스트리에서 컨테이너 이미지를 사용하는 워크로드를 배포하는 경우 다음 단계가 수행됩니다.

  1. 노드의 kubelet은 비공개 레지스트리에서 이미지를 가져오려고 시도합니다.
  2. 레지스트리는 서버 측 TLS 인증서를 제공합니다.
  3. 컨테이너 런타임은 레지스트리 인증서 유효성을 암호화 방식으로 검사하고 FQDN이 개발자가 지정한 것과 일치하는지 확인합니다.
  4. 유효성 검사가 통과하면 GKE에서 이미지를 가져오고 워크로드를 예약합니다.

혜택

비공개 레지스트리에 액세스하는 이 방법은 다음과 같은 이점을 제공합니다.

  1. 컨테이너 런타임 구성 신뢰성 향상: DaemonSet과 같은 메서드를 사용하여 containerd 구성을 설정하면 구성 DaemonSet 전에 다른 DaemonSet이 실행될 수 있는 경합 상태가 발생할 위험이 높아집니다.
  2. 권한 에스컬레이션 공격에 대한 취약점 감소: 컨테이너 런타임 구성을 수정하는 권한이 있는 DaemonSet을 실행할 필요가 없습니다.
  3. 관리 오버헤드 감소: Secret Manager를 사용하면 CA 공개 키를 중앙 위치에 저장하고 IAM을 사용하여 키에 대한 액세스 권한을 관리하며 버전 제어와 주석을 구현할 수 있습니다. 자세한 내용은 Secret Manager 제품 개요를 참조하세요.
  4. 감사 기능 개선: Cloud Logging은 인증서가 클러스터에 추가되는 경우와 GKE 노드에서 이미지를 가져오는 경우를 포함하여 이미 로그를 수집합니다.

가격 책정

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

  • GKE
  • Secret Manager
  • Logging: GKE는 관리자 활동 감사 로그를 생성하고 사용 설정된 경우 이 기능에 대한 데이터 액세스 감사 로그를 생성합니다. 다양한 유형의 감사 로그에 대한 자세한 내용은 GKE 감사 로깅을 참조하세요.

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

시작하기 전에

시작하기 전에 다음 태스크를 수행했는지 확인합니다.

  • Google Kubernetes Engine API를 사용 설정합니다.
  • Google Kubernetes Engine API 사용 설정
  • 이 태스크에 Google Cloud CLI를 사용하려면 gcloud CLI를 설치한 후 초기화합니다. 이전에 gcloud CLI를 설치한 경우 gcloud components update를 실행하여 최신 버전을 가져옵니다.
  • Enable the Secret Manager API.

    Enable the API

  • 레지스트리에 액세스하려면 이미 비공개 레지스트리와 비공개 CA 인증서가 있어야 합니다. 이 가이드에서는 비공개 레지스트리 설정 또는 인증서 만들기를 설명하지 않습니다.

요구사항

비공개 CA 공개 키를 사용하여 비공개 레지스트리에 액세스하려면 다음 요구사항을 충족해야 합니다.

  • 클러스터에서는 GKE 버전 1.27.3-gke.1700 이상을 사용해야 합니다.
  • 모든 GKE 클러스터의 기본값인 containerd가 포함된 Container-Optimized OS 노드 이미지를 사용해야 합니다. containerd를 포함한 Ubuntu 노드 이미지는 지원되지 않습니다. Windows Server 노드 이미지는 지원되지 않습니다.
  • 인증서를 다운로드하려면 노드 풀에 노드에 대한 cloud-platform 액세스 범위가 있어야 합니다. 자세한 내용은 GKE의 기본 액세스 범위를 참조하세요. 이 문서에는 클러스터나 노드 풀을 만들 때 액세스 범위를 설정하는 안내가 포함되어 있습니다.

제한사항

다음 제한사항을 고려하세요.

  • Ubuntu 노드 이미지에서는 비공개 CA 인증서를 사용할 수 없습니다.
  • Windows Server 노드에서는 비공개 CA 인증서를 사용할 수 없습니다.
  • 각 클러스터는 비공개 레지스트리의 비공개 CA 인증서를 최대 5개까지 지원합니다.
  • 각 인증서에는 정규화된 도메인 이름(FQDN)이 최대 25개까지 있을 수 있습니다.
  • 각 도메인은 단일 인증서 파일에서만 사용될 수 있습니다. 그러나 인증서 번들은 지원됩니다.
  • 인증서는 PEM으로 인코딩되어야 합니다.
  • 서버에서는 인증서를 자동으로 순환하지 않습니다. 자세한 내용은 이 문서의 비공개 CA 인증서 순환을 참조하세요.
  • FQDN에는 다음과 같은 제한사항이 있습니다.
    • 최대 FQDN 길이는 특수문자를 포함하여 255자입니다.
    • FQDN에는 문자, 숫자, 대시(-)만 사용할 수 있습니다.
    • 퓨니코드는 지원되지 않습니다.
    • 와일드 카드 문자는 지원되지 않습니다.

구성 DaemonSet에서 마이그레이션

GKE Standard 클러스터에서 권한이 있는 DaemonSet을 배포하여 컨테이너 런타임 구성을 수정할 수 있습니다. 이 방법은 각 노드에서 containerd 구성을 직접 수정합니다.

권한이 있는 DaemonSet을 사용하여 비공개 레지스트리에 대한 액세스 권한을 구성하는 경우 이 문서를 수행하기 전에 다음을 고려하세요.

  • Secret Manager에 비공개 CA 공개 키를 저장하면 비공개 레지스트리에 대한 액세스 권한만 구성됩니다. 다른 레지스트리 관련 구성은 지원되지 않습니다.
  • 이 기능을 사용 설정하면 클러스터에서 이전 구성 모델과 호환되지 않는 containerd의 CRI hostpath 구성 모델이 사용됩니다. 안전하지 않은 비공개 레지스트리, 미러 또는 프록시와 같이 containerd 호스트 구성을 수정하는 DaemonSet이 있으면 CRI hostpath 모델을 사용하도록 DaemonSet을 업데이트합니다.

    CRI hostpath 모델에서 사용 가능한 필드는 containerd GitHub 저장소의 레지스트리 구성을 참조하세요.

이 기능을 사용 설정하면 GKE에서 CRI hostpath 구성 모델을 클러스터의 노드에 적용합니다. 기존 노드는 업그레이드와 같은 이벤트 중에 다시 생성될 때까지 이전 구성 모델을 계속 사용합니다.

두 구성 모델을 지원하도록 DaemonSet 업데이트

특정 구성 모델을 지원하는 노드에서 구성 DaemonSet이 작동하지 않는 위험을 줄이려면 DaemonSet에서 노드의 containerd 구성 파일에 따라 특정 구성 모델을 조건부로 사용해야 합니다. 이 조건부 논리를 구현하는 DaemonSet 예시는 GoogleCloudPlatform/k8s-node-tools GitHub 저장소에서 insecure-registry-config.yaml 매니페스트를 참조하세요.

Secret Manager에 CA 공개 키 저장

비공개 레지스트리 인증서를 발급하는 비공개 CA의 공개 키를 Secret Manager에 보안 비밀로 저장합니다. 자세한 내용은 Secret Manager 문서의 보안 비밀 만들기를 참조하세요.

GKE에서 Secret Manager에 대한 액세스 구성

클러스터의 IAM 서비스 계정에 Secret Manager에서 보안 비밀을 가져오는 데 필요한 권한이 있는지 확인하려면 관리자에게 클러스터의 IAM 서비스 계정에 보안 비밀에 대한 다음 IAM 역할을 부여해 달라고 요청하세요.

역할 부여에 대한 자세한 내용은 액세스 관리를 참조하세요.

이러한 사전 정의된 역할에는 Secret Manager에서 보안 비밀을 가져오는 데 필요한 권한이 포함되어 있습니다. 필요한 정확한 권한을 보려면 필수 권한 섹션을 펼치세요.

필수 권한

Secret Manager에서 보안 비밀을 가져오려면 다음 권한이 필요합니다.

  • resourcemanager.projects.get
  • resourcemanager.projects.list
  • secretmanager.secrets.get
  • secretmanager.secrets.list
  • secretmanager.versions.get
  • secretmanager.versions.list
  • secretmanager.versions.access

관리자는 커스텀 역할이나 다른 사전 정의된 역할을 사용하여 클러스터의 IAM 서비스 계정에 이러한 권한을 부여할 수도 있습니다.

커스텀 IAM 서비스 계정을 클러스터나 노드 풀과 연결하지 않았으면(Google에서 권장한 방식) 클러스터에서 Compute Engine 기본 서비스 계정을 사용합니다. 가능하면 최소한의 권한이 있는 IAM 서비스 계정으로 클러스터와 노드 풀을 구성하는 것이 좋습니다. 자세한 내용은 최소 권한이 있는 서비스 계정 사용을 참조하세요.

런타임 구성 파일 만들기

GKE에서 비공개 레지스트리에 비공개 CA 인증서를 사용할 수 있게 하려면 YAML 파일을 만들어 containerd 구성을 수정합니다.

  1. Google Cloud 프로젝트 번호를 가져옵니다.

    gcloud projects describe PROJECT_ID \
        --format="value(projectNumber)"
    

    출력은 숫자 프로젝트 번호입니다.

  2. 다음 구성을 containerd-configuration.yaml로 저장합니다.

    privateRegistryAccessConfig:
      certificateAuthorityDomainConfig:
      - gcpSecretManagerCertificateConfig:
          secretURI: "projects/PROJECT_NUMBER/secrets/SECRET_NAME/versions/SECRET_VERSION"
        fqdns:
          - "FQDN1"
          - "FQDN2"
      enabled: true
    

    다음을 바꿉니다.

    • PROJECT_NUMBER: 이전 단계에서 가져온 프로젝트 번호입니다.
    • SECRET_VERSION: Secret Manager에 있는 보안 비밀의 버전 번호입니다. 선택적으로 버전 별칭을 사용할 수 있지만 관리 복잡성이 방지되도록 버전 번호를 사용하는 것이 좋습니다.
    • FQDN1, FQDN2: 비공개 레지스트리의 정규화된 도메인 이름입니다. 인증서가 해당 주소에 발급된 경우 IPv4 주소를 사용할 수도 있지만 사용하지 않는 것이 좋습니다.

이러한 필드에 대한 설명은 사용 가능한 containerd 구성 옵션 표의 privateRegistryAccessConfig를 참조하세요.

새 클러스터에 containerd 구성 적용

이 섹션에서는 새 GKE 클러스터를 만들 때 containerd 구성 파일을 적용하는 방법을 보여줍니다.

다음 명령어를 실행합니다.

gcloud container clusters create-auto CLUSTER_NAME \
    --location=LOCATION \
    --scopes="cloud-platform" \
    --containerd-config-from-file="PATH_TO_CONFIG_FILE"

다음을 바꿉니다.

  • CLUSTER_NAME: 새 클러스터의 이름
  • LOCATION: 새 클러스터의 Compute Engine 위치
  • PATH_TO_CONFIG_FILE: 생성된 구성 파일의 경로(예: ~/containerd-configuration.yaml)

같은 옵션으로 gcloud container clusters create 명령어를 실행하여 새 표준 클러스터에서 비공개 레지스트리 구성을 사용 설정할 수 있습니다.

기존 클러스터에 containerd 구성 적용

이 섹션에서는 기존 클러스터와 노드에 containerd 구성을 적용하는 방법을 보여줍니다.

액세스 범위 확인

이 기능을 사용하려면 기존 클러스터에 cloud-platform 액세스 범위가 있어야 합니다. 이 섹션에서는 액세스 범위를 확인하고 새롭거나 수정된 비공개 레지스트리 구성 파일로 기존 클러스터를 업데이트하는 방법을 보여줍니다.

새 클러스터의 기본 액세스 범위에 대한 자세한 내용은 GKE의 액세스 범위를 참조하세요.

Autopilot 액세스 범위 확인

다음 명령어를 실행합니다.

gcloud container clusters describe CLUSTER_NAME \
    --location=LOCATION \
    --flatten=nodeConfig \
    --format='csv[delimiter="\\n",no-heading](oauthScopes)'

클러스터에 https://www.googleapis.com/auth/cloud-platform 액세스 범위가 없으면 이 액세스 범위로 새 클러스터를 만듭니다.

표준 액세스 범위 확인

표준 클러스터 액세스 범위를 확인하려면 노드 풀을 확인합니다.

gcloud container node-pools describe NODE_POOL_NAME \
    --cluster=CLUSTER_NAME \
    --location=LOCATION \
    --flatten=nodeConfig \
    --format='csv[delimiter="\\n",no-heading](oauthScopes)'

NODE_POOL_NAME을 노드 풀의 이름으로 바꿉니다.

클러스터에 https://www.googleapis.com/auth/cloud-platform 액세스 범위가 없으면 cloud-platform 액세스 범위로 새 노드 풀을 만들고 기존 노드 풀을 삭제합니다.

구성 파일을 사용하도록 클러스터 업데이트

다음 명령어를 실행합니다.

gcloud container clusters update CLUSTER_NAME \
    --location=LOCATION \
    --containerd-config-from-file="PATH_TO_CONFIG_FILE"

표준 클러스터에서 노드 다시 만들기

표준 클러스터에서 자동 업그레이드를 사용하지 않는 경우에 노드 풀을 수동으로 다시 만들어 새 구성을 적용해야 합니다. 수동으로 노드 다시 만들기를 트리거하려면 클러스터를 이미 사용 중인 같은 GKE 버전으로 업그레이드합니다.

gcloud container clusters upgrade CLUSTER_NAME \
    --location=LOCATION \
    --cluster-version=VERSION

VERSION을 클러스터에서 이미 사용 중인 같은 GKE 패치 버전으로 바꿉니다.

클러스터에서 비공개 레지스트리에 액세스할 수 있는지 확인

다음 명령어를 실행합니다.

gcloud container clusters describe CLUSTER_NAME \
    --location=LOCATION \
    --flatten="nodePoolDefaults.nodeConfigDefaults.containerdConfig"

출력은 다음과 비슷합니다.

    containerdConfig:
      privateRegistryAccessConfig:
        certificateAuthorityDomainConfig:
        - fqdns:
          - 203.0.113.105
          gcpSecretManagerCertificateConfig:
            secretUri: projects/123456789012/secrets/example-secret-name/versions/1
        enabled: true

비공개 이미지에 액세스하는 워크로드 배포

이 섹션에서는 비공개 레지스트리의 이미지를 참조하는 정적 포드를 배포합니다.

  1. 다음 매니페스트를 private-registry-pod.yaml로 저장합니다.

    apiVersion: v1
    kind: Pod
    metadata:
      name: private-registry-pod
    spec:
      containers:
      - name: private-image
        image: IMAGE_NAME
    

    IMAGE_NAME을 비공개 이미지 이름으로 바꿉니다.

  2. 포드를 배포합니다.

    kubectl create -f private-registry-pod.yaml
    

비공개 CA 인증서 순환

Secret Manager와 GKE는 Secret Manager에서 비공개 CA 인증서를 자동으로 순환할 수 없습니다. 인증서 순환을 수행하려면 다음 단계를 수행합니다. 다음 단계에서는 기존 노드를 두 번 다시 만들어야 합니다. 워크로드 중단의 영향이 최소화되도록 예정된 다운타임 중에 인증서를 순환하는 것이 좋습니다.

  1. 이전 인증서와 새 인증서 모두 포함된 PEM 인코딩 인증서 번들을 만듭니다.
  2. Secret Manager에 번들을 새 보안 비밀 버전으로 추가합니다.
  3. 런타임 구성 파일 secretURI 필드를 새 보안 비밀 버전 번호로 업데이트합니다.
  4. 새 보안 비밀 버전을 사용하도록 클러스터를 업데이트합니다.
  5. 업데이트 작업의 타임스탬프를 가져옵니다.

    gcloud container operations list \
        --filter="operationType ~ UPDATE_CLUSTER AND targetLink ~ CLUSTER_NAME" \
        --sort-by=startTime \
        --limit=1 \
        --format='value(endTime)'
    

    출력은 다음과 비슷합니다.

    2024-01-31T09:27:30.864308964Z
    
  6. 업데이트 작업이 종료되기 전에 생성된 노드를 찾습니다.

    kubectl get nodes -o json | jq ".items[] |
    select(.metadata.creationTimestamp | fromdateiso8601 < $(date -d
    CLUSTER_UPDATE_TIMESTAMP +%s)) | .metadata.name"
    

    CLUSTER_UPDATE_TIMESTAMP를 이전 단계의 타임스탬프로 바꿉니다.

    출력은 업데이트된 구성으로 다시 생성되지 않은 노드 이름의 목록입니다. 출력이 비어 있으면 다음 단계로 진행합니다.

  7. 새 인증서만 사용하여 Secret Manager에 새 버전의 보안 비밀을 만듭니다.

  8. 이전 단계를 반복하여 클러스터를 업데이트하고 작업 타임스탬프를 가져오고 노드에서 새 보안 비밀 버전을 사용하는지 확인합니다.

  9. Secret Manager에서 이전 보안 비밀 버전을 삭제합니다.

Logging에서 감사 로그 보기

이 섹션에서는 Logging을 사용하여 GKE에서 노드에 보안 비밀 버전을 설치했는지 여부를 확인하는 방법을 보여줍니다.

  1. Google Cloud 콘솔의 로그 탐색기 페이지로 이동합니다.

    로그 탐색기로 이동

  2. 다음 쿼리를 지정합니다.

    resource.type="gce_instance"
    textPayload:"Installed certificate \\\"projects/PROJECT_NUMBER/secrets/SECRET_NAME/versions/SECRET_VERSION\\\""
    

    인증서 설치가 성공하면 출력은 다음과 비슷합니다.

    "Installed certificate "projects/PROJECT_NUMBER/secrets/SECRET_NAME/versions/SECRET_VERSION""
    

    인증서 설치가 실패하면 출력은 다음과 비슷합니다.

    "Failed to install certificate "projects/PROJECT_NUMBER/secrets/SECRET_NAME/versions/SECRET_VERSION""
    

권장사항

이 기능을 사용할 때 다음 권장사항을 따르는 것이 좋습니다.

  • Secret Manager 보안 비밀 버전에 별칭을 사용하지 마세요. 보안 비밀 버전마다 자동 생성된 버전 번호를 사용합니다. 별칭은 시간이 경과함에 따라 다른 인증서 버전을 가리킬 수 있으므로 워크로드에서 사용하는 특정 버전을 추적하기가 복잡해질 수 있습니다.
  • 유지보수 기간 및 제외를 사용하여 GKE에서 노드를 다시 만들어 업데이트된 containerd 구성을 적용할 수 있는 시기를 제어합니다.
  • 프로젝트 수준이 아닌 보안 비밀 수준에서 보안 비밀에 대한 액세스 권한을 제공합니다.

containerd 구성 옵션 중지

커스텀 구성을 삭제하려면 다음을 수행합니다.

  1. 다음 예시와 같이 구성 파일을 업데이트하여 중지하려는 구성 항목에서 enabled: false를 지정하고 항목의 다른 모든 필드를 삭제합니다.

    privateRegistryAccessConfig:
      enabled: false
  2. 업데이트된 구성 파일을 클러스터에 적용합니다. 자세한 내용은 기존 클러스터에 containerd 구성 적용을 참조하세요.

문제 해결

문제 해결 단계는 컨테이너 런타임 문제 해결을 참조하세요.