Infograb logo
쿠버네티스 접근 문제 해결

이 페이지에서는 쿠버네티스와 관련된 일반적인 문제와 이를 해결하는 방법을 설명합니다.

"hostname에 대한 권한이 없음"으로 인해 클러스터에 에이전트가 가입하지 못함

증상

에이전트가 재시작 후 Teleport 클러스터에 다시 가입하지 못하고 다음과 같은 오류를 보고합니다:

ssh: handshake failed: ssh: no authorities for hostname

설명

Teleport는 각 구성 요소에 대해 인증서를 서명하기 위해 인증서 기관(CAs)을 사용합니다. 구성 요소가 처음으로 클러스터에 가입할 때 클러스터의 CA에 의해 서명된 인증서를 받아 상태 디렉터리에 저장합니다. 구성 요소가 재시작될 때 상태 디렉터리에 저장된 인증서를 사용하여 클러스터에 다시 가입합니다.

이 오류는 구성 요소가 Teleport 클러스터에 다시 가입하려고 할 때 발생하며, 클러스터의 CA가 변경되어 구성 요소의 인증서가 더 이상 유효하지 않은 경우에 발생합니다.

클러스터의 CA가 회전되거나 클러스터가 재생성되거나 이름이 변경될 때 발생할 수 있습니다.

해결 방법

에이전트의 상태를 재설정해야 하며, 이를 통해 새로운 인증서를 요청하고 클러스터에 다시 가입할 수 있습니다.

에이전트의 상태를 삭제하는 과정은 에이전트가 쿠버네티스 내부 또는 외부에서 실행되는지에 따라 다릅니다.

쿠버네티스 외부에서 실행되는 에이전트(독립 실행형)

에이전트가 쿠버네티스 외부에서 실행되고 있는 경우, 기본적으로 상태 디렉터리는 /var/lib/teleport/proc에 위치합니다. 다음 명령어로 상태 디렉터리를 삭제할 수 있습니다:

sudo rm -rf /var/lib/teleport/proc

그런 다음 에이전트를 재시작합니다:

sudo systemctl restart teleport

쿠버네티스 내에서 실행되는 에이전트(teleport-kube-agent)

Teleport 11부터 teleport-kube-agent 포드의 상태는 설치 네임스페이스에 존재하는 Kubernetes Secret에 저장됩니다 - 이름: {pod-name}-state. 상태를 삭제하려면 다음 단계를 따르세요:

# teleport-kube-agent 포드에 대한 비밀 가져오기
$ kubectl get secret -o name -n teleport-agent | grep "state"
teleport-agent-0-state
teleport-agent-1-state

# 비밀 삭제
$ kubectl delete secret -n teleport-agent teleport-agent-0-state teleport-agent-1-state

컨테이너에 /var/lib/teleport를 마운트하고 있는 경우, 컨테이너 내에서 /var/lib/teleport/proc의 내용을 정리한 다음 컨테이너를 재시작해주세요.

상태가 삭제된 후 각 에이전트 포드를 재시작합니다.

GKE Autopilot 클러스터에 연결할 수 없음

GKE Warden authz [denied by user-impersonation-limitation]: impersonating system identities are not allowed

증상

Teleport에서 GKE Autopilot 클러스터를 구성한 후, 모든 Kubernetes 객체 검색 시도에서 다음과 같은 오류가 발생합니다:

또는 다음과 같은 오류가 발생할 수 있습니다:

GKE Autopilot denies requests that impersonate "system:masters" group

이 문제는 GKE Autopilot 클러스터에만 영향을 미칩니다. 표준 GKE 클러스터를 사용하고 있는 경우 이 문제는 해당되지 않습니다.

설명

표준 쿠버네티스 클러스터와는 달리, Autopilot 클러스터는 시스템 신원을 임시 사용할 수 있는 요청을 금지합니다. 이는 사용자가 클러스터의 제어 평면에 액세스하고 관리 작업을 수행하는 것을 방지하는 보안 기능입니다. 사용자를 대신하여 Kubernetes 객체를 검색하기 위해 Teleport는 임시 사용을 사용합니다. 이는 사용자의 신원을 Impersonate-User 헤더에 사용하고 그들이 사용할 수 있는 모든 Kubernetes 그룹을 Impersonate-Group 헤더에 포함하여 Kubernetes API 서버에 요청을 보내는 방식으로 이루어집니다.

system:masters는 모든 클러스터에서 기본으로 제공되는 Kubernetes 그룹으로, 관리자가 클러스터의 제어 평면에 대한 관리 액세스를 얻기 위해 일반적으로 사용합니다. 그러나 Autopilot 클러스터는 이 그룹을 임시하는 것을 금지하고 대신 다른 그룹을 사용해야 합니다.

해결 방법

위의 설명에 따라, 해결책은 Teleport에서 임시화에 대해 다른 그룹을 구성하는 것입니다. 이는 역할의 kubernetes_group 매개변수를 Autopilot 클러스터에서 임시 화할 수 있는 그룹으로 설정하여 수행할 수 있습니다.

teleport-kube-agent 차트는 대상 클러스터가 GKE 클러스터인지 감지할 때 system:masters 그룹과 동일한 액세스 수준을 가진 Kubernetes 그룹을 구성합니다. 이 그룹의 기본 이름은 cluster-admin이지만, adminClusterRoleBinding.name 매개변수를 설정하여 이름을 변경할 수 있습니다.

이 Kubernetes 그룹은 비-GKE 클러스터에 차트를 설치할 때 자동으로 생성되지 않으므로 사용자가 그룹을 수동으로 생성하지 않거나 adminClusterRoleBinding.create 매개변수를 true로 설정하여 차트를 설치하지 않는 한 kubernetes_groups 매개변수를 cluster-admin으로 변경하지 마십시오.

그룹을 임시화에 사용할 수 있기 전에 클러스터에 구성해야 하는 점도 중요합니다. 그룹이 구성되지 않은 경우, 임시화 요청은 403 Forbidden 오류와 함께 실패하며 사용자가 클러스터에 접근할 수 없습니다.

비-Autopilot 클러스터에서 임시화를 위해 system:masters 그룹을 계속 사용하기로 선택한 경우, system:masters 액세스를 부여하는 Teleport 역할이 GKE Autopilot 클러스터에 접근할 수 없도록 해야 합니다.

예를 들어, 다음 역할을 가진 사용자는 모든 Kubernetes 클러스터에서 system:masters 그룹을 임시할 수 있습니다:

kind: role
version: v7
metadata:
  name: k8s-admin
spec:
  allow:
    kubernetes_labels:
      '*': '*'
    kubernetes_groups: ["system:masters"]

kubernetes_labels에서의 와일드카드 *는 사용자가 Teleport 클러스터의 모든 Kubernetes 클러스터에 접근할 수 있게 합니다. 해당 역할을 가진 사용자가 GKE Autopilot 클러스터에 접근하지 못하도록 하려면, Autopilot 클러스터로 클러스터를 식별하는 레이블과 함께 teleport-kube-agent 차트를 설치할 수 있습니다. 예를 들어:

PROXY_ADDR=teleport.example.com:443
CLUSTER=cookie

values.yaml 파일 생성

cat > values.yaml << EOFauthToken: "${TOKEN}"proxyAddr: "${PROXY_ADDR}"roles: "kube,app,discovery"joinParams: method: "token" tokenName: "${TOKEN}"kubeClusterName: "${CLUSTER}"labels: "type" : "autopilot"EOF

values.yaml 설정으로 helm 차트 설치

helm install teleport-agent teleport/teleport-kube-agent \ -f values.yaml \ --create-namespace \ --namespace=teleport-agent \ --version 16.2.0

Teleport 에이전트 포드가 실행 중인지 확인하세요. 단일 준비된 컨테이너가 있는 Teleport 에이전트 포드가 하나 보일 것입니다:

kubectl -n teleport-agent get pods
NAME READY STATUS RESTARTS AGEteleport-agent-0 1/1 Running 0 32s

이제 클러스터에 레이블이 있으므로 k8s-admin 역할을 두 개의 역할로 분할할 수 있습니다: 하나는 모든 비-Autopilot 클러스터에 대한 접근을 허용하고, 다른 하나는 Autopilot 클러스터에 대한 접근만 허용합니다.

kind: role
version: v7
metadata:
  name: k8s-admin-non-gke-autopilot
spec:
  allow:
    kubernetes_labels_expression: 'labels["type"] != "autopilot"'
    kubernetes_groups: ["system:masters"]
---
kind: role
version: v7
metadata:
  name: k8s-admin-gke-autopilot
spec:
  allow:
    kubernetes_labels_expression: 'labels["type"] == "autopilot"'
    kubernetes_groups: ["cluster-admin"]

역할이 생성되면 사용자가 이 역할을 평소와 같이 할당할 수 있지만, 즉시 효과를 보기 위해서는 반드시 로그아웃 한 후 다시 로그인해야 합니다.

kubectl 1.30+에서 Pod로 exec할 수 없음

pods "<pod_name>" is forbidden: User "<user>" cannot get resource "pods/exec" in API group "" in the namespace "<namespace>"

증상

kubectl을 버전 1.30 이상으로 업그레이드한 후 Pod로 exec을 시도하면 다음과 같은 오류가 발생합니다:

pods "<pod_name>" is forbidden: User "<user>" cannot get resource "pods/exec" in API group "" in the namespace "<namespace>"

설명

Kubernetes 1.30부터 kubectl exec 명령은 Kubernetes API 서버와의 통신을 위해 SPDY 프로토콜에서 WebSocket 프로토콜로 전환되었습니다. 이 변경은 kubectl exec 명령의 성능과 신뢰성을 향상시키기 위해 이루어졌습니다. SPDY 프로토콜은 더 이상 지원되지 않습니다.

WebSocket이 SPDY의 대체 사용을 목적으로 설계되었음에도 불구하고, RBAC가 pods/exec 리소스에 대한 접근을 create 동사만으로 제한한 Kubernetes 클러스터에 대해 중단된 변경을 초래했습니다. 이전에 SPDY 프로토콜은 연결을 생성하기 위해 GET(Kubernetes RBAC에서는 get으로 매핑) 또는 POST(Kubernetes RBAC에서는 create로 매핑)를 사용할 수 있었습니다.

하지만 WebSocket 프로토콜에서는 kubectl exec 명령이 연결을 생성하기 위해 항상 GET 메서드를 사용합니다. 즉, RBAC 정책이 create 동사만 허용하는 경우, 연결이 거부됩니다.

해결 방법

이 문제를 해결하려면, RBAC 정책을 업데이트하여 pods/exec (하위) 리소스에 대한 get 동사를 허용해야 합니다. 이는 사용자에게 접근 권한을 부여하는 ClusterRole 또는 Role을 수정하여 수행할 수 있습니다.

예를 들어, pods/exec 리소스에 대한 접근을 create 동사로 부여하는 ClusterRole이 있는 경우, 이를 get 동사도 허용하도록 업데이트합니다:

- apiGroups: [""]
  resources: ["pods/exec"]
  verbs: ["create", "get"]

ClusterRole이 업데이트되면 kubectl 버전 1.30 이상에서 Pods에 exec할 수 있을 것입니다.

Teleport 원문 보기