쿠버네티스 접근 문제 해결
Teleport v18.9이 페이지에서는 쿠버네티스에서 발생하는 일반적인 문제와 이를 우회하거나 해결하는 방법을 설명합니다. 에이전트가 재시작 후 Teleport 클러스터에 다시 조인하지 못하고 다음과 유사한 오류를 보고합니다: Teleport는 각 컴포넌트의 인증서에 서명하기 위해 인증 기관(CA)을 사용합니다.
이 페이지에서는 쿠버네티스에서 발생하는 일반적인 문제와 이를 우회하거나 해결하는 방법을 설명합니다.
에이전트가 "no authorities for hostname" 오류로 클러스터에 조인하지 못하는 경우#
증상#
에이전트가 재시작 후 Teleport 클러스터에 다시 조인하지 못하고 다음과 유사한 오류를 보고합니다:
ssh: handshake failed: ssh: no authorities for hostname
설명#
Teleport는 각 컴포넌트의 인증서에 서명하기 위해 인증 기관(CA)을 사용합니다. 컴포넌트가 클러스터에 처음 조인할 때, 클러스터의 CA가 서명한 인증서를 발급받아 상태 디렉터리에 저장합니다. 컴포넌트가 재시작되면 상태 디렉터리에 저장된 인증서를 사용해 클러스터에 다시 조인합니다.
이 오류는 컴포넌트가 Teleport 클러스터에 다시 조인하려 할 때, 클러스터의 CA가 변경되어 컴포넌트의 인증서가 더 이상 유효하지 않을 때 발생합니다.
이는 클러스터의 CA가 순환(rotate)되거나 클러스터가 재생성 또는 이름이 변경될 때 발생할 수 있습니다.
해결 방법#
에이전트가 새 인증서를 요청하고 클러스터에 다시 조인할 수 있도록 에이전트의 상태를 초기화해야 합니다.
에이전트의 상태를 삭제하는 절차는 에이전트가 쿠버네티스 내부에서 실행 중인지 외부에서 실행 중인지에 따라 다릅니다.
쿠버네티스 외부에서 실행 중인 에이전트 (단독 실행)#
에이전트가 쿠버네티스 외부에서 실행 중인 경우, 상태 디렉터리는 기본적으로
/var/lib/teleport/proc에 위치합니다. 다음 명령으로 상태 디렉터리를 삭제할 수
있습니다:
sudo rm -rf /var/lib/teleport/proc
그런 다음 에이전트를 재시작합니다:
sudo systemctl restart teleport
쿠버네티스 내에서 실행 중인 에이전트 (teleport-kube-agent)#
Teleport 11부터 teleport-kube-agent Pod의 상태는 설치 네임스페이스에 존재하는
쿠버네티스 시크릿(이름: {pod-name}-state)에 저장됩니다.
상태를 삭제하려면 다음 단계를 따르세요:
# teleport-kube-agent Pod의 시크릿 가져오기
$ 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 콘텐츠를 정리한 후 컨테이너를 재시작하세요.
상태가 삭제되면 각 에이전트 Pod를 재시작하세요.
GKE Autopilot 클러스터에 연결할 수 없는 경우#
GKE Warden authz [denied by user-impersonation-limitation]: impersonating system identities are not allowed
증상#
Teleport에서 GKE Autopilot 클러스터를 구성한 후, 쿠버네티스 객체를 가져오려는 모든 시도가 다음과 유사한 오류로 실패합니다:
또는 다음과 같은 오류가 발생합니다:
GKE Autopilot denies requests that impersonate "system:masters" group
이 문제는 GKE Autopilot 클러스터에만 영향을 미칩니다. 표준 GKE 클러스터를 사용 중이라면 이 문제는 해당되지 않습니다.
설명#
표준 쿠버네티스 클러스터와 달리, Autopilot 클러스터는 시스템 아이덴티티를 임퍼소네이션하는 요청을 금지합니다. 이는 사용자나 그룹을 임퍼소네이션할 수 있을 경우 클러스터의 컨트롤 플레인에 접근하여 관리 작업을 수행하는 것을 방지하는 보안 기능입니다. GKE Autopilot 보안에 대해 자세히 알아보기.
Teleport는 사용자를 대신하여 쿠버네티스 객체를 가져오기 위해 임퍼소네이션을
사용합니다. 이는 사용자의 아이덴티티를 Impersonate-User 헤더에, 사용자가 사용할 수
있는 모든 쿠버네티스 그룹을 Impersonate-Group 헤더에 담아 쿠버네티스 API 서버에
요청을 보내는 방식으로 수행됩니다.
system:masters는 모든 클러스터에 내장된 쿠버네티스 그룹이므로, 관리자가 이를
사용하여 클러스터의 컨트롤 플레인에 대한 관리 접근 권한을 얻는 것이 일반적입니다.
하지만 Autopilot 클러스터는 이 그룹을 임퍼소네이션하는 것을 금지하며, 대신 다른
그룹을 사용하도록 요구합니다.
해결 방법#
위 설명에 따라, 해결책은 Teleport에서 임퍼소네이션에 사용할 다른 그룹을 구성하는
것입니다. 이는 역할의 kubernetes_groups 매개변수를 Autopilot 클러스터가
임퍼소네이션을 허용하는 그룹으로 설정하여 수행할 수 있습니다.
teleport-kube-agent 차트는 대상 클러스터가 GKE 클러스터임을 감지하면
system:masters 그룹과 동일한 접근 수준을 가진 쿠버네티스 그룹을 구성합니다.
이 그룹의 기본 이름은 cluster-admin이지만, adminClusterRoleBinding.name
매개변수를 설정하여 이름을 변경할 수 있습니다.
쿠버네티스 그룹은 non-GKE 클러스터에 차트를 설치할 때 자동으로 생성되지 않으므로,
직접 그룹을 생성했거나 adminClusterRoleBinding.create 매개변수를 true로 설정하여
차트를 설치한 경우가 아니라면 kubernetes_groups 매개변수를 cluster-admin으로
변경하지 마세요.
그룹은 임퍼소네이션에 사용되기 전에 클러스터 내에 구성되어 있어야 한다는 점에
유의하는 것이 중요합니다. 그룹이 구성되지 않은 경우, 임퍼소네이션 요청은
403 Forbidden 오류로 실패하며 사용자는 클러스터에 접근할 수 없습니다.
non-Autopilot 클러스터에서 임퍼소네이션에 계속 system:masters 그룹을 사용하기로
선택한 경우, system:masters 접근 권한을 부여하는 Teleport 역할이 GKE Autopilot
클러스터에 접근하는 데 사용될 수 없도록 해야 합니다.
예를 들어, 다음 역할을 가진 사용자는 모든 쿠버네티스 클러스터에서 system:masters
그룹을 임퍼소네이션할 수 있습니다:
kind: role
version: v7
metadata:
name: k8s-admin
spec:
allow:
kubernetes_labels:
'*': '*'
kubernetes_groups: ["system:masters"]
kubernetes_labels의 와일드카드 *는 사용자가 Teleport 클러스터 내 모든
쿠버네티스 클러스터에 접근할 수 있도록 허용합니다. 이 역할로 사용자가 GKE Autopilot
클러스터에 접근하지 못하도록 하려면, 클러스터를 Autopilot 클러스터로 식별하는
라벨을 사용하여 teleport-kube-agent 차트를 설치할 수 있습니다. 예를 들면:
$ PROXY_ADDR=teleport.example.com:443
$ CLUSTER=cookie
# values.yaml 파일 생성
$ cat > values.yaml << EOF
authToken: "${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 (=teleport.version=)
Teleport 에이전트 Pod가 실행 중인지 확인하세요. 준비 완료된 컨테이너 하나를 가진 Teleport 에이전트 Pod 하나가 표시되어야 합니다:
$ kubectl -n teleport-agent get pods
NAME READY STATUS RESTARTS AGE
teleport-agent-0 1/1 Running 0 32s
이제 클러스터에 라벨이 지정되었으므로, k8s-admin 역할을 두 개의 역할로 나눌 수
있습니다. 하나는 모든 non-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>"
설명#
쿠버네티스 1.30부터 kubectl exec 명령은 쿠버네티스 API 서버와 통신할 때
SPDY 프로토콜 대신 WebSocket 프로토콜을 사용하도록 변경되었습니다. 이 변경은
SPDY 프로토콜이 지원 중단됨에 따라 kubectl exec 명령의 성능과 안정성을 향상시키기
위해 이루어졌습니다.
WebSocket은 SPDY의 드롭인 대체제로 의도되었지만, pods/exec 리소스에 대한 접근을
create verb만으로 제한하도록 RBAC가 구성된 쿠버네티스 클러스터에는 호환성이
깨지는 변경을 일으켰습니다. 이전에는 SPDY 프로토콜이 GET(쿠버네티스 RBAC에서
get에 매핑됨) 또는 POST(쿠버네티스 RBAC에서 create에 매핑됨) 중 하나를
사용하여 연결을 생성할 수 있도록 허용했습니다.
WebSocket 프로토콜에서는 kubectl exec 명령이 연결을 생성할 때 항상 GET 메서드를
사용합니다. 즉, RBAC 정책이 create verb만 허용하는 경우 연결이 거부됩니다.
해결 방법#
이 문제를 해결하려면 pods/exec (하위)리소스에 대해 get verb를 허용하도록 RBAC
정책을 업데이트하세요. 이는 사용자에게 접근 권한을 부여하는 ClusterRole 또는
Role을 수정하여 수행할 수 있습니다.
예를 들어, create verb로 pods/exec 리소스에 대한 접근을 부여하는 ClusterRole이
있다면, get verb도 허용하도록 업데이트하세요:
- apiGroups: [""]
resources: ["pods/exec"]
verbs: ["create", "get"]
ClusterRole이 업데이트되면, kubectl 버전 1.30 이상을 사용하여 Pod에 exec할 수
있습니다.
헬스 체크: 쿠버네티스 클러스터에 접근할 수 없음#
증상#
쿠버네티스 클러스터가 unhealthy로 보고되며, Teleport와 쿠버네티스 클러스터 API
간의 모든 호출이 실패합니다.
설명#
Teleport 쿠버네티스 서비스가 쿠버네티스 클러스터에 대해 여러 차례 헬스 체크를 수행했지만 응답을 받지 못했습니다.
쿠버네티스 클러스터 API 엔드포인트 /selfsubjectaccessreviews 및 /readyz에
대한 호출이 HTTP 상태 코드 없이 오류를 반환했습니다.
해결 방법#
쿠버네티스 클러스터와 네트워크의 근본 원인을 조사하세요.
쿠버네티스 클러스터의 상태를 확인하세요.
kubectl cluster-info
kubectl get --raw /readyz
네트워크 및 방화벽 규칙을 확인하세요.
- 네트워크가 올바르게 구성되어 있습니까?
- 보안 그룹을 확인하세요
- 네트워크 정책을 확인하세요
헬스 체크: 필요한 쿠버네티스 권한 누락#
증상#
쿠버네티스 클러스터가 unhealthy로 보고되며, impersonate users,
impersonate groups, impersonate service accounts, get pods와 같은 하나 이상의
쿠버네티스 권한이 누락되어 있습니다.
설명#
Teleport 쿠버네티스 서비스가 쿠버네티스 클러스터에 대해 헬스 체크를 수행했으며, 필요한 쿠버네티스 클러스터 기능이 거부되었다는 응답을 받았습니다.
쿠버네티스 클러스터에 ClusterRole이 누락되었거나, 부분적인 ClusterRole로
구성되어 있습니다. Teleport에는 4가지 쿠버네티스
SelfSubjectAccessReview
권한이 필요합니다:
- 사용자 임퍼소네이션
- 그룹 임퍼소네이션
- 서비스 계정 임퍼소네이션
- Pod 가져오기
해결 방법#
쿠버네티스 클러스터에 4가지 권한을 가진 ClusterRole과 ClusterRoleBinding을
추가하세요.
$ kubectl config use-context <your-kube-context>
kubectl apply -f - <<EOF
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: teleport-impersonation
rules:
- apiGroups:
- ""
resources:
- users
- groups
- serviceaccounts
verbs:
- impersonate
- apiGroups:
- ""
resources:
- pods
verbs:
- get
- apiGroups:
- "authorization.k8s.io"
resources:
- selfsubjectaccessreviews
verbs:
- create
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: teleport
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: teleport-impersonation
subjects:
- kind: ServiceAccount
name: teleport-serviceaccount
namespace: default
EOF
ClusterRoleBinding은 환경에 따라 다를 수 있습니다.
Teleport 쿠버네티스에서 임퍼소네이션 활성화하기도 참고하세요.
헬스 체크: 상태 코드와 함께 비정상 쿠버네티스 클러스터 감지됨#
증상#
쿠버네티스 클러스터가 unhealthy로 보고되며, Teleport가 쿠버네티스 클러스터로부터
오류 상태 코드가 포함된 응답을 받았습니다.
설명#
Teleport 쿠버네티스 서비스가 쿠버네티스 클러스터에 대해 여러 차례 헬스 체크를 수행했고 응답을 받았습니다.
권한 엔드포인트 /selfsubjectaccessreviews에 대한 호출은 실패했고, 쿠버네티스
클러스터의 /readyz 엔드포인트에 대한 호출은 오류 상태 코드가 포함된 응답을
반환했습니다. 이 오류 상태 코드는 쿠버네티스 클러스터 내 컴포넌트가 비정상 상태임을
나타냅니다.
해결 방법#
kubectl을 사용하여 쿠버네티스 클러스터 오류 상태 코드를 진단하세요.
kubectl cluster-info
kubectl get --raw /readyz
헬스 체크: 쿠버네티스 권한을 확인할 수 없음#
증상#
쿠버네티스 클러스터가 unhealthy로 보고되며, Teleport가 헬스 체크 엔드포인트로부터
혼재된 응답을 받았습니다.
설명#
Teleport 쿠버네티스 서비스가 쿠버네티스 클러스터에 대해 여러 차례 헬스 체크를 수행했고 응답을 받았습니다.
권한 엔드포인트 /selfsubjectaccessreviews에 대한 호출은 실패했고, 쿠버네티스
클러스터의 /readyz에 대한 호출은 성공했습니다. 쿠버네티스 클러스터 컴포넌트는
정상 작동 중이며, 쿠버네티스
SelfSubjectAccessReview
API에 대한 호출을 무언가가 차단하고 있습니다.
해결 방법#
kubectl을 사용하여 쿠버네티스 클러스터를 진단하세요.
kubectl cluster-info
kubectl get --raw /readyz