GKE 비공개 클러스터의 제한된 액세스 구성

이 문서에서는 VPC 서비스 제어 서비스 경계에서 Google Kubernetes Engine 비공개 클러스터를 사용할 때 제한된 가상 IP(VIP)를 사용하여 pkg.devgcr.io 도메인으로 요청을 라우팅하도록 DNS 항목을 구성하는 방법을 설명합니다.

이러한 레지스트리 도메인은 일반적으로 인터넷의 공개 IP 주소로 확인됩니다. GKE 비공개 클러스터에서 노드는 기본적으로 인터넷에서 격리됩니다. 즉, 제한된 VIP에 대한 DNS 라우팅을 구성하지 않는 경우 레지스트리에 대한 요청이 실패함을 의미합니다.

비공개 클러스터는 항상 제한된 VIP를 통해 Artifact Registry 또는 Container Registry에 액세스하여 지원되는 서비스에서 지원되지 않는 서비스로의 데이터 무단 반출을 방지해야 합니다.

이 단계는 다음과 같은 경우에만 필요합니다.

  • GKE 비공개 클러스터를 사용 중입니다.
  • pkg.dev 또는 gcr.io 레지스트리 도메인의 라우팅을 restricted.googleapis.com으로 아직 구성하지 않았습니다.

시작하기 전에

서비스 경계를 만들기 전에 새로운 비공개 클러스터를 설정하거나 보호하려는 기존 비공개 클러스터를 식별합니다.

또한 443 포트에서 199.36.153.4/30으로의 이그레스를 허용해야 합니다. 일반적으로 VPC 네트워크에는 모든 대상으로의 이그레스 트래픽을 허용하는 임시 규칙이 있습니다. 그러나 이러한 트래픽을 거부하는 규칙이 있으면 포트 443의 TCP 트래픽을 199.36.153.4/30으로 허용하는 이그레스 방화벽 규칙을 만들어야 합니다.

DNS 구성

레지스트리 주소에 대한 요청이 제한된 VIP인 restricted.googleapis.com으로 확인되도록 DNS 서버를 구성합니다. Cloud DNS 비공개 DNS 영역을 사용하여 이렇게 구성할 수 있습니다.

  1. 관리형 비공개 영역을 만듭니다.

    gcloud dns managed-zones create ZONE_NAME \
        --visibility=private \
        --networks=https://www.googleapis.com/compute/v1/projects/PROJECT_ID/global/networks/NETWORK \
        --description=DESCRIPTION \
        --dns-name=REGISTRY_DOMAIN \
        --project=PROJECT_ID
    

    각 항목의 의미는 다음과 같습니다.

    • ZONE_NAME은 만들려는 영역의 이름입니다. 예를 들면 registry입니다. 이 이름은 다음과 같은 각 단계에서 사용됩니다.

    • PROJECT_ID는 GKE 비공개 클러스터를 호스팅하는 프로젝트의 ID입니다.

    • NETWORK는 요청을 리디렉션할 클러스터 네트워크 이름의 선택적 목록입니다.

    • DESCRIPTION은 관리형 영역에 대한 사람이 읽을 수 있는 설명입니다.

    • REGISTRY_DOMAIN은 레지스트리의 도메인입니다.

      • Artifact Registry의 경우 pkg.dev
      • Container Registry 또는 Artifact Registry에 호스팅되는 gcr.io 저장소의 경우 gcr.io
  2. 트랜잭션을 시작합니다.

    gcloud dns record-sets transaction start \
      --zone=ZONE_NAME \
      --project=PROJECT_ID
    

    각 항목의 의미는 다음과 같습니다.

    • ZONE_NAME은 첫 번째 단계에서 생성한 영역의 이름입니다.

    • PROJECT_ID는 GKE 비공개 클러스터를 호스팅하는 프로젝트의 ID입니다.

  3. 레지스트리에 CNAME 레코드를 추가합니다.

    gcloud dns record-sets transaction add \
      --name=*.REGISTRY_DOMAIN. \
      --type=CNAME REGISTRY_DOMAIN. \
      --zone=ZONE_NAME \
      --ttl=300 \
      --project=PROJECT_ID
    

    각 항목의 의미는 다음과 같습니다.

    • ZONE_NAME은 첫 번째 단계에서 생성한 영역의 이름입니다.

    • PROJECT_ID는 GKE 비공개 클러스터를 호스팅하는 프로젝트의 ID입니다.

    • REGISTRY_DOMAIN은 레지스트리의 도메인입니다.

      • Artifact Registry의 경우 pkg.dev
      • Container Registry 또는 Artifact Registry에 호스팅되는 gcr.io 저장소의 경우 gcr.io
  4. 제한된 VIP에 A 레코드를 추가합니다.

    gcloud dns record-sets transaction add \
      --name=REGISTRY_DOMAIN. \
      --type=A 199.36.153.4 199.36.153.5 199.36.153.6 199.36.153.7 \
      --zone=ZONE_NAME \
      --ttl=300 \
      --project=PROJECT_ID
    

    각 항목의 의미는 다음과 같습니다.

    • ZONE_NAME은 첫 번째 단계에서 생성한 영역의 이름입니다.

    • PROJECT_ID는 GKE 비공개 클러스터를 호스팅하는 프로젝트의 ID입니다.

    • REGISTRY_DOMAIN은 레지스트리의 도메인입니다.

      • Artifact Registry의 경우 pkg.dev
      • Container Registry 또는 Artifact Registry에 호스팅되는 gcr.io 저장소의 경우 gcr.io
  5. 트랜잭션을 실행합니다.

    gcloud dns record-sets transaction execute \
      --zone=ZONE_NAME \
      --project=PROJECT_ID
    

    각 항목의 의미는 다음과 같습니다.

    • ZONE_NAME은 첫 번째 단계에서 생성한 영역의 이름입니다.

    • PROJECT_ID는 GKE 비공개 클러스터를 호스팅하는 프로젝트의 ID입니다.

DNS 라우팅을 구성한 후 GKE, 레지스트리, 기타 필수 서비스가 VPC 서비스 제어 서비스 경계 내에 있는지 확인합니다. 서비스 경계를 구성하려면 다음 섹션을 참조하세요.

서비스 경계 구성

DNS 레코드를 구성한 후에는 새로운 서비스 경계를 생성하거나 기존 경계를 업데이트한 후 서비스 경계를 사용하여 보호하려는 서비스 목록에 Container Registry 또는 Artifact Registry 서비스를 추가합니다.

또한 다음 사항도 적용됩니다.

  • 레지스트리와 함께 사용하는 다른 지원 서비스(예: Cloud Build, Artifact Analysis, Binary Authorization)를 서비스 경계에 추가합니다.
  • Container Registry의 경우 Cloud Storage도 서비스 경계에 추가해야 합니다.

경계가 작동하는지 확인

서비스 경계를 구성한 후 GKE 비공개 클러스터의 노드는 Artifact Registry 및 Container Registry의 컨테이너 이미지가 서비스 경계에 있는 프로젝트에 저장된 경우 해당 컨테이너 이미지에 액세스할 수 있습니다.

일부 특정 읽기 전용 공개 저장소를 제외하고 경계 외부의 프로젝트에 있는 컨테이너 이미지에는 계속 액세스할 수 없습니다.

예를 들어 google-samples 프로젝트가 서비스 경계에 없는 경우 hello-app 컨테이너에서 배포를 만드는 명령어를 실행하면 실패합니다.

pkg.dev 도메인

kubectl create deployment hello-server --image=us-docker.pkg.dev/google-samples/containers/gke/hello-app:1.0

gcr.io 도메인

kubectl create deployment hello-server --image=gcr.io/google-samples/hello-app:1.0

다음 명령어로 Pod 상태를 확인합니다.

kubectl get pods

이 명령어는 다음 예시와 비슷한 테이블을 반환합니다. 포드 상태 ErrImagePull은 가져오기가 실패했음을 나타냅니다.

NAME                            READY   STATUS         RESTARTS   AGE
hello-server-dbd86c8c4-h5wsf    1/1     ErrImagePull   0          45s

kubectl describe pod 명령어를 사용하여 배포에 대한 세부정보를 볼 수 있습니다. 이전 예시에 있는 pod의 경우 명령어는 다음과 같습니다.

kubectl describe pod hello-server-dbd86c8c4-h5wsf