클러스터 보안 문제 해결


이 페이지에서는 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 권한이 있는 역할을 부여합니다. 자세한 내용은 역할 기반 액세스 제어를 사용하여 클러스터의 작업 승인을 참조하세요.

워크로드 아이덴티티

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

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

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

    IAM Credentials API 사용 설정

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

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

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

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

    gcloud container node-pools describe NODEPOOL_NAME \
        --cluster=CLUSTER_NAME \
        --format="value(config.workloadMetadataConfig.mode)"
    
  4. Kubernetes 서비스 계정이 올바르게 주석 처리되었는지 확인합니다.

    kubectl describe serviceaccount \
        --namespace NAMESPACE KSA_NAME
    

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

    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
    

포드 시작 시 제한 시간 오류

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
    

제어 영역 사용 불가로 인해 워크로드 아이덴티티 실패

클러스터 제어 영역을 사용할 수 없으면 메타데이터 서버가 워크로드 아이덴티티를 반환할 수 없습니다. 메타데이터 서버를 호출하면 상태 코드 500이 반환됩니다.

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

dial tcp 35.232.136.58:443: connect: connection refused

이 경우 워크로드 아이덴티티를 사용할 수 없는 예상 상태로 이어집니다.

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

워크로드 아이덴티티 실패

어떠한 이유로든 GKE 메타데이터 서버가 차단되면 워크로드 아이덴티티가 실패합니다.

Istio를 사용하는 경우 워크로드 아이덴티티를 사용하는 모든 워크로드에 다음과 같은 애플리케이션 수준 주석을 추가해야 합니다.

"traffic.sidecar.istio.io/excludeOutboundIPRanges=169.254.169.254/32"

또는 global.proxy.excludeIPRanges Istio ConfigMap 키를 변경하여 동일한 작업을 수행할 수 있습니다.

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

gke-metadata-server 시스템 DaemonSet 포드는 노드에서 워크로드 아이덴티티를 용이하게 합니다. 포드는 클러스터의 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
    

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

DeployPatch가 실패하여 오류 메시지가 워크로드 아이덴티티에 사용 설정되지 않음

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

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

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 프로젝트 번호로 바꿉니다.

워크로드 아이덴티티를 다시 사용 설정하려고 시도합니다.