GKE 인증 문제 해결


이 페이지에서는 Google Kubernetes Engine(GKE) Autopilot 및 Standard 클러스터의 보안 구성과 관련된 문제를 해결하는 방법을 설명합니다.

RBAC 및 IAM

인증된 IAM 계정이 클러스터 내 작업을 수행하지 못함

다음 문제는 클러스터에서 작업을 수행하려고 하는데 GKE에서 작업을 승인하는 RBAC 정책을 찾을 수 없을 때 발생합니다. GKE는 동일한 권한을 부여하는 IAM 허용 정책을 찾으려고 시도합니다. 이 작업이 실패하면 다음과 유사한 오류 메시지가 표시됩니다.

Error from server (Forbidden): roles.rbac.authorization.k8s.io is forbidden:
User "example-account@example-project.iam.gserviceaccount.com" cannot list resource "roles" in
API group "rbac.authorization.k8s.io" in the namespace "kube-system": requires
one of ["container.roles.list"] permission(s).

이 문제를 해결하려면 RBAC 정책을 사용하여 시도한 작업에 대한 권한을 부여합니다. 예를 들어 이전 샘플의 문제를 해결하려면 kube-system 네임스페이스의 roles 객체에서 list 권한이 있는 역할을 부여합니다. 자세한 내용은 역할 기반 액세스 제어를 사용한 클러스터의 작업 승인을 참조하세요.

GKE용 워크로드 아이덴티티 제휴

포드가 Google Cloud에 인증할 수 없음

애플리케이션이 Google Cloud에 인증할 수 없으면 다음 설정이 올바르게 구성되었는지 확인합니다.

  1. GKE 클러스터가 포함된 프로젝트에서 IAM Service Account Credentials API를 사용 설정했는지 확인합니다.

    IAM Credentials API 사용 설정

  2. 워크로드 아이덴티티 풀이 설정되어 있는지 확인하여 클러스터에서 GKE용 워크로드 아이덴티티 제휴가 사용 설정되었는지 확인합니다.

    gcloud container clusters describe CLUSTER_NAME \
        --format="value(workloadIdentityConfig.workloadPool)"
    

    CLUSTER_NAME을 GKE 클러스터 이름으로 바꿉니다.

    gcloud의 기본 영역 또는 리전을 아직 지정하지 않았으면 이 명령어를 실행할 때 --region 또는 --zone 플래그를 지정해야 할 수도 있습니다.

  3. 애플리케이션이 실행 중인 노드 풀에서 GKE 메타데이터 서버가 구성되었는지 확인합니다.

    gcloud container node-pools describe NODEPOOL_NAME \
        --cluster=CLUSTER_NAME \
        --format="value(config.workloadMetadataConfig.mode)"
    

    다음을 바꿉니다.

    • NODEPOOL_NAME을 노드 풀 이름으로 바꿉니다.
    • CLUSTER_NAME을 GKE 클러스터 이름으로 바꿉니다.
  4. Kubernetes 서비스 계정이 올바르게 주석 처리되었는지 확인합니다.

    kubectl describe serviceaccount \
        --namespace NAMESPACE KSA_NAME
    

    다음을 바꿉니다.

    • NAMESPACE를 GKE 클러스터의 네임스페이스로 바꿉니다.
    • KSA를 Kubernetes 서비스 계정의 이름으로 바꿉니다.

    예상 출력에는 다음과 비슷한 주석이 포함됩니다.

    iam.gke.io/gcp-service-account: GSA_NAME@PROJECT_ID.iam.gserviceaccount.com
    
  5. IAM 서비스 계정이 올바르게 구성되어 있는지 확인합니다.

    gcloud iam service-accounts get-iam-policy \
        GSA_NAME@GSA_PROJECT.iam.gserviceaccount.com
    

    예상 출력에 다음과 유사한 바인딩이 포함됩니다.

    - members:
      - serviceAccount:PROJECT_ID.svc.id.goog[NAMESPACE/KSA_NAME]
      role: roles/iam.workloadIdentityUser
    
  6. 클러스터 네트워크 정책이 있는 경우 1.21.0-gke.1000 이전 GKE 버전을 실행하는 클러스터에 대해서는 포트 988에서 127.0.0.1/32로의 이그레스를 허용했고 GKE 버전 1.21.0-gke.1000 이상을 실행하는 클러스터에 대해서는 포트 988에서 169.254.169.252/32로의 이그레스를 허용해야 합니다. GKE Dataplane V2를 실행하는 클러스터의 경우 포트 80169.254.169.254/32로 이그레스를 허용해야 합니다.

    kubectl describe networkpolicy NETWORK_POLICY_NAME
    

    NETWORK_POLICY_NAME을 GKE 네트워크 정책 이름으로 바꿉니다.

IAM 서비스 계정 액세스가 거부됨

IAM 역할 바인딩을 추가한 직후 포드가 GKE용 워크로드 아이덴티티 제휴로 리소스에 액세스하지 못할 수 있습니다. 액세스 실패는 IAM 허용 정책, 역할 바인딩, Kubernetes 포드와 같은 리소스가 함께 생성되는 배포 파이프라인이나 선언적 Google Cloud 구성에서 발생할 가능성이 더 높습니다. 포드 로그에 다음 오류 메시지가 표시됩니다.

HTTP/403: generic::permission_denied: loading: GenerateAccessToken("SERVICE_ACCOUNT_NAME@PROJECT_ID.iam.gserviceaccount.com", ""): googleapi: Error 403: Permission 'iam.serviceAccounts.getAccessToken' denied on resource (or it may not exist).

이 오류는 IAM의 액세스 변경 전파로 인해 발생할 수 있습니다. 즉, 역할 부여와 같은 액세스 변경사항이 시스템 전체에 전파되는 데 시간이 걸립니다. 역할 부여의 경우 일반적으로 전파되는 데 2분 정도 걸리지만 7분 이상 걸릴 수도 있습니다. 자세한 내용은 액세스 변경 전파를 참조하세요.

이 오류를 해결하려면 포드가 생성된 후 Google Cloud 리소스에 액세스하려고 시도하기 전에 지연 시간을 추가하는 것이 좋습니다.

DNS 변환 문제

이 섹션에서는 DNS 변환 문제로 인해 포드에서 Google Cloud API로의 연결 오류를 식별하고 해결하는 방법을 설명합니다. 이 섹션의 단계로 연결 오류가 해결되지 않으면 포드 시작 시 제한 시간 오류 섹션을 참조하세요.

일부 Google Cloud 클라이언트 라이브러리는 DNS 이름 metadata.google.internal을 변환하여 GKE 및 Compute Engine 메타데이터 서버에 연결되도록 구성되어 있습니다. 이러한 라이브러리의 경우 정상 클러스터 내 DNS 변환은 워크로드가Google Cloud 서비스에 인증하는 데 중요한 종속 항목입니다.

이 문제를 감지하는 방법은 로깅 구성을 포함하여 배포된 애플리케이션의 세부정보에 따라 달라집니다. GOOGLE_APPLICATION_CREDENTIALS를 구성하라는 오류 메시지, 요청에 사용자 인증 정보가 없어Google Cloud 서비스에 대한 요청이 거부되었다는 오류 메시지, 메타데이터 서버를 찾을 수 없다는 오류 메시지를 찾습니다.

예를 들어 다음 오류 메시지는 DNS 변환 문제가 있음을 나타낼 수 있습니다.

ComputeEngineCredentials cannot find the metadata server. This is likely because code is not running on Google Compute Engine

metadata.google.internal의 DNS 변환 문제가 발생하면 환경 변수 GCE_METADATA_HOST169.254.169.254로 설정하여 일부 Google Cloud 클라이언트 라이브러리에 DNS 변환을 건너뛰라고 지시할 수 있습니다.

apiVersion: v1
kind: Pod
metadata:
  name: example-pod
  namespace: default
spec:
  containers:
  - image: debian
    name: main
    command: ["sleep", "infinity"]
    env:
    - name: GCE_METADATA_HOST
      value: "169.254.169.254"

이는 Google Cloud 컴퓨팅 플랫폼에서 메타데이터 서비스를 항상 사용할 수 있는 하드 코딩된 IP 주소입니다.

다음 Google Cloud 라이브러리가 지원됩니다.

  • Python
  • Java
  • Node.js
  • Golang

    기본적으로 Go 클라이언트 라이브러리는 IP 주소를 사용하여 연결합니다.

포드 시작 시 제한 시간 오류

GKE 메타데이터 서버가 새 포드에서 요청을 수락하려면 몇 초가 걸려야 합니다. 포드 수명의 첫 몇 초 내에 GKE용 워크로드 아이덴티티 제휴를 사용하여 인증을 시도할 경우 짧은 제한 시간 동안 구성된 애플리케이션과 Google Cloud 클라이언트 라이브러리에서 인증이 실패할 수 있습니다.

제한 시간 오류가 발생하면 다음을 시도합니다.

  • 워크로드에서 사용하는 Google Cloud 클라이언트 라이브러리를 업데이트합니다.
  • 애플리케이션 코드를 변경하고 몇 초 후에 다시 시도합니다.
  • 포드의 기본 컨테이너를 실행하기 전에 GKE 메타데이터 서버를 사용할 수 있을 때까지 기다리는 initContainer를 배포합니다.

    예를 들어 다음 매니페스트는 initContainer가 있는 포드를 위한 것입니다.

    apiVersion: v1
    kind: Pod
    metadata:
      name: pod-with-initcontainer
    spec:
      serviceAccountName: KSA_NAME
      initContainers:
      - image:  gcr.io/google.com/cloudsdktool/cloud-sdk:alpine
        name: workload-identity-initcontainer
        command:
        - '/bin/bash'
        - '-c'
        - |
          curl -sS -H 'Metadata-Flavor: Google' 'http://169.254.169.254/computeMetadata/v1/instance/service-accounts/default/token' --retry 30 --retry-connrefused --retry-max-time 60 --connect-timeout 3 --fail --retry-all-errors > /dev/null && exit 0 || echo 'Retry limit exceeded. Failed to wait for metadata server to be available. Check if the gke-metadata-server Pod in the kube-system namespace is healthy.' >&2; exit 1
      containers:
      - image: gcr.io/your-project/your-image
        name: your-main-application-container
    

컨트롤 플레인 사용 불가로 인한 GKE용 워크로드 아이덴티티 제휴 실패

클러스터 컨트롤 플레인을 사용할 수 없으면 메타데이터 서버가 GKE용 워크로드 아이덴티티 제휴를 반환할 수 없습니다. 메타데이터 서버를 호출하면 상태 코드 500이 반환됩니다.

로그 항목은 로그 탐색기에서 다음과 비슷하게 표시될 수 있습니다.

dial tcp 35.232.136.58:443: connect: connection refused

이 동작으로 인해 GKE용 워크로드 아이덴티티 제휴를 사용할 수 없습니다.

IP 순환, 컨트롤 플레인 VM 업그레이드, 클러스터 또는 노드 풀 크기 조정과 같이 클러스터 유지보수 중에는 영역 클러스터에서 컨트롤 플레인을 사용하지 못할 수 있습니다. 컨트롤 플레인 가용성에 대한 자세한 내용은 리전 또는 영역별 컨트롤 플레인 선택을 참조하세요. 리전 클러스터로 전환하면 이 문제가 사라집니다.

Istio를 사용하는 클러스터에서 GKE용 워크로드 아이덴티티 제휴 인증 실패

애플리케이션이 시작되고 엔드포인트와 통신하려고 할 때 다음과 비슷한 오류가 표시될 수 있습니다.

Connection refused (169.254.169.254:80)
Connection timeout

이러한 오류는 istio-proxy 컨테이너가 준비되기 전에 애플리케이션에서 네트워크 연결을 시도할 때 발생할 수 있습니다. 기본적으로 Istio 및 Cloud Service Mesh는 트래픽을 가로채고 리디렉션하는 서비스 메시 프록시 워크로드 실행 여부와 관계없이 워크로드가 시작되는 즉시 요청을 보낼 수 있도록 허용합니다. GKE용 워크로드 아이덴티티 제휴를 사용하는 포드의 경우 프록시가 시작되기 전에 발생하는 이러한 초기 요청이 GKE 메타데이터 서버에 도달하지 않을 수 있습니다. 이로 인해 Google Cloud API에 대한 인증이 실패합니다. 애플리케이션에서 요청을 재시도하도록 구성하지 않으면 워크로드가 실패할 수 있습니다.

이 문제가 오류의 원인인지 확인하려면 로그를 보고 istio-proxy 컨테이너가 성공적으로 시작되었는지 확인합니다.

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

    로그 탐색기로 이동

  2. 쿼리 창에 다음 쿼리를 입력합니다.

    (resource.type="k8s_container"
    resource.labels.pod_name="POD_NAME"
    textPayload:"Envoy proxy is ready" OR textPayload:"ERROR_MESSAGE")
    OR
    (resource.type="k8s_pod"
    logName:"events"
    jsonPayload.involvedObject.name="POD_NAME")
    

    다음을 바꿉니다.

    • POD_NAME: 영향을 받는 워크로드가 있는 포드의 이름
    • ERROR_MESSAGE: 애플리케이션에서 수신한 오류(connection timeout 또는 connection refused)
  3. 쿼리 실행을 클릭합니다.

  4. 출력을 검토하고 istio-proxy 컨테이너가 준비된 시점을 확인합니다.

    다음 예시에서는 애플리케이션이 gRPC 호출을 시도했습니다. 하지만 istio-proxy 컨테이너가 계속 초기화되고 있었으므로 애플리케이션에 Connection refused 오류가 발생했습니다. Envoy proxy is ready 메시지 옆의 타임스탬프는 istio-proxy 컨테이너에서 연결 요청 준비가 된 시점을 나타냅니다.

    2024-11-11T18:37:03Z started container istio-init
    2024-11-11T18:37:12Z started container gcs-fetch
    2024-11-11T18:37:42Z Initializing environment
    2024-11-11T18:37:55Z Started container istio-proxy
    2024-11-11T18:38:06Z StatusCode="Unavailable", Detail="Error starting gRPC call. HttpRequestException: Connection refused (169.254.169.254:80)
    2024-11-11T18:38:13Z Envoy proxy is ready
    

이 문제를 해결하고 재발을 방지하려면 다음 워크로드별 구성 옵션 중 하나를 사용해 보세요.

  • 프록시 워크로드가 준비될 때까지 애플리케이션에서 요청을 보내지 못하게 합니다. 다음 주석을 포드 사양의 metadata.annotations 필드에 추가합니다.

    proxy.istio.io/config: '{ "holdApplicationUntilProxyStarts": true }'
    
  • GKE 메타데이터 서버의 IP 주소가 리디렉션에서 제외되도록 Istio 또는 Cloud Service Mesh를 구성합니다. 다음 주석을 포드 사양의 metadata.annotations 필드에 추가합니다.

    traffic.sidecar.istio.io/excludeOutboundIPRanges: 169.254.169.254/32
    

오픈소스 Istio에서는 다음 전역 구성 옵션 중 하나를 설정하여 모든 포드에서 이 문제를 선택적으로 완화할 수 있습니다.

  • 리디렉션에서 GKE 메타데이터 서버 IP 주소 제외: 169.254.169.254/32 IP 주소 범위가 추가되도록 global.proxy.excludeIPRanges 전역 구성 옵션을 업데이트합니다.

  • 프록시가 시작할 때까지 애플리케이션에서 요청을 보내지 못하도록 방지: 값이 trueglobal.proxy.holdApplicationUntilProxyStarts 전역 구성 옵션을 Istio 구성에 추가합니다.

gke-metadata-server 포드가 비정상 종료됨

gke-metadata-server 시스템 DaemonSet 포드는 노드에서 GKE용 워크로드 아이덴티티 제휴를 용이하게 합니다. 포드는 클러스터의 Kubernetes 서비스 계정 수에 비례하는 메모리 리소스를 사용합니다.

다음 문제는 gke-metadata-server 포드의 리소스 사용량이 한도를 초과하면 발생합니다. kubelet은 메모리 부족 오류가 있는 포드를 제거합니다. 클러스터에 3,000개가 넘는 Kubernetes 서비스 계정이 있으면 이 문제가 발생할 수 있습니다.

문제를 식별하려면 다음을 수행합니다.

  1. kube-system 네임스페이스에서 비정상 종료 gke-metadata-server 포드를 찾습니다.

    kubectl get pods -n=kube-system | grep CrashLoopBackOff
    

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

    NAMESPACE     NAME                        READY     STATUS             RESTARTS   AGE
    kube-system   gke-metadata-server-8sm2l   0/1       CrashLoopBackOff   194        16h
    kube-system   gke-metadata-server-hfs6l   0/1       CrashLoopBackOff   1369       111d
    kube-system   gke-metadata-server-hvtzn   0/1       CrashLoopBackOff   669        111d
    kube-system   gke-metadata-server-swhbb   0/1       CrashLoopBackOff   30         136m
    kube-system   gke-metadata-server-x4bl4   0/1       CrashLoopBackOff   7          15m
    
  2. 비정상 종료 포드를 설명하여 메모리 부족 제거가 원인임을 확인합니다.

    kubectl describe pod POD_NAME --namespace=kube-system | grep OOMKilled
    

    POD_NAME을 확인할 포드 이름으로 바꿉니다.

GKE 메타데이터 서버로 기능을 복원하려면 클러스터의 서비스 계정 수를 3,000개 미만으로 줄입니다.

DeployPatch 실패 오류 메시지와 함께 GKE용 워크로드 아이덴티티 제휴 사용 설정 실패

GKE는 Google Cloud관리형 Kubernetes Engine 서비스 에이전트를 사용하여 클러스터에서 GKE용 워크로드 아이덴티티 제휴를 용이하게 합니다. Google Kubernetes Engine API를 사용 설정하면 Google Cloud 에서 이 서비스 에이전트에 프로젝트에 대한 Kubernetes Engine 서비스 에이전트 역할(roles/container.serviceAgent)을 자동으로 부여합니다.

서비스 에이전트에 Kubernetes Engine 서비스 에이전트 역할이 없는 프로젝트의 클러스터에서 GKE용 워크로드 아이덴티티 제휴를 사용 설정하려고 하면 다음과 유사한 오류 메시지가 표시되면서 작업이 실패합니다.

Error waiting for updating GKE cluster workload identity config: DeployPatch failed

이 문제를 해결하려면 다음을 단계를 시도해 보세요.

  1. 프로젝트에 서비스 에이전트가 있고 올바르게 구성되었는지 확인합니다.

    gcloud projects get-iam-policy PROJECT_ID \
        --flatten=bindings \
        --filter=bindings.role=roles/container.serviceAgent \
        --format="value[delimiter='\\n'](bindings.members)"
    

    PROJECT_ID를 Google Cloud프로젝트 ID로 바꿉니다.

    서비스 에이전트가 올바르게 구성되었으면 출력에 서비스 에이전트의 전체 ID가 표시됩니다.

    serviceAccount:service-PROJECT_NUMBER@container-engine-robot.iam.gserviceaccount.com
    

    출력에 서비스 에이전트가 표시되지 않으면 Kubernetes Engine 서비스 에이전트 역할을 부여해야 합니다. 이 역할을 부여하려면 다음 단계를 완료하세요.

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

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

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

    123456789012
    
  3. 서비스 에이전트에 역할을 부여합니다.

    gcloud projects add-iam-policy-binding PROJECT_ID \
        --member=serviceAccount:service-PROJECT_NUMBER@container-engine-robot.iam.gserviceaccount.com \
        --role=roles/container.serviceAgent \
        --condition=None
    

    여기에서 PROJECT_NUMBER를 Google Cloud프로젝트 번호로 바꿉니다.

  4. GKE용 워크로드 아이덴티티 제휴를 다시 사용 설정합니다.

다음 단계

  • 문서에서 문제 해결 방법을 찾을 수 없으면 지원 받기를 참조하여 다음 주제에 대한 조언을 포함한 추가 도움을 요청하세요.